/******************************************************************************* * Copyright © 2012, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.eunit.internal.actions; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Properties; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.edt.compiler.internal.PartWrapper; import org.eclipse.edt.gen.eunit.CommonUtilities; import org.eclipse.edt.gen.eunit.EGL2Base; import org.eclipse.edt.gen.eunit.GenPartsXMLFile; import org.eclipse.edt.gen.eunit.IEUnitGenerationNotifier; import org.eclipse.edt.ide.core.IIDECompiler; import org.eclipse.edt.ide.core.internal.lookup.ProjectBuildPath; import org.eclipse.edt.ide.core.internal.lookup.ProjectBuildPathManager; import org.eclipse.edt.ide.core.model.EGLCore; import org.eclipse.edt.ide.core.model.EGLModelException; import org.eclipse.edt.ide.core.model.IEGLElement; import org.eclipse.edt.ide.core.model.IEGLFile; import org.eclipse.edt.ide.core.model.IEGLPathEntry; import org.eclipse.edt.ide.core.model.IEGLProject; import org.eclipse.edt.ide.core.model.IPackageFragment; import org.eclipse.edt.ide.core.model.IPackageFragmentRoot; import org.eclipse.edt.ide.core.model.IPart; import org.eclipse.edt.ide.core.model.PPListElement; import org.eclipse.edt.ide.core.utils.DefaultDeploymentDescriptorUtility; import org.eclipse.edt.ide.core.utils.ProjectSettingsUtility; import org.eclipse.edt.ide.eunit.Activator; import org.eclipse.edt.ide.ui.wizards.EGLProjectUtility; import org.eclipse.edt.ide.ui.wizards.EGLWizardUtilities; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.ui.IObjectActionDelegate; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchSite; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.osgi.framework.Bundle; import org.osgi.service.prefs.BackingStoreException; import com.ibm.icu.text.SimpleDateFormat; public abstract class GenTestDriverAction implements IObjectActionDelegate{ private static final String RUNUNIT_PROPERTIES = "rununit.properties"; protected static final String RESULTROOT_KEY = "EGLTestResultRoot"; protected static final String RESULTROOT_DIR_APPEND = "ResultRoot"; protected static final String GENERATORID_JAVA = "org.eclipse.edt.ide.gen.JavaGenProvider"; protected static final String GENERATORID_JAVACORE = "org.eclipse.edt.ide.gen.JavaCoreGenProvider"; protected static final String GENERATORID_JAVASCRIPT = "org.eclipse.edt.ide.gen.JavaScriptGenProvider"; protected static final String GENERATORID_JAVASCRIPT_DEV = "org.eclipse.edt.ide.gen.JavaScriptDevGenProvider"; /** * The root relative path of the EGL Resources plugin to retrieve the files to copy from */ protected static final String token = "eunit_runtime"; //$NON-NLS-1$ /** * The list of file names that need to be copied */ protected static final String[] EUNITRUNTIME_FILE = { "dataDef.egl", //$NON-NLS-1$ "TestExecutionLib.egl", //$NON-NLS-1$ "WriteResultLib.egl", //$NON-NLS-1$ "ExternalTypes.egl"}; //$NON-NLS-1$ protected static final String[] EUNITRUNTIME_FILE_MUSTJAVAGEN = {"TestResultService.egl", "ExternalTypes.egl"}; protected String[] EUNITRUNTIME_FILE_BYLANG={}; protected IStructuredSelection fSelection; protected IWorkbenchSite fSite; @Override public void run(IAction action) { ProgressMonitorDialog progressDialog = new ProgressMonitorDialog(fSite.getShell()); IResource selResource = (IResource)(fSelection.getFirstElement()); IProject baseProj = selResource.getProject(); String baseProjName = baseProj.getName(); IEGLProject baseEGLProj = EGLCore.create(baseProj); IWorkspaceRoot wsRoot = baseProj.getWorkspace().getRoot(); try{ List<WorkspaceModifyOperation> ops = getGenTestDriverOperatoins(wsRoot, baseProjName, baseProj, baseEGLProj); for(WorkspaceModifyOperation op : ops){ progressDialog.run(true, true, op); } } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } protected abstract List<WorkspaceModifyOperation> getGenTestDriverOperatoins(IWorkspaceRoot wsRoot, String baseProjName, IProject baseProj, IEGLProject baseEGLProj); protected WorkspaceModifyOperation getRefreshWSOperation(final IProject baseProj, final IProject driverProj){ WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { monitor.subTask("Refresh base project and generated driver project"); baseProj.refreshLocal(IResource.DEPTH_INFINITE, monitor); driverProj.refreshLocal(IResource.DEPTH_INFINITE, monitor); monitor.worked(2); } }; return op; } protected WorkspaceModifyOperation getCopyECKRuntimeFilesOperation(final IProject driverProject, final String languageToken){ WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { monitor.subTask("copying eunit runtime files..."); copyFilesToProject(driverProject, CommonUtilities.EUNITRUNTIME_PACKAGENAME, EUNITRUNTIME_FILE, token, monitor); copyFilesToProject(driverProject, CommonUtilities.EUNITRUNTIME_PACKAGENAME, EUNITRUNTIME_FILE_BYLANG, token+"/"+languageToken, monitor); monitor.worked(1); } }; return op; } protected WorkspaceModifyOperation getGenDriverOperation(final IWorkspaceRoot wsRoot, final IProject baseProject, final IEGLProject baseEGLProject, final IProject driverProject, final IEGLProject driverEGLProject) { WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { try{ IEUnitGenerationNotifier eckGenerationNotifier = new EUnitGenerationNotifier(monitor); IPath irRootPath = baseEGLProject.getOutputLocation(); //get required projects here so we can return to eclipse if exception during build. ProjectBuildPath projBP = ProjectBuildPathManager.getInstance().getProjectBuildPath(driverProject); IContainer[] eglSrcs = projBP.getSourceLocations(); IPath eglSourcePath = eglSrcs[0].getFullPath(); //String[] args = new String[4]; List<String> argList = new ArrayList<String>(); argList.add("-output"); argList.add(wsRoot.getFolder(eglSourcePath).getLocation().toOSString()); argList.add("-root"); argList.add(wsRoot.getFolder(irRootPath).getLocation().toOSString()); IIDECompiler compiler = ProjectSettingsUtility.getCompiler(baseProject); //if the selection is not project, then calculate all the EGL parts needs to be generated if(!isSelectionProject()){ String genPartsFileLocation = getGenPartsArgument(wsRoot, baseProject); if(genPartsFileLocation != null && genPartsFileLocation.length() > 0){ argList.add("-" + EGL2Base.ARG_PARM_GENPARTS); argList.add(genPartsFileLocation); } } String[] args = argList.toArray(new String[argList.size()]); invokeDriverGenerator(args, compiler, eckGenerationNotifier); } catch(Exception e){ e.printStackTrace(); } } }; return op; } protected boolean isSelectionProject(){ Object sel = fSelection.getFirstElement(); if(sel instanceof IProject){ return true; } return false; } protected String getGenPartsArgument(IWorkspaceRoot wsRoot, IProject baseProject){ String fileLocation = getGenFileFullLocation(wsRoot, baseProject); try { List<IEGLFile> eglFiles = getEGLFiles(fSelection); List<String> partNameEntries = new ArrayList<String>(); for(IEGLFile eglFile : eglFiles){ IPart[] parts = eglFile.getParts(); for(IPart part : parts) { partNameEntries.add(part.getFullyQualifiedName()); } } writePart2ConfigurationFile(fileLocation, partNameEntries); } catch (EGLModelException e) { // TODO Auto-generated catch block e.printStackTrace(); } return fileLocation; } /** * * @return */ protected String getGenFileFullLocation(IWorkspaceRoot wsRoot, IProject baseProject) { Date now = new Date(System.currentTimeMillis()); SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmssZ"); IPath path = baseProject.getFullPath(); path = path.append(EGL2Base.ARG_PARM_GENPARTS + String.valueOf(dateFormat.format(now))); path = path.addFileExtension("xml"); return wsRoot.getFolder(path).getLocation().toOSString(); } /** * * @param entry */ protected void writePart2ConfigurationFile(String fileName, List<String> entries) { GenPartsXMLFile driverXMLFile = new GenPartsXMLFile(fileName); try { driverXMLFile.saveGenerationEntries("", entries); } catch (IOException e) { e.printStackTrace(); } } private void getEGLElements(IEGLElement eglElem, List <IEGLFile> result) throws EGLModelException { if(eglElem != null) { switch(eglElem.getElementType()) { // case IEGLElement.EGL_PROJECT: // IPackageFragmentRoot[] pkgRoots = ((IEGLProject)eglElem).getPackageFragmentRoots(); // for(int i=0; i<pkgRoots.length; i++) // { // collectEGLFiles(pkgRoots[i], result); // } // break; case IEGLElement.PACKAGE_FRAGMENT_ROOT: collectEGLFiles((IPackageFragmentRoot)eglElem, result); break; case IEGLElement.PACKAGE_FRAGMENT: collectEGLFiles((IPackageFragment)eglElem, result); break; case IEGLElement.EGL_FILE: result.add((IEGLFile)eglElem); break; } } } private List <IEGLFile> getEGLFiles(IStructuredSelection selection) throws EGLModelException { List <IEGLFile> result = new ArrayList<IEGLFile>(); if(selection != null) { Iterator it = selection.iterator(); while(it.hasNext()) { Object element = it.next(); if(element instanceof IEGLElement) { IEGLElement eglElem = (IEGLElement)element; getEGLElements(eglElem, result); } // else if(element instanceof IProject) // { // IEGLProject eglproj = EGLCore.create((IProject)element); // getEGLElements(eglproj, result); // } else if(element instanceof IResource) { IEGLElement eglResourceElem = EGLCore.create((IResource)element); getEGLElements(eglResourceElem, result); } } } return result; } private void collectEGLFiles(IPackageFragment pkg, List <IEGLFile> result) throws EGLModelException { IEGLFile[] eglfiles = pkg.getEGLFiles(); for(int i=0; i<eglfiles.length; i++) { result.add(eglfiles[i]); } } private void collectEGLFiles(IPackageFragmentRoot pkgRoot, List <IEGLFile> result) throws EGLModelException { if(pkgRoot.getKind() == IPackageFragmentRoot.K_SOURCE) { IEGLElement[] children = pkgRoot.getChildren(); for(int i=0; i<children.length; i++) { collectEGLFiles((IPackageFragment)children[i], result); } } } protected abstract void invokeDriverGenerator(String[] args, IIDECompiler compiler, IEUnitGenerationNotifier eckGenerationNotifier); /** * add dependedProjName as a depended project for projname, * * @param eglProj - EGLProject for projname * @param projname * @param dependedProjName * * */ protected WorkspaceModifyOperation getSetEGLBuildPathOperation(final IEGLProject eglProj, final String projname, final String dependedProjName){ WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { monitor.subTask("Setting EGL build path depends on project " + dependedProjName); List <String> eglDepends = new ArrayList<String>(); eglDepends.add(dependedProjName); List<PPListElement>depends = EGLWizardUtilities.getProjectDependencies(projname, eglDepends); int nEntries = depends.size(); IEGLPathEntry[] classpath = new IEGLPathEntry[nEntries]; // create and set the class path int i=0; for(PPListElement entry: depends){ classpath[i] = entry.getEGLPathEntry(); i++; } eglProj.setRawEGLPath(classpath, monitor); monitor.worked(1); } }; return op; } protected WorkspaceModifyOperation getSetJavaBuildPathOperation(final IProject javaDriverProject, final IProject dependentProj){ WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { if (javaDriverProject.hasNature(JavaCore.NATURE_ID)) { monitor.subTask("Set java build path depends on project " + dependentProj.getName()); IJavaProject javaProject = JavaCore.create(javaDriverProject); IClasspathEntry[] classpath = javaProject.getRawClasspath(); boolean javaProjBuildPathAlreadySet = false; //check to see if the java build path already set for the same dependent project for(int p=0; p<classpath.length && !javaProjBuildPathAlreadySet; p++){ if(classpath[p].getEntryKind() == IClasspathEntry.CPE_PROJECT){ IPath dependentProjPath = classpath[p].getPath(); if(dependentProj.getFullPath().equals(dependentProjPath)) javaProjBuildPathAlreadySet = true; } } //if not set, set it if(!javaProjBuildPathAlreadySet){ List<IClasspathEntry> additions = new ArrayList<IClasspathEntry>(); IClasspathEntry newClsPathEntry = JavaCore.newProjectEntry(dependentProj.getFullPath()); additions.add(newClsPathEntry); if (additions.size() > 0) { IClasspathEntry[] newEntries = new IClasspathEntry[classpath.length + additions.size()]; System.arraycopy(classpath, 0, newEntries, 0, classpath.length); for (int i = 0; i < additions.size(); i++) { newEntries[classpath.length + i] = additions.get(i); } javaProject.setRawClasspath(newEntries, null); } } monitor.worked(1); } } }; return op; } protected WorkspaceModifyOperation getCreateEGLProjectOperation(final IWorkspaceRoot wsRoot, final String newProjName, final String baseProj){ WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { monitor.subTask("Creating driver project " + newProjName); IProject newProj = wsRoot.getProject(newProjName); if(!newProj.exists()) { EGLWizardUtilities.createProject(newProjName, 0); // Also set the Default DD of the new project to that of the original project. // Don't do this as a separate operation because we only want to do this when creating a new project. // The user should be allowed to modify this setting and then re-run EUnit generation without losing their change. IProject origProj = wsRoot.getProject(baseProj); if (origProj.exists()) { PartWrapper pw = DefaultDeploymentDescriptorUtility.getDefaultDeploymentDescriptor(origProj); if (pw != null && pw.getPartPath() != null && pw.getPartPath().length() > 0) { DefaultDeploymentDescriptorUtility.setDefaultDeploymentDescriptor(newProj, pw); } } } monitor.worked(1); } }; return op; } protected WorkspaceModifyOperation getSetGeneratorIDOperation(final IProject driverProject, final String[] generatorIDs) { WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { monitor.subTask("set generator id " + generatorIDs[0] +" for project " + driverProject.getName()); try { ProjectSettingsUtility.setGeneratorIds(driverProject, generatorIDs); } catch (BackingStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } monitor.worked(1); } }; return op; } protected WorkspaceModifyOperation getCreateRununitPropertyOperation(final IWorkspaceRoot wsRoot, final IProject driverProject){ WorkspaceModifyOperation op = new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { if (driverProject.hasNature(JavaCore.NATURE_ID)) { monitor.subTask("Creating rununit property " + RESULTROOT_KEY); IJavaProject javaProject = JavaCore.create(driverProject); IClasspathEntry[] classpath = javaProject.getRawClasspath(); IClasspathEntry sourceClsPath = null; for(int i=0; (i<classpath.length) && (sourceClsPath == null); i++){ if(classpath[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) sourceClsPath = classpath[i]; } if(sourceClsPath != null){ IPath propertyFilePath = sourceClsPath.getPath().append(RUNUNIT_PROPERTIES); IFile propertyFile = wsRoot.getFile(propertyFilePath); String propertyOSPath = propertyFile.getLocation().toOSString(); try { Properties props = new Properties(); if(propertyFile.exists()){ FileReader inReader = new FileReader(propertyOSPath); props.load(inReader); inReader.close(); } PrintWriter outWriter = new PrintWriter(propertyOSPath); String resultRootFolder = driverProject.getFolder(RESULTROOT_DIR_APPEND).getLocation().toOSString(); props.put(RESULTROOT_KEY, resultRootFolder); props.store(outWriter, ""); outWriter.flush(); outWriter.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } monitor.worked(1); } } }; return op; } /** * Convienence method for copy files from the EGL Resources plugin to an EGL project * * @param toProject The project to copy to * @param toPackage The package to copy to * @param files The array of file names to copy * @param resourceLocation The locacation relative to the plugin's root location, this plugin has the files you wan to copy * @throws InvocationTargetException * @throws InterruptedException * @throws CoreException * */ protected static void copyFilesToProject(IProject toProject, String toPackage, String[] files, String resourceLocation, IProgressMonitor monitor) throws CoreException, InterruptedException, InvocationTargetException { EGLWizardUtilities.createPackage(toPackage, toProject.getName()); Bundle sourcePlugin = Platform.getBundle(Activator.PLUGIN_ID); String[] sourceFileNames = files; IPath sourceRelative2PluginPath = new Path(resourceLocation); IEGLProject eproject = EGLCore.create(toProject); List <PPListElement> eglSrcs = EGLProjectUtility.getDefaultClassPath(eproject); IPath eglSourcePath = eglSrcs.get(0).getPath(); IPackageFragmentRoot root = eproject.findPackageFragmentRoot(eglSourcePath.makeAbsolute()); IPackageFragment frag = root.getPackageFragment(toPackage); IPath targetRelative2ProjectPath = frag.getResource().getProjectRelativePath(); copyFiles(sourcePlugin, sourceRelative2PluginPath, sourceFileNames, toProject, targetRelative2ProjectPath, monitor); } /** * This will copy the files specified in sourceFileNames, which are * under sourcePlugin/sourceRelative2PluginPath to targetProject/targetRelative2ProjPath * * Note: the copy will not occur if the target file already existed in the file system * * @param sourcePlugin - source Plug in * @param sourceRelative2PluginPath - the source path location relative to the source plug in * @param sourceFileNames - list of files in the source location needs to be copied * @param targetProj - target project * @param targetRelative2ProjPath - target files path location relative to the project * @throws CoreException * @throws Exception */ protected static void copyFiles(Bundle sourcePlugin, IPath sourceRelative2PluginPath, String[] sourceFileNames, IProject targetProj, IPath targetRelative2ProjPath, IProgressMonitor monitor) throws CoreException { for(int i=0; i<sourceFileNames.length; i++) { IFolder targetFolder = targetProj.getFolder(targetRelative2ProjPath); EGLWizardUtilities.createFolderRecursiveIfNeeded(targetFolder); IPath filepathRelative2Proj = targetRelative2ProjPath.append(sourceFileNames[i]); IFile targetFile = targetProj.getFile(filepathRelative2Proj); //check for existence if(!targetFile.exists()){ IPath sourceFile = sourceRelative2PluginPath.append(sourceFileNames[i]); InputStream sourceStream; try { sourceStream = FileLocator.openStream(sourcePlugin, sourceFile, false); targetFile.create(sourceStream, true, monitor); sourceStream.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //if it's one of the file that must be generated with java generator //eunit runtime java external type and services parts must be generated with java generator try { for (int x=0; x<EUNITRUNTIME_FILE_MUSTJAVAGEN.length; x++){ if(sourceFileNames[i].equals(EUNITRUNTIME_FILE_MUSTJAVAGEN[x])){ //set the java generator for these files ProjectSettingsUtility.setGeneratorIds(targetFile, new String[]{GENERATORID_JAVA}); } } } catch (BackingStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } @Override public void selectionChanged(IAction action, ISelection selection) { fSelection = (IStructuredSelection)selection; } @Override public void setActivePart(IAction action, IWorkbenchPart targetPart) { fSite = targetPart.getSite(); } }