/******************************************************************************* * Copyright (c) 2012 Bundlemaker project team. * 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: * Bundlemaker project team - initial API and implementation ******************************************************************************/ package org.bundlemaker.core.transformations.script.runner; import java.io.File; import java.lang.reflect.Method; import java.net.URL; import java.util.LinkedList; import java.util.List; import java.util.concurrent.Callable; import org.bundlemaker.core.analysis.AnalysisCore; import org.bundlemaker.core.analysis.AnalysisModelConfiguration; import org.bundlemaker.core.analysis.IAnalysisModelConfiguration; import org.bundlemaker.core.analysis.IRootArtifact; import org.bundlemaker.core.resource.IModularizedSystem; import org.bundlemaker.core.transformations.internal.Activator; import org.bundlemaker.core.transformations.script.ITransformationScript; import org.bundlemaker.core.transformations.script.ITransformationScriptLogger; import org.bundlemaker.core.transformations.script.TransformationModelConfiguration; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.launching.JavaRuntime; /** * @author Nils Hartmann (nils@nilshartmann.net) * */ public class TransformationScriptRunner { private final IType _transformationScriptType; private final IModularizedSystem _modularizedSystem; /** * @param shell * @param transformationScriptType */ public TransformationScriptRunner(IModularizedSystem modularizedSystem, IType transformationScriptType) { _transformationScriptType = transformationScriptType; _modularizedSystem = modularizedSystem; } // public void runScript() { // // try { // doRunScript(); // } catch (Exception ex) { // // // Show exception to user // StatusManager.getManager().handle( // new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to run script: " + ex, ex), StatusManager.SHOW); // } // } // /* // * (non-Javadoc) // * // * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor) // */ // @Override // public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { // // try { // doRunScript(monitor); // } catch (InterruptedException ex) { // throw ex; // } catch (Exception ex) { // throw new InvocationTargetException(ex); // } // // } // /* // * (non-Javadoc) // * // * @see org.eclipse.core.resources.WorkspaceJob#runInWorkspace(org.eclipse.core.runtime.IProgressMonitor) // */ // @Override // public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { // try { // doRunScript(); // } catch (Exception ex) { // return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to run script: " + ex, ex); // } // // return Status.OK_STATUS; // } public void runScript(IProgressMonitor progressMonitor) throws Exception { if (progressMonitor == null) { progressMonitor = new NullProgressMonitor(); } // Instantiate the script final ITransformationScript transformationScript = createTransformationScript(); // Get the required artifact model configuration IAnalysisModelConfiguration artifactModelConfiguration = getAnalysisModelConfiguration(transformationScript); // Get an artifact model according to the configuration specified in the script IRootArtifact rootArtifact = AnalysisCore.getAnalysisModel(_modularizedSystem, artifactModelConfiguration); // Create a Logger that logs to the BundleMaker console final ITransformationScriptLogger logger = getLogger(); final TransformationScriptContext context = new TransformationScriptContext(progressMonitor, logger, rootArtifact); final long scriptStart = System.currentTimeMillis(); // Run the script try { IRootArtifact.Factory.executeWithoutNotification(rootArtifact, new Callable<Void>() { @Override public Void call() throws Exception { transformationScript.transform(context); return null; } }); } catch (Exception ex) { handleScriptException(context, ex); } final long scriptDuration = System.currentTimeMillis() - scriptStart; logger.log("Executing Transformation Script took " + scriptDuration + "ms (" + (scriptDuration / 1000) + "s)"); } protected void handleScriptException(TransformationScriptContext context, final Exception ex) { context.getLogger().log("TRANSFORMATION SCRIPT FAILED: " + ex, ex); } /** * @return * @throws Exception */ private ITransformationScript createTransformationScript() throws Exception { // Create the classloader ClassLoader classLoader = createScriptClassLoader(); // Load the script's class Class<?> loadClass = classLoader.loadClass(_transformationScriptType.getFullyQualifiedName()); // Instantiate Object object = loadClass.newInstance(); ITransformationScript transformationScript = (ITransformationScript) object; return transformationScript; } private IAnalysisModelConfiguration getAnalysisModelConfiguration(ITransformationScript script) throws Exception { Method declaredTransformMethod = ITransformationScript.class.getDeclaredMethods()[0]; Method scriptMethod = script.getClass().getMethod(declaredTransformMethod.getName(), declaredTransformMethod.getParameterTypes()); TransformationModelConfiguration annotation = scriptMethod.getAnnotation(TransformationModelConfiguration.class); if (annotation == null) { return null; } AnalysisModelConfiguration artifactModelConfiguration = new AnalysisModelConfiguration( annotation.hierarchicalPackages(), annotation.contentType(), annotation.useVirtualModuleForMissingTypes()); return artifactModelConfiguration; } private ClassLoader createScriptClassLoader() throws Exception { // Determine classpath. Note that classes from BundleMaker libraries // are always loaded first, regardless where the BM container is placed // in the project's classpath IProject project = _transformationScriptType.getResource().getProject(); IJavaProject javaProject = JavaCore.create(project); String[] classpath = JavaRuntime.computeDefaultRuntimeClassPath(javaProject); List<URL> urls = new LinkedList<URL>(); for (String classpathEntry : classpath) { File file = new File(classpathEntry); if (file.exists()) { URL url = file.toURI().toURL(); urls.add(url); } } TransformationScriptClassLoader classLoader = TransformationScriptClassLoader.createBundleClassLoaderFor(Activator .getDefault().getBundleContext().getBundle(), urls.toArray(new URL[0])); return classLoader; } protected ITransformationScriptLogger getLogger() { return Activator.getDefault().getTransformationScriptLogger(); } }