/* * Copyright 2004-5 Enigmatec Corporation Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * Change History: * Feb 17, 2005 : Initial version created by gary */ package org.savara.tools.scenario.designer.simulate; import java.io.File; import java.io.IOException; import java.text.MessageFormat; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.IStreamListener; import org.eclipse.debug.core.model.IStreamMonitor; import org.eclipse.debug.core.model.IProcess; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate; import org.eclipse.jdt.launching.ExecutionArguments; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.IVMRunner; import org.eclipse.jdt.launching.VMRunnerConfiguration; import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.savara.scenario.simulation.ScenarioSimulatorMain; import org.savara.tools.common.eclipse.BundleRegistry; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.Path; /** * This class is responsible for launching a scenario test against * a test scenario. */ public class ScenarioSimulationLauncher extends AbstractJavaLaunchConfigurationDelegate { private static Logger logger = Logger.getLogger(ScenarioSimulationLauncher.class.getName()); /** * This is the default constructor. * */ public ScenarioSimulationLauncher() { } /** * This method launches the scenario test. * * @param configuration The launch configuration * @param mode The mode (run or debug) * @param launch The launch object * @param monitor The optional progress monitor */ public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException { if (monitor == null) { monitor = new NullProgressMonitor(); } monitor.beginTask(MessageFormat.format("{0}...", new String[]{configuration.getName()}), 3); //$NON-NLS-1$ // check for cancellation if (monitor.isCanceled()) { return; } monitor.subTask("Verifying launch configuration...."); String mainTypeName = ScenarioSimulatorMain.class.getName(); IVMInstall vm = verifyVMInstall(configuration); IVMRunner runner = vm.getVMRunner(mode); if (runner == null) { abort("VM runner does not exist", null, IJavaLaunchConfigurationConstants.ERR_VM_RUNNER_DOES_NOT_EXIST); //$NON-NLS-1$ } File workingDir = verifyWorkingDirectory(configuration); String workingDirName = null; if (workingDir != null) { workingDirName = workingDir.getAbsolutePath(); } // Environment variables String[] envp= DebugPlugin.getDefault().getLaunchManager().getEnvironment(configuration); // Program & VM args //String filename=configuration.getAttribute( // ScenarioSimulationLaunchConfigurationConstants.ATTR_PROJECT_NAME, "")+ // "/"+configuration.getAttribute( // ScenarioSimulationLaunchConfigurationConstants.ATTR_SCENARIO, ""); String simulationFile=configuration.getAttribute( ScenarioSimulationLaunchConfigurationConstants.ATTR_SIMULATION_FILE, ""); String pgmArgs="\""+simulationFile+"\""; logger.fine("Launching scenario test with args: "+pgmArgs); String vmArgs = getVMArguments(configuration); ExecutionArguments execArgs = new ExecutionArguments(vmArgs, pgmArgs); // VM-specific attributes Map vmAttributesMap = getVMSpecificAttributesMap(configuration); // Classpath String[] classpath = getClasspath(configuration); // Create VM config VMRunnerConfiguration runConfig = new VMRunnerConfiguration(mainTypeName, classpath); runConfig.setProgramArguments(execArgs.getProgramArgumentsArray()); runConfig.setEnvironment(envp); runConfig.setVMArguments(execArgs.getVMArgumentsArray()); runConfig.setWorkingDirectory(workingDirName); runConfig.setVMSpecificAttributesMap(vmAttributesMap); // Bootpath runConfig.setBootClassPath(getBootpath(configuration)); // check for cancellation if (monitor.isCanceled()) { return; } // stop in main prepareStopInMain(configuration); // done the verification phase monitor.worked(1); // Launch the configuration - 1 unit of work runner.run(runConfig, launch, monitor); IProcess[] processes=launch.getProcesses(); if (processes.length > 0) { processes[0].getStreamsProxy().getOutputStreamMonitor(). addListener(new IStreamListener() { public void streamAppended(String str, IStreamMonitor mon) { handleResults(str, false); } }); processes[0].getStreamsProxy().getErrorStreamMonitor(). addListener(new IStreamListener() { public void streamAppended(String str, IStreamMonitor mon) { handleResults(str, true); } }); } // check for cancellation if (monitor.isCanceled()) { return; } monitor.done(); } /** * This method handles the results produced by the launched * test. * * @param results The results * @param errorStream Whether the results are from the error * stream */ protected void handleResults(String results, boolean errorStream) { System.out.println(results); } /** * This method returns the full path to the scenario. * * @param relativePath The is the scenario path begining at * the project * @return The full path */ protected String getPathForScenario(String relativePath) { String ret=null; IFile file=ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(relativePath)); if (file != null && file.exists()) { ret = file.getLocation().toString(); } return(ret); } /** * This method derives the classpath required to run the * ScenarioTester utility. * * @param configuration The launch configuation * @return The list of classpath entries */ public String[] getClasspath(ILaunchConfiguration configuration) { String[] ret=null; java.util.Vector<String> classpathEntries=new java.util.Vector<String>(); // Add classpath entry for current Java project String projnames=null; try { projnames = configuration.getAttribute( ScenarioSimulationLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); String[] projname=projnames.split(","); java.util.List<String> outputPaths=new java.util.Vector<String>(); for (int n=0; n < projname.length; n++) { try { if (logger.isLoggable(Level.FINE)) { logger.fine("Building classpath for project: "+projname[n]); } IProject project= ResourcesPlugin.getWorkspace().getRoot().getProject(projname[n]); IJavaProject jproject=JavaCore.create(project); // Add output location IPath outputLocation=jproject.getOutputLocation(); IFolder folder= ResourcesPlugin.getWorkspace().getRoot().getFolder(outputLocation); String path=folder.getLocation().toString(); outputPaths.add(path); // Add other libraries to the classpath IClasspathEntry[] curclspath=jproject.getRawClasspath(); for (int i=0; curclspath != null && i < curclspath.length; i++) { if (curclspath[i].getEntryKind() == IClasspathEntry.CPE_LIBRARY) { IFile file= ResourcesPlugin.getWorkspace(). getRoot().getFile(curclspath[i].getPath()); if (file.exists()) { // Library is within the workspace classpathEntries.add(file.getLocation().toString()); } else { // Assume library is external to workspace classpathEntries.add(curclspath[i].getPath().toString()); } } else if (curclspath[i].getEntryKind() == IClasspathEntry.CPE_CONTAINER) { // Container's not currently handled - but // problem need to retrieve from project and // iterate over container entries } } } catch(Exception e) { // TODO: report error } } if (outputPaths.size() == 1) { classpathEntries.add(outputPaths.get(0)); } else if (outputPaths.size() > 0) { // Need to merge output folders into one location java.io.File dir=new java.io.File(System.getProperty("java.io.tmpdir")+ java.io.File.separatorChar+"savara"+java.io.File.separatorChar+ "simulation"+System.currentTimeMillis()); dir.deleteOnExit(); dir.mkdirs(); classpathEntries.add(dir.getAbsolutePath()); for (String path : outputPaths) { copy(new java.io.File(path), dir); } } } catch(Exception ex) { ex.printStackTrace(); } java.util.List<Bundle> bundles=getBundles(); for (Bundle b : bundles) { buildClassPath(b, classpathEntries); } ret = new String[classpathEntries.size()]; classpathEntries.copyInto(ret); if (logger.isLoggable(Level.FINEST)) { logger.finest("Scenario Simulation Classpath:"); for (int i=0; i < ret.length; i++) { logger.finest(" ["+i+"] "+ret[i]); } } return(ret); } protected void copy(java.io.File src, java.io.File target) throws java.io.IOException { if (src.isDirectory()) { // Check if target folder needs to be created if (target.exists() == false) { if (target.mkdirs() == false) { throw new IOException("Could not create target direcotry: "+ target.getPath()); } } target.deleteOnExit(); java.io.File[] children=src.listFiles(); for (int i=0; i < children.length; i++) { copy(children[i], new File(target, children[i].getName())); } } else { java.io.FileInputStream fis=new java.io.FileInputStream(src); byte[] b=new byte[fis.available()]; fis.read(b); fis.close(); java.io.FileOutputStream fos=new java.io.FileOutputStream(target); fos.write(b); fos.close(); target.deleteOnExit(); } } protected java.util.List<Bundle> getBundles() { java.util.List<Bundle> ret=new java.util.Vector<Bundle>(); Bundle bundle=Platform.getBundle("org.savara.tools.scenario"); if (bundle != null) { getBundles(bundle, ret, false); } for (Bundle b : BundleRegistry.getBundles()) { getBundles(b, ret, false); } if (logger.isLoggable(Level.FINE)) { logger.fine("Number of bundles is: "+ret.size()); } return(ret); } protected boolean isBundleRelevant(Bundle bundle) { if (bundle.getSymbolicName().startsWith("org.savara") || bundle.getSymbolicName().startsWith("org.pi4soa")) { return (true); } return (false); } /** * This method determines whether non-savara dependencies should * be considered relevant. * * @param bundle The bundle * @return Whether transient non-savara dependencies should now be relevant */ protected boolean isTransientDependenciesRelevant(Bundle bundle) { if (bundle.getSymbolicName().startsWith("org.pi4soa")) { return (true); } return (false); } protected void getBundles(Bundle bundle, java.util.List<Bundle> list, boolean transDepends) { if (list.contains(bundle)) { return; } // If bundle is not relevant, and transient dependencies are // not to be included, then return if (!isBundleRelevant(bundle) && !transDepends) { return; } if (!transDepends && isTransientDependenciesRelevant(bundle)) { transDepends = true; } list.add(bundle); // Check for role simulators ServiceReference<?>[] refs=bundle.getServicesInUse(); if (refs != null) { for (ServiceReference<?> ref : refs) { if (logger.isLoggable(Level.FINER)) { logger.finer("Bundle: "+bundle+" Referenced="+ref.getBundle()); } getBundles(ref.getBundle(), list, transDepends); } } // Get required bundles String required=bundle.getHeaders().get(Constants.REQUIRE_BUNDLE); if (required != null) { String[] bundles=required.split(","); for (int i=0; i < bundles.length; i++) { String bundleId=bundles[i]; int index=0; if ((index=bundleId.indexOf(';')) != -1) { bundleId = bundleId.substring(0, index); } Bundle other=Platform.getBundle(bundleId); if (logger.isLoggable(Level.FINER)) { logger.finer("Bundle: "+bundle+" Required="+other); } if (other == null) { logger.finest("Failed to find bundle '"+bundleId+"'"); } else { getBundles(other, list, transDepends); } } } } protected void buildClassPath(Bundle bundle, java.util.List<String> entries) { java.net.URL installLocation= bundle.getEntry("/"); java.net.URL local= null; try { local= Platform.asLocalURL(installLocation); } catch (java.io.IOException e) { e.printStackTrace(); } String baseLocation = local.getFile(); try { String projectClassPath=getProjectClasspath(baseLocation); // TODO: If classpath has been set, but the items are not available, // then resort to the .classpath file. Issue - how to resolve variables? String requires = (String)bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH); ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, requires); for (int i=0; elements != null && i < elements.length; i++) { String path=baseLocation+elements[i].getValue(); // Check if path is for a Jar and that the // file exists - if not see if a classes // directory exists if (path.endsWith(".jar")) { if ((new File(path)).exists() == false) { String jarPath=null; // Check if .classpath file exists - may be running in test workbench // and need to access local maven repo if (projectClassPath != null) { jarPath = getJarPath(projectClassPath, elements[i].getValue()); } if (jarPath != null) { path = jarPath; } else { if ((new File(baseLocation+"classes")).exists()) { path = baseLocation+"classes"+File.separatorChar+elements[i].getValue(); } else if ((new File(baseLocation+"target"+File.separatorChar+"classes")).exists()) { path = baseLocation+"target"+File.separatorChar+"classes"+File.separatorChar+elements[i].getValue(); } else if ((new File(baseLocation+"bin")).exists()) { path = baseLocation+"bin"+File.separatorChar+elements[i].getValue(); } else { path = baseLocation; } } } } else if (elements[i].getValue().equals(".")) { if ((new File(baseLocation+"classes")).exists()) { path = baseLocation+"classes"; } else if ((new File(baseLocation+"target"+File.separatorChar+"classes")).exists()) { path = baseLocation+"target"+File.separatorChar+"classes"; } else if ((new File(baseLocation+"bin")).exists()) { path = baseLocation+"bin"; } else { path = baseLocation; } } if (entries.contains(path) == false) { if (logger.isLoggable(Level.FINE)) { logger.fine("Adding classpath entry '"+ path+"'"); } entries.add(path); if (elements[i].getValue().equals(".")) { if ((new File(baseLocation+"classes")).exists()) { path = baseLocation+"classes"; entries.add(path); } } } } if (elements == null) { if (logger.isLoggable(Level.FINE)) { logger.fine("Adding classpath entry '"+ baseLocation+"'"); } if ((new File(baseLocation+"classes")).exists()) { entries.add(baseLocation+"classes"); } else if ((new File(baseLocation+"target"+File.separatorChar+"classes")).exists()) { entries.add(baseLocation+"target"+File.separatorChar+"classes"); } else if ((new File(baseLocation+"bin")).exists()) { entries.add(baseLocation+"bin"); } else { entries.add(baseLocation); } } } catch(Exception e) { logger.severe("Failed to construct classpath: "+e); e.printStackTrace(); } } protected String getProjectClasspath(String baseLocation) { String ret=null; File cppath=new File(baseLocation+".classpath"); if (cppath.exists()) { try { java.io.FileInputStream fis=new java.io.FileInputStream(cppath); byte[] b=new byte[fis.available()]; fis.read(b); fis.close(); ret = new String(b); } catch(Exception e) { e.printStackTrace(); } } return(ret); } protected String getJarPath(String projectClassPath, String element) { String ret=null; // Extract the jar name (without preceding folders or the file suffix) int startindex=element.lastIndexOf('/'); int endindex=element.lastIndexOf('.'); String jarName=element.substring(startindex+1, endindex); String locator="/"+jarName+"/"; int index=projectClassPath.indexOf(locator); if (index != -1) { int startpos=index; for (; projectClassPath.charAt(startpos) != '"'; startpos--); int endpos=projectClassPath.indexOf('"', index); String newpath=projectClassPath.substring(startpos+1, endpos); ret=newpath.replaceAll("M2_REPO", System.getenv("HOME")+"/.m2/repository"); } return(ret); } }