/******************************************************************************* * 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.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.regex.Matcher; import org.deved.antlride.core.AntlrConstants; import org.deved.antlride.core.build.AntlrBuildUnit; import org.deved.antlride.core.build.AntlrDeployer; import org.deved.antlride.core.launch.AntlrLauncher; import org.deved.antlride.core.model.IGrammar; import org.deved.antlride.core.model.IGrammarAction; import org.deved.antlride.core.model.evaluation.AntlrResultListener; import org.deved.antlride.core.model.evaluation.IEvalElement; import org.deved.antlride.core.model.test.AntlrTestCase; import org.deved.antlride.debug.model.event.AntlrDebugEvent; import org.deved.antlride.debug.model.event.AntlrDebugEventFactory; import org.deved.antlride.debug.ui.AntlrDebugParser; 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.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.DebugPlugin; 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.launching.IRuntimeClasspathEntry; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.swt.widgets.Display; public class AntlrJavaLauncher extends AntlrAbstractJavaLauncher implements AntlrLauncher { private AntlrResultListener listener; private int run(IProgressMonitor monitor, AntlrBuildUnit unit, AntlrTestCase test, IJavaProject javaProject, IRuntimeClasspathEntry[] classpath, IPath src, IPath classes) throws CoreException, InterruptedException { ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager(); ILaunchConfigurationType type = manager .getLaunchConfigurationType(ID_JAVA_APPLICATION); ILaunchConfigurationWorkingCopy workingCopy = type.newInstance(null, new StringBuilder(test.getRule()).append(" ").append( test.getName()).toString()); workingCopy.setAttribute(ATTR_PROJECT_NAME, javaProject .getElementName()); workingCopy.setAttribute(ATTR_MAIN_TYPE_NAME, "org.deved.antlride.runtime.LaunchParser"); workingCopy.setAttribute(ATTR_DEFAULT_CLASSPATH, false); IPath runtimePath = AntlrDeployer.RUNTIME_LOCATION; IRuntimeClasspathEntry runtimeEntry = JavaRuntime .newArchiveRuntimeClasspathEntry(runtimePath); runtimeEntry.setClasspathProperty(IRuntimeClasspathEntry.USER_CLASSES); IRuntimeClasspathEntry classesEntry = JavaRuntime .newArchiveRuntimeClasspathEntry(classes); classesEntry.setClasspathProperty(IRuntimeClasspathEntry.USER_CLASSES); classesEntry.setSourceAttachmentRootPath(src); String[] cp = new String[classpath.length + 2]; cp[0] = runtimeEntry.getMemento(); cp[1] = classesEntry.getMemento(); for (int i = 0; i < classpath.length; i++) { cp[i + 2] = classpath[i].getMemento(); } workingCopy.setAttribute(ATTR_CLASSPATH, Arrays.asList(cp)); IGrammar grammar = unit.getGrammar(); String grammarName = grammar.getElementName(); String lexerPackage = getLexerJavaPackage(grammar); StringBuilder lexerClass = new StringBuilder(lexerPackage); String parserPackage = getParserJavaPackage(grammar); StringBuilder parserClass = new StringBuilder(parserPackage) .append(grammarName); if (grammar.isCombinedGrammar()) { lexerClass.append(grammarName).append("Lexer"); parserClass.append("Parser"); } else { // it can only be a parser grammar lexerClass.append(grammar.getOption("tokenVocab")); } int port = findFreePort(); StringBuilder programArgs = new StringBuilder(); programArgs.append("-port").append(" ").append(port).append(" "); programArgs.append("-testCase").append(" ").append( safeArg( test.getPath().toOSString())).append(" "); programArgs.append("-lexer").append(" ").append(lexerClass).append(" "); programArgs.append("-parser").append(" ").append(parserClass).append( " "); programArgs.append("-ruleName").append(" ").append(test.getRule()); // programArgs.append("").append(" ").append(); // programArgs.append("").append(" ").append(); // programArgs.append("").append(" ").append(); // programArgs.append("").append(" ").append(); // programArgs.append("").append(" ").append(); workingCopy .setAttribute(ATTR_PROGRAM_ARGUMENTS, programArgs.toString()); // create and run the launch configuration ILaunchConfiguration config = workingCopy.doSave(); config.launch(ILaunchManager.RUN_MODE, monitor); // delete the configuration config.delete(); return port; } public 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 { String[] classpath = new String[runtimeClassPath.length]; for (int i = 0; i < runtimeClassPath.length; i++) { classpath[i] = runtimeClassPath[i].getMemento(); } IGrammar grammar = unit.getGrammar(); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++ run // ++++++++++++++++++++++++++++++++++++++++++++++++++++ int port = run(monitor, unit, testCase, javaProject, runtimeClassPath, src, classes); // ++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++ start listener // ++++++++++++++++++++++++++++++++++++++++++++++++++++ startListener(grammar, port); } private void startListener(final IGrammar grammar, int port) throws UnknownHostException, IOException { try { // wait for debugger Thread.sleep(1000L); } catch (InterruptedException e1) { e1.printStackTrace(); } ; final Socket socket = new Socket("localhost", port); socket.setTcpNoDelay(true); final PrintWriter writer = createWriter(socket); final BufferedReader reader = createReader(socket); Job job = new Job("ANTLR Event Listener") { @Override protected IStatus run(IProgressMonitor monitor) { try { String line = reader.readLine(); Collection<AntlrDebugEvent> events = new LinkedHashSet<AntlrDebugEvent>(); while (!"terminate".equals(line)) { AntlrDebugEvent event = AntlrDebugEventFactory .createFromString(null, grammar, line); events.add(event); writer.println("ack"); writer.flush(); line = reader.readLine(); } final IEvalElement element = AntlrDebugParser.createGraphModel(grammar, events); Display.getDefault().asyncExec(new Runnable() { public void run() { listener.setResult(element); } }); reader.close(); writer.close(); socket.close(); events.clear(); } catch (IOException e) { e.printStackTrace(); } return Status.OK_STATUS; } }; job.schedule(); } private static PrintWriter createWriter(Socket socket) throws IOException { OutputStream os = socket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(os, "UTF8"); return new PrintWriter(new BufferedWriter(osw)); } private static BufferedReader createReader(Socket socket) throws IOException { return new BufferedReader(new InputStreamReader( socket.getInputStream(), "UTF8")); } private static int findFreePort() { ServerSocket socket = null; try { socket = new ServerSocket(0); return socket.getLocalPort(); } catch (IOException e) { } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { } } } return 49153; } private static String getParserJavaPackage(IGrammar grammar) { if (grammar.isCombinedGrammar() || grammar.isParserGrammar() || grammar.isTreeParserGrammar()) { return extractJavaPackage(grammar, "header"); } return ""; } private static String getLexerJavaPackage(IGrammar grammar) { if (grammar.isCombinedGrammar()) { return extractJavaPackage(grammar, "lexer::header"); } if (grammar.isParserGrammar() || grammar.isTreeParserGrammar()) { IGrammar tokenGrammar = grammar.getTokenVocab(); if (tokenGrammar != null) { return extractJavaPackage(tokenGrammar, "header"); } } if (grammar.isLexerGrammar()) { return extractJavaPackage(grammar, "header"); } return ""; } private static String extractJavaPackage(IGrammar grammar, String action) { IGrammarAction header = grammar.findAction(action); String packageName = ""; if (header != null) { String headerText = header.toString(); Matcher matcher = AntlrConstants.ANTLR_JAVA_PACKAGE_PATTERN .matcher(headerText); if (matcher.find()) { packageName = matcher.group(1) + "."; } } return packageName; } public void setResultListener(AntlrResultListener listener) { this.listener = listener; } }