/******************************************************************************* * Copyright (c) 2007, 2008 Edgar Espina. * 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 * *******************************************************************************/ package org.deved.antlride.jdt.launch; import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_CLASSPATH; import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH; import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME; import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS; import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME; import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.UnknownHostException; import java.util.Arrays; import org.deved.antlride.core.AntlrCore; import org.deved.antlride.core.build.AntlrBuildUnit; import org.deved.antlride.core.build.AntlrDeployer; import org.deved.antlride.core.build.AntlrDeployerRepository; import org.deved.antlride.core.launch.AntlrLauncher; import org.deved.antlride.core.model.IGrammar; import org.deved.antlride.core.model.test.AntlrTestCase; import org.deved.antlride.core.util.AntlrCoreHelper; import org.deved.antlride.integration.jdt.AntlrJDT; import org.deved.antlride.integration.jdt.AntlrJavaTargetService; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.launching.IRuntimeClasspathEntry; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.widgets.Display; import org.osgi.framework.Bundle; public abstract class AntlrAbstractJavaLauncher implements AntlrLauncher { public AntlrAbstractJavaLauncher() { } public final void launch(final boolean rebuild, final AntlrBuildUnit unit, final AntlrTestCase testCase) throws CoreException { try { final IJavaProject javaProject = JavaCore.create(unit.getFile() .getProject()); if (javaProject != null /* && javaProject.exists() */) { ProgressMonitorDialog dialog = new ProgressMonitorDialog(null); dialog.run(true, true, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { AntlrDeployer deployer = AntlrDeployerRepository .createDeployer(); deployer.deployRuntime(); IPath compilerPath = deployCompiler(); IGrammar grammar = unit.getGrammar(); IPath src = getFolder(grammar, "src", false); IPath classes = getFolder(grammar, "classes", rebuild); final IJavaProject javaProject = JavaCore .create(unit.getFile().getProject()); IRuntimeClasspathEntry[] runtimeClassPath; if (javaProject.exists()) { runtimeClassPath = AntlrJavaTargetService .computeDefaultRuntimeClassPath(javaProject); } else { runtimeClassPath = new IRuntimeClasspathEntry[0]; } runtimeClassPath = AntlrJavaTargetService .mergeClasspath(monitor, unit, runtimeClassPath); String[] classpath = AntlrJavaTargetService .getMementoClassPath(runtimeClassPath); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++ generate code // ++++++++++++++++++++++++++++++++++++++++++++++++++++ if (rebuild) { generateCode(monitor, unit, javaProject, classpath, src); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++ compile // ++++++++++++++++++++++++++++++++++++++++++++++++++++ compile(monitor, unit, javaProject, runtimeClassPath, compilerPath, src, classes); } doLaunch(monitor, javaProject, runtimeClassPath, rebuild, unit, testCase, compilerPath, src, classes); } catch (CoreException e) { showError(e.getStatus()); } catch (UnknownHostException e) { showError(createFailStatus(e)); } catch (IOException e) { showError(createFailStatus(e)); } } }); } } catch (Exception ex) { showError(createFailStatus(ex)); } } private static void showError(final IStatus status) { Display.getDefault().asyncExec(new Runnable() { public void run() { ErrorDialog.openError(null, "Launch problem", "Execution was cancelled", status); } }); } private static IStatus createFailStatus(Exception ex) { IStatus status = new Status(IStatus.ERROR, AntlrJDT.PLUGIN_ID, ex .getMessage(), ex); return status; } protected abstract void doLaunch(IProgressMonitor monitor, IJavaProject javaProject, IRuntimeClasspathEntry[] runtimeClassPath, boolean rebuild, AntlrBuildUnit unit, AntlrTestCase testCase, IPath compilerPath, IPath src, IPath classes) throws CoreException, InterruptedException, UnknownHostException, IOException; protected String safeArg(String arg) { String[] tokens = arg.split(" "); StringBuilder builder = new StringBuilder(); for (int i = 0; i < tokens.length - 1; i++) { builder.append(tokens[i]).append("\" \""); } builder.append(tokens[tokens.length - 1]); return builder.toString(); } protected void generateCode(IProgressMonitor monitor, AntlrBuildUnit unit, IJavaProject javaProject, String[] classpath, IPath src) throws CoreException, InterruptedException { ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager(); ILaunchConfigurationType type = manager .getLaunchConfigurationType(ID_JAVA_APPLICATION); ILaunchConfigurationWorkingCopy cgwc = type.newInstance(null, "Generating Code for " + unit.getGrammar().getElementName()); cgwc.setAttribute(ATTR_PROJECT_NAME, javaProject.getElementName()); cgwc.setAttribute(ATTR_MAIN_TYPE_NAME, "org.antlr.Tool"); cgwc.setAttribute(ATTR_DEFAULT_CLASSPATH, false); cgwc.setAttribute(ATTR_CLASSPATH, Arrays.asList(classpath)); // program arguments StringBuilder programArgs = new StringBuilder(); programArgs.append("-verbose "); programArgs.append("-debug "); programArgs.append("-o "); programArgs.append(safeArg(src.toOSString())); programArgs.append(" "); IGrammar grammar = unit.getGrammar(); if (grammar.isParserGrammar()) { String lexerGrammarName = grammar.getOption("tokenVocab"); IPath lexerFile = unit.getAbsoluteLibraryPath().append( lexerGrammarName).addFileExtension("g"); programArgs.append(safeArg(lexerFile.toOSString())).append(" "); } programArgs.append(safeArg(unit.getAbsolutePath().toOSString())); cgwc.setAttribute(ATTR_PROGRAM_ARGUMENTS, programArgs.toString()); // create and run the launch configuration ILaunchConfiguration config = cgwc.doSave(); ILaunch launch = config.launch(ILaunchManager.RUN_MODE, monitor); while (!launch.isTerminated()) { Thread.sleep(500L); } // delete the configuration config.delete(); int exitValue = launch.getProcesses()[0].getExitValue(); if (exitValue != 0) { throw new CoreException(new Status(IStatus.ERROR, AntlrJDT.PLUGIN_ID, "Code generation fails")); } } protected void compile(IProgressMonitor monitor, AntlrBuildUnit unit, IJavaProject javaProject, IRuntimeClasspathEntry[] classpath, IPath compilerPath, IPath src, IPath classes) throws CoreException, InterruptedException { ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager(); ILaunchConfigurationType type = manager .getLaunchConfigurationType(ID_JAVA_APPLICATION); ILaunchConfigurationWorkingCopy workingCopy = type.newInstance(null, "Compiling " + unit.getGrammar().getElementName()); workingCopy.setAttribute(ATTR_PROJECT_NAME, javaProject .getElementName()); workingCopy.setAttribute(ATTR_MAIN_TYPE_NAME, "org.eclipse.jdt.internal.compiler.batch.Main"); workingCopy.setAttribute(ATTR_DEFAULT_CLASSPATH, false); IRuntimeClasspathEntry compilerEntry = JavaRuntime .newArchiveRuntimeClasspathEntry(compilerPath); compilerEntry.setClasspathProperty(IRuntimeClasspathEntry.USER_CLASSES); workingCopy.setAttribute(ATTR_CLASSPATH, Arrays.asList(compilerEntry .getMemento())); StringBuilder compilerArgs = new StringBuilder(); compilerArgs.append("-showversion "); compilerArgs.append("-cp "); for (IRuntimeClasspathEntry rcp : classpath) { compilerArgs.append(safeArg(rcp.getLocation())); compilerArgs.append(File.pathSeparator); } compilerArgs.setLength(compilerArgs.length() - 1); String sourceLevel = "-" + javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true); compilerArgs.append(" -nowarn "); compilerArgs.append(sourceLevel); compilerArgs.append(" -d "); compilerArgs.append(safeArg(classes.toOSString())); compilerArgs.append(" "); compilerArgs.append(safeArg(src.toOSString())); workingCopy.setAttribute(ATTR_PROGRAM_ARGUMENTS, compilerArgs .toString()); // create and run the launch configuration ILaunchConfiguration config = workingCopy.doSave(); ILaunch launch = config.launch(ILaunchManager.RUN_MODE, monitor); while (!launch.isTerminated()) { Thread.sleep(500L); } // delete the configuration config.delete(); int exitValue = launch.getProcesses()[0].getExitValue(); if (exitValue != 0) { throw new CoreException(new Status(IStatus.ERROR, AntlrJDT.PLUGIN_ID, "Compilation fails")); } } private static IPath deployCompiler() { IPath root = AntlrJDT.getDefault().getStateLocation().append("jars"); IPath lib = Path.fromPortableString("lib"); String jarFileName = "org.eclipse.jdt.core_3.4.0.jar"; IPath compilerJar = root.append(jarFileName); try { File file = compilerJar.toFile(); File container = file.getParentFile(); if (!container.exists()) { container.mkdirs(); } if (!file.exists()) { Bundle bundle = AntlrJDT.getDefault().getBundle(); String bundleFile = lib.append(jarFileName).toPortableString(); AntlrCoreHelper.copyFileFromBundle(bundle, bundleFile, file); } } catch (IOException e) { AntlrCore.error(e); } return compilerJar; } private static IPath getFolder(IGrammar grammar, String name, boolean clean) { IPath path = getDeployHome(grammar).append(grammar.getElementName()) .append(name); File folder = path.toFile(); if (!folder.exists()) { folder.mkdirs(); } else if (clean) { clean(folder); } return path; } private static IPath getDeployHome(IGrammar grammar) { return AntlrCore.getDefault().getStateLocation().append("java").append( grammar.getFolder()); } private static void clean(File dir) { File[] files = dir.listFiles(); if (files != null && files.length > 0) { for (File file : files) { if (file.isDirectory()) { clean(file); } file.delete(); } } } }