Java tutorial
/******************************************************************************* * Copyright (c) 2000, 2005 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 lslplus; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.URL; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import lslplus.decorators.ErrorDecorator; import lslplus.editor.LslPartitionScanner; import lslplus.editor.lsl.LslCodeScanner; import lslplus.language_metadata.LslConstant; import lslplus.language_metadata.LslFunction; import lslplus.language_metadata.LslHandler; import lslplus.language_metadata.LslMetaData; import lslplus.language_metadata.LslParam; import lslplus.lsltest.TestManager; import lslplus.util.LslColorProvider; import lslplus.util.Util; import lslplus.util.Util.ArrayMapFunc; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; /** * The class representing the LSL Plus plugin. * @author rgreayer * */ public class LslPlusPlugin extends AbstractUIPlugin { public static final String LSLPLUS_NATIVE_PATH = "lslplus.native_path"; //$NON-NLS-1$ private static final Pattern LSLPLUS_CORE_VERSION_PAT = Pattern.compile("^0\\.6(\\..*)?$"); //$NON-NLS-1$ private static final String LSLPLUS_CORE_VERSION = "0.6.*"; //$NON-NLS-1$ private static final String LSL_EXECUTABLE = "LslPlus" + ((File.separatorChar == '\\') ? ".exe" : ""); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ private static final String LSL_COMMAND = "LslPlus"; //$NON-NLS-1$ private static class ValidationResult { public boolean ok; public String msg; } public static final boolean DEBUG = true; private static LslPlusPlugin instance; public final static String LSL_PARTITIONING = "__lsl_partitioning"; //$NON-NLS-1$ public static final String PLUGIN_ID = "lslplus"; //$NON-NLS-1$ public static Image createImage(String path) { ImageDescriptor descriptor = imageDescriptorFromPlugin(path); if (descriptor != null) return descriptor.createImage(); return null; } /** * Returns the default plug-in instance. * * @return the default plug-in instance */ public static LslPlusPlugin getDefault() { return instance; } public static ImageDescriptor imageDescriptorFromPlugin(String path) { return imageDescriptorFromPlugin(PLUGIN_ID, path); } public static void openResource(Shell shell, final IFile resource) { final IWorkbenchPage activePage = (PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) ? PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() : null; if (activePage != null) { final Display display = shell.getDisplay(); if (display != null) { display.asyncExec(new Runnable() { public void run() { try { IDE.openEditor(activePage, resource, true); } catch (PartInitException e) { Util.error(e, e.getLocalizedMessage()); } } }); } } } /** * Run executable with an input string. Return a process so that the output can be monitored * as it is produced. * @param command the path to the executable * @param input the input string * @param redir an indicator as to whether stderr should be redirected to stdout * @return the process to monitor */ public static Process runCommand(String command, String input, boolean redir) { try { Process process = launchCoreCommand(command, redir); if (process == null) return null; OutputStream out = process.getOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(out); writer.write(input); writer.close(); return process; } catch (IOException e) { Util.error(e, e.getMessage()); return null; } } /** * Find and launch a command in the Lsl Plus Core. * @param command the command for the core to execute. * @param redir an indicator as to whether stderr should be redirected to stdout * @return the process to monitor */ public static Process launchCoreCommand(String command, boolean redir) { String path = getDefault().getExecutablePath(); if (path == null) return null; return execute(command, redir, path); } private static Process executeWithRetry(String command, boolean redir, String exeName) { Process p = execute(command, redir, exeName); if (p != null) return p; if (File.separatorChar == '\\') return null; // only want to do this if normal execution failed... try { Util.chmod(new File(exeName)); } catch (IOException e) { Util.error(e, "can't change mode of native executable"); //$NON-NLS-1$ } return execute(command, redir, exeName); } private static Process execute(String command, boolean redir, String exeName) { try { ProcessBuilder builder = new ProcessBuilder(new String[] { exeName, command }); builder.redirectErrorStream(redir); Process process = builder.start(); return process; } catch (IOException e) { Util.error(e, e.getLocalizedMessage()); return null; } } private String executablePath; private boolean determineExecutable() { String path = getDefault().getPreferenceStore().getString(LSLPLUS_NATIVE_PATH); String preferredVersion = null; String embeddedVersion = null; String installedVersion = null; if (path != null && !"".equals(path.trim())) { //$NON-NLS-1$ preferredVersion = tryTask("Version", path); //$NON-NLS-1$ if (checkVersion(preferredVersion)) { setExecutablePath(path); return true; } } URL url = FileLocator.find(getDefault().getBundle(), preferredNativePath(), null); if (url != null) { try { path = FileLocator.toFileURL(url).getFile(); embeddedVersion = tryTask("Version", path); //$NON-NLS-1$ if (checkVersion(embeddedVersion)) { setExecutablePath(path); return true; } } catch (IOException e) { Util.error(e, "can't locate " + url); //$NON-NLS-1$ } } url = FileLocator.find(getDefault().getBundle(), alternateNativePath(), null); if (url != null) { try { path = FileLocator.toFileURL(url).getFile(); embeddedVersion = tryTask("Version", path); //$NON-NLS-1$ if (checkVersion(embeddedVersion)) { setExecutablePath(path); return true; } } catch (IOException e) { Util.error(e, "can't locate " + url); //$NON-NLS-1$ } } installedVersion = tryTask("Version", LSL_COMMAND); //$NON-NLS-1$ if (checkVersion(installedVersion)) { setExecutablePath(LSL_COMMAND); return true; } StringBuilder versions = new StringBuilder(); boolean versionFound = false; if (preferredVersion != null) { versions.append(preferredVersion).append(" (version of executable set in LSL Plus Preferences)\n"); //$NON-NLS-1$ TODO versionFound = true; } if (embeddedVersion != null) { versions.append(embeddedVersion).append(" (version installed as part of plugin)\n"); //$NON-NLS-1$ TODO versionFound = true; } if (installedVersion != null) { versions.append(installedVersion).append(" (version found on PATH)\n"); //$NON-NLS-1$ TODO versionFound = true; } final StringBuilder buf = new StringBuilder(); if (versionFound) { buf.append("The following versions of the LSL Plus native executable were found:\n"); //$NON-NLS-1$ TODO buf.append(versions); buf.append("\nNone of these version are compatible with this plugin, which requires\n"); //$NON-NLS-1$ TODO buf.append("version ").append(LSLPLUS_CORE_VERSION).append(".\n"); //$NON-NLS-1$//$NON-NLS-2$ TODO } else { buf.append("The LSL Plus native executable was not found!\n"); //$NON-NLS-1$ TODO } buf.append("The LSLPlus native executable is available from Hackage:\n"); //$NON-NLS-1$ TODO buf.append("http://hackage.haskell.org/cgi-bin/hackage-scripts/pacakge/LslPlus\n\n"); //$NON-NLS-1$ TODO buf.append("Please also see the Help documentation for LSL Plus, under 'Installation'"); //$NON-NLS-1$ TODO getWorkbench().getDisplay().asyncExec(new Runnable() { public void run() { MessageDialog dlg = new MessageDialog(getWorkbench().getActiveWorkbenchWindow().getShell(), "LSL Plus Native Executable Problem", //$NON-NLS-1$ TODO null, buf.toString(), MessageDialog.ERROR, new String[] { "Ok" }, //$NON-NLS-1$ TODO 0); dlg.open(); } }); return false; } private String tryTask(String command, String path) { try { Process process = executeWithRetry(command, true, path); if (process == null) return null; OutputStream out = process.getOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(out); writer.close(); return readString(process.getInputStream()); } catch (IOException e) { return null; } } private String getExecutablePath() { return executablePath; } private void setExecutablePath(String path) { Util.log("executablePath = " + path); //$NON-NLS-1$ this.executablePath = path; } private static IPath preferredNativePath() { return new Path("os") //$NON-NLS-1$ .append(System.getProperty("osgi.os", "os")) //$NON-NLS-1$ //$NON-NLS-2$ .append(System.getProperty("osgi.arch", "arch")) //$NON-NLS-1$ //$NON-NLS-2$ .append(LSL_EXECUTABLE).removeTrailingSeparator(); } private static IPath alternateNativePath() { if ("x86_64".equals(System.getProperty("osgi.arch", "arch"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return new Path("os") //$NON-NLS-1$ .append(System.getProperty("osgi.os", "os")) //$NON-NLS-1$ //$NON-NLS-2$ .append("x86") //$NON-NLS-1$ .append(LSL_EXECUTABLE).removeTrailingSeparator(); } else { return null; } } public static String defaultNativePath() { try { URL url = FileLocator.find(getDefault().getBundle(), new Path("os"), null); //$NON-NLS-1$ String os = System.getProperty("osgi.os", "os"); //$NON-NLS-1$//$NON-NLS-2$ String arch = System.getProperty("osgi.arch", "arch"); //$NON-NLS-1$//$NON-NLS-2$ File f = new File(FileLocator.toFileURL(url).getFile() + File.separatorChar + os + File.separatorChar + arch + File.separatorChar + LSL_EXECUTABLE); return f.getAbsolutePath(); } catch (IOException e) { Util.error(e, "can't compute default path"); //$NON-NLS-1$ return ""; //$NON-NLS-1$ } } public static String runTask(String command, String input) { Process p = runCommand(command, input, true); if (p == null) return null; return readString(p.getInputStream()); } private static String readString(InputStream in) { InputStreamReader reader = new InputStreamReader(in); StringBuilder buf = new StringBuilder(); char[] chars = new char[512]; int count = 0; try { while ((count = reader.read(chars)) >= 0) { buf.append(chars, 0, count); } return buf.toString(); } catch (IOException e) { Util.error(e, e.getLocalizedMessage()); return null; } finally { try { reader.close(); } catch (IOException e) { Util.error(e, e.getLocalizedMessage()); } } } static String validateExpression(String expression) { if (DEBUG) Util.log("expression: " + expression); //$NON-NLS-1$ String result = runTask("ExpressionHandler", expression); //$NON-NLS-1$ if (DEBUG) Util.log("result: " + result); //$NON-NLS-1$ if (result == null) { return "Can't evaluate expression (internal error)"; //$NON-NLS-1$ TODO } XStream xstream = new XStream(new DomDriver()); xstream.alias("result", ValidationResult.class); //$NON-NLS-1$ ValidationResult e = (ValidationResult) xstream.fromXML(result); if (e.ok) return null; return e.msg; } private LslCodeScanner fCodeScanner; private LslColorProvider fColorProvider; private ErrorDecorator fErrorDecorator; private LslPartitionScanner fPartitionScanner; private LslMetaData lslMetaData = null; private TestManager testManager = null; private SimManager simManager = null; private static String[] statefulFunctions = null; /** * Creates a new plug-in instance. */ public LslPlusPlugin() { instance = this; } private LslMetaData buildMetaData() { String result = runTask("MetaData", ""); //$NON-NLS-1$//$NON-NLS-2$ if (result == null) { Util.error(Messages.LslPlusPlugin_NO_META_DATA); return new LslMetaData(); } if (DEBUG) Util.log("Meta-Data: " + result); //$NON-NLS-1$ XStream xstream = new XStream(new DomDriver()); xstream.alias("lslmeta", LslMetaData.class); //$NON-NLS-1$ xstream.alias("handler", LslHandler.class); //$NON-NLS-1$ xstream.alias("param", LslParam.class); //$NON-NLS-1$ xstream.alias("function", LslFunction.class); //$NON-NLS-1$ xstream.alias("constant", LslConstant.class); //$NON-NLS-1$ LslMetaData md = null; try { md = (LslMetaData) xstream.fromXML(result); } catch (Exception e) { Util.error(e, Messages.LslPlusPlugin_COULD_NOT_DESERIALIZE_META_DATA); md = new LslMetaData(); } return md; } public void errorStatusChanged() { getWorkbench().getDisplay().asyncExec(new Runnable() { public void run() { if (fErrorDecorator != null) { fErrorDecorator.errorStatusChanged(); } } }); } /** * Returns the singleton LSL code scanner. * * @return the singleton LSL code scanner */ public LslCodeScanner getLslCodeScanner() { if (fCodeScanner == null) { String[] handlerNames = Util.arrayMap(new Util.ArrayMapFunc<String>() { public Class<String> elementType() { return String.class; } public String map(Object o) { return ((LslHandler) o).getName(); } }, getLslMetaData().getHandlers()); String[] predefFuncs = Util.arrayMap(new Util.ArrayMapFunc<String>() { public Class<String> elementType() { return String.class; } public String map(Object o) { return ((LslFunction) o).getName(); } }, getLslMetaData().getFunctions()); String[] predefConsts = Util.arrayMap(new Util.ArrayMapFunc<String>() { public Class<String> elementType() { return String.class; } public String map(Object o) { return ((LslConstant) o).getName(); } }, getLslMetaData().getConstants()); fCodeScanner = new LslCodeScanner(getLslColorProvider(), handlerNames, predefFuncs, predefConsts, this.getPreferenceStore()); } return fCodeScanner; } /** * Returns the singleton Java color provider. * * @return the singleton Java color provider */ public LslColorProvider getLslColorProvider() { if (fColorProvider == null) fColorProvider = new LslColorProvider(this.getPreferenceStore()); return fColorProvider; } public synchronized LslMetaData getLslMetaData() { if (lslMetaData == null) { lslMetaData = buildMetaData(); } return lslMetaData; } /** * Return a scanner for creating LSL Plus partitions. * * @return a scanner for creating Java partitions */ public LslPartitionScanner getLslPartitionScanner() { if (fPartitionScanner == null) fPartitionScanner = new LslPartitionScanner(); return fPartitionScanner; } public TestManager getTestManager() { return testManager; } public void setErrorDecorator(ErrorDecorator errorDecorator) { this.fErrorDecorator = errorDecorator; } public SimManager getSimManager() { return simManager; } public static synchronized String[] getStatefulFunctions() { if (LslPlusPlugin.statefulFunctions == null) { List<String> funcs = Util.filtMap(new ArrayMapFunc<String>() { public Class<String> elementType() { return String.class; } public String map(Object o) { LslFunction f = (LslFunction) o; return f.isStateless() ? null : f.getName(); } }, getLLFunctions()); LslPlusPlugin.statefulFunctions = funcs.toArray(new String[funcs.size()]); } return LslPlusPlugin.statefulFunctions; } public static LslFunction[] getLLFunctions() { return getDefault().getLslMetaData().getFunctions(); } public void start(BundleContext context) throws Exception { super.start(context); getPreferenceStore().setDefault(LSLPLUS_NATIVE_PATH, ""); //$NON-NLS-1$ //checkVersion(); if (determineExecutable()) { testManager = new TestManager(); simManager = new SimManager(); } } private boolean checkVersion(final String version) { if (version == null) return false; Matcher m = LSLPLUS_CORE_VERSION_PAT.matcher(version.trim()); boolean matches = m.matches(); return matches; } }