X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.team.ui%2Fsrc%2Forg%2Fsimantics%2Fteam%2Finternal%2FStagingLauncher.java;fp=bundles%2Forg.simantics.team.ui%2Fsrc%2Forg%2Fsimantics%2Fteam%2Finternal%2FStagingLauncher.java;h=4b541a4f0fc43c7ee279fef05e14f4277c793fd9;hp=7744d30498d37be879849ebdf0b8785aef78efb6;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 diff --git a/bundles/org.simantics.team.ui/src/org/simantics/team/internal/StagingLauncher.java b/bundles/org.simantics.team.ui/src/org/simantics/team/internal/StagingLauncher.java index 7744d3049..4b541a4f0 100644 --- a/bundles/org.simantics.team.ui/src/org/simantics/team/internal/StagingLauncher.java +++ b/bundles/org.simantics.team.ui/src/org/simantics/team/internal/StagingLauncher.java @@ -1,452 +1,452 @@ -package org.simantics.team.internal; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Properties; -import java.util.Set; - -import org.eclipse.core.runtime.Platform; -import org.eclipse.equinox.frameworkadmin.BundleInfo; -import org.eclipse.equinox.internal.frameworkadmin.equinox.EquinoxConstants; -import org.eclipse.equinox.internal.frameworkadmin.utils.Utils; -import org.eclipse.equinox.internal.provisional.frameworkadmin.ConfigData; -import org.eclipse.equinox.internal.provisional.frameworkadmin.FrameworkAdmin; -import org.eclipse.equinox.internal.provisional.frameworkadmin.FrameworkAdminRuntimeException; -import org.eclipse.equinox.internal.provisional.frameworkadmin.LauncherData; -import org.eclipse.equinox.internal.provisional.frameworkadmin.Manipulator; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.ServiceReference; -import org.simantics.application.db.SocketUtils; -import org.simantics.databoard.binding.error.BindingConstructionException; -import org.simantics.db.Resource; -import org.simantics.db.Session; -import org.simantics.db.exception.DatabaseException; -import org.simantics.utils.FileUtils; -import org.simantics.utils.strings.EString; - -@SuppressWarnings("restriction") -public final class StagingLauncher { - private static final boolean DEBUG = true; - private static final boolean DEBUG_EXEC = true; - private static final boolean REMOTE_DEBUG_DISABLED = true; - public static StagingResult launch( - final Config stagingConfig, - String serverAddress, - String targetResourceId) - throws InvalidSyntaxException, IllegalArgumentException, - FrameworkAdminRuntimeException, IOException, BindingConstructionException, DatabaseException { - Bundle dsBundle = Platform.getBundle("org.eclipse.equinox.ds"); - try { - dsBundle.start(/*Bundle.START_TRANSIENT*/); - if (DEBUG) - System.out.println("state="+dsBundle.getState()); - } catch (BundleException ex) { - throw new StagingException("Could not start org.eclipse.equinox.ds.", ex); - } - Bundle faBundle = FrameworkUtil.getBundle(FrameworkAdmin.class); - if (null == faBundle) - throw new StagingException("Bundle for FrameworkAdmin not available."); - BundleContext faContext = faBundle.getBundleContext(); - if (null == faContext) - throw new StagingException("Context for FrameworkAdmin not available."); - ServiceReference ref = faContext.getServiceReference(FrameworkAdmin.class); - if (ref == null) - throw new StagingException("Reference for FrameworkAdmin not available."); - FrameworkAdmin admin = (FrameworkAdmin)faContext.getService(ref); - if (null == admin) - throw new StagingException("FrameworkAdmin not available."); - try { - Manipulator rmanip = admin.getRunningManipulator(); - if (rmanip == null) - throw new StagingException("No FrameworkAdmin Manipulator available for the currently running environment."); - if (DEBUG) - System.out.println("FrameworkAdmin Manipulator of the running environment:\n" + rmanip); - Properties system = System.getProperties(); - ConfigData rcd = rmanip.getConfigData(); - LauncherData rld = rmanip.getLauncherData(); - Manipulator manip = admin.getManipulator(); - manip.setConfigData(rcd); - manip.setLauncherData(rld); - ConfigData cd = manip.getConfigData(); - LauncherData ld = manip.getLauncherData(); - Properties config = new Properties(); - StringBuilder osgiBundles = new StringBuilder(1024); - StringBuilder bundlesInfo = new StringBuilder(1024); - bundlesInfo.append("#version=1\n"); - for (BundleInfo bi : cd.getBundles()) { - boolean started = isMarkedAsStarted(bi); - bundlesInfo - .append(bi.getSymbolicName()) - .append(",") - .append(bi.getVersion()) - .append(",") - //.append(bi.getLocation().toString()) - .append(URLDecoder.decode(bi.getLocation().toString(), "UTF-8")) - .append(",") - .append(bi.getStartLevel()) - .append(",") - .append(started) - .append("\n"); - if (DEBUG) { - System.out.println("bundle: " + bi.getSymbolicName() + "\n\t" + bi.getLocation().toString() + "\n\t" + started); - if (started) - System.out.println("IS STARTED: bundle: " + bi.getSymbolicName() + "\n\t" + bi.getLocation().toString()); - if (!started && bi.isMarkedAsStarted()) - System.out.println("NOT STARTED, BUT WAS MARKED AS STARTED: bundle: " + bi.getSymbolicName() + "\n\t" + bi.getLocation().toString()); - } - if (isStartUpBundle(bi)) { - if (osgiBundles.length() > 0) { - osgiBundles.append(","); - } - osgiBundles - .append("reference:") - .append(URLDecoder.decode(bi.getLocation().toString(), "UTF-8")) - .append("@") - .append(bi.getStartLevel()) - .append(":start"); - } - } - //File cwd = new File(system.getProperty("user.dir")); - File javaHome = new File(system.getProperty("java.home")); - String installArea = system.getProperty("osgi.install.area"); - config.setProperty("eclipse.application", "org.simantics.workbench.application"); - config.setProperty("eclipse.product", "org.simantics.devs3.ui.product"); - //config.setProperty("eclipse.consoleLog", ""); - config.setProperty("org.eclipse.update.reconcile", "false"); - config.setProperty("osgi.bundles", osgiBundles.toString()); - config.setProperty("osgi.bundles.defaultStartLevel", "4"); - //config.setProperty("osgi.clean", "true"); - //config.setProperty("osgi.configuration.area", "@default"); - config.setProperty("osgi.configuration.cascaded", "false"); - //config.setProperty("osgi.console", ""); - //config.setProperty("osgi.debug", ""); - config.setProperty("osgi.framework", URLDecoder.decode(ld.getFwJar().toURI().toString(), "UTF-8")); - //config.setProperty("osgi.noShutdown", ""); - config.setProperty("osgi.install.area", installArea); - config.setProperty("osgi.instance.area", stagingConfig.workspaceRoot.getAbsolutePath()); -// cd.setProperty("osgi.instance.area", "@none"); - config.setProperty("osgi.user.area", "@none"); - // Eclipse 3.6, not sure what this is for but modern apps have it. - config.setProperty("equinox.use.ds", "true"); - // Ignore INFO level log messages - config.setProperty("eclipse.log.level", "WARNING"); - File configDir = new File(stagingConfig.workspaceRoot, "configuration"); - File simpleConfiguratorDir = new File(configDir, "org.eclipse.equinox.simpleconfigurator"); - simpleConfiguratorDir.mkdirs(); - File bundlesInfoFile = new File(simpleConfiguratorDir, "bundles.info"); - config.setProperty("org.eclipse.equinox.simpleconfigurator.configUrl", URLDecoder.decode(bundlesInfoFile.toURI().toString(), "UTF-8")); - File logFile = new File(stagingConfig.workspaceRoot, "db-client.log"); - writeProperties(config, new File(configDir, "config.ini"), "This configuration file was written by: " + StagingLauncher.class.getCanonicalName()); - writeFile(bundlesInfo.toString(), bundlesInfoFile); - - ld.setJvm(new File(new File(javaHome, "bin"), "java")); - ld.setFwConfigLocation(configDir); - ld.setFwPersistentDataLocation(configDir, false); - ld.setLauncher(null); - int maxHeap = 768; /*prefs.getInt(Activator.PLUGIN_ID, ImportPreferences.PREF_IMPORT_PROCESS_MAX_HEAP, - ImportPreferences.getDefaultImportProcessMaxHeap(), preferenceScopes); - // Just a safety if preferences have not been properly initialized for some reason. - if (maxHeap == 0) - maxHeap = ImportPreferences.getDefaultImportProcessMaxHeap();*/ - ld.addJvmArg("-Xmx" + maxHeap + "m"); - ld.addJvmArg("-Xms" + maxHeap + "m"); - // Enable assertions to have faster failure in db client routines with improper input. - ld.addJvmArg("-ea"); - // For supporting OSGi dev mode (launched from IDE) - if (Platform.inDevelopmentMode()) { - // TODO: %osgi.dev is not escaped, it can contain whitespace - // but this doesn't seem to matter ? - ld.addJvmArg("-Dosgi.dev=" + system.getProperty("osgi.dev")); - } - ld.addJvmArg("-Dosgi.arch=" + rcd.getProperty("osgi.arch")); - ld.addJvmArg("-Dosgi.os=" + rcd.getProperty("osgi.os")); - ld.addJvmArg("-Dosgi.ws=" + rcd.getProperty("osgi.ws")); - ld.addJvmArg("-Dosgi.nl=" + rcd.getProperty("osgi.nl")); - - // WORKAROUND for a problem in org.eclipse.ecf fragment org.eclipse.ecf.ssl. - // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=316500 - // Either one of these works, THESE: - //ld.addJvmArg("-Dosgi.java.profile.bootdelegation=override"); - //ld.addJvmArg("-Dorg.osgi.framework.bootdelegation=sun.*, com.sun.*, javax.*"); - // OR: - ld.addJvmArg("-Dosgi.compatibility.bootdelegation=true"); - - // Enable remote debugging when in osgi dev mode. - if (Platform.inDevelopmentMode()) - if (!REMOTE_DEBUG_DISABLED) { - ld.addJvmArg("-Xdebug"); - ld.addJvmArg("-Xnoagent"); - int port = SocketUtils.getFreeEphemeralPort(); - ld.addJvmArg("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=" + port); - } - - ld.addJvmArg("-D" + Constants.PROP_DUMP_PROPERTIES); - ld.addJvmArg("-D" + Constants.PROP_LOGFILE + "=" + logFile.toURI().toString()); - String titleArgument = System.getProperty(Constants.PROP_WINDOW_TITLE); - if (null != titleArgument && !titleArgument.equals("")) - titleArgument = stagingConfig.titlePrefix + " " + titleArgument; - else - titleArgument = stagingConfig.titlePrefix; - ld.addJvmArg("-D" + Constants.PROP_WINDOW_TITLE + "=" + titleArgument); - if (null != stagingConfig.teamFolder) - ld.addJvmArg("-D" + Constants.PROP_TEAM_FOLDER + "=" + stagingConfig.teamFolder.getAbsolutePath()); - ld.addJvmArg("-D" + Constants.PROP_WORKSPACE_ROOT + "=" + stagingConfig.workspaceRoot.toURI().toString()); - if (DEBUG) - System.out.println("JVM ARGS: " + Arrays.toString(ld.getJvmArgs())); - - // Using this means that - // * config.ini must not be written self - // * parent program bundles.info can be reused (this could be done in any case) - // * running platform configuration must not be copied completely, only selected parts of - //manip.save(false); - - // #5849 workaround -// XSupport xs = stagingConfig.session.getService(XSupport.class); -// xs.initClusterIdMap(stagingConfig.workspaceRoot.getAbsolutePath()); - if (null != stagingConfig.clusterMapFolder) { - String file = "clusterIdMap.dat"; - File f = new File(stagingConfig.clusterMapFolder, file); - File tFolder = new File(stagingConfig.workspaceRoot, ".metadata/.plugins/org.simantics.db.procore"); - tFolder.mkdirs(); - FileUtils.copyFile(f, new File(tFolder, file)); - String file2 = "nextId.dat"; - File f2 = new File(stagingConfig.clusterMapFolder, file2); - File tFolder2 = new File(stagingConfig.workspaceRoot, "db"); - FileUtils.copyFile(f2, new File(tFolder2, file2)); - } - if (DEBUG) - System.out.println("LAUNCHING\n" + manip); - Process process; - { - LauncherData launcherData = ld; - if (DEBUG) - System.out.println("Framework JAR: " + ld.getFwJar().toURI().toString()); - Utils.checkAbsoluteFile(launcherData.getFwJar(), "fwJar"); //$NON-NLS-1$ - File cwd = stagingConfig.workspaceRoot; - Utils.checkAbsoluteDir(cwd, "cwd"); //$NON-NLS-1$ - - List cmdList = new LinkedList(); - if (launcherData.getJvm() != null) - cmdList.add(launcherData.getJvm().getAbsolutePath()); - else - cmdList.add("java"); //$NON-NLS-1$ - - if (launcherData.getJvmArgs() != null) - for (int i = 0; i < launcherData.getJvmArgs().length; i++) - cmdList.add(launcherData.getJvmArgs()[i]); - - cmdList.add("-jar"); //$NON-NLS-1$ - cmdList.add("\"" + launcherData.getFwJar().getAbsolutePath() + "\""); - - //EquinoxManipulatorImpl.checkConsistencyOfFwConfigLocAndFwPersistentDataLoc(launcherData); - cmdList.add(EquinoxConstants.OPTION_CONFIGURATION); - cmdList.add("\"" + launcherData.getFwPersistentDataLocation().getAbsolutePath() + "\""); - - cmdList.add("-data"); - cmdList.add(stagingConfig.workspaceRoot.getAbsolutePath()); - - if (launcherData.isClean()) - cmdList.add(EquinoxConstants.OPTION_CLEAN); - - String[] cmdarray = cmdList.toArray(new String[cmdList.size()]); - - if (DEBUG_EXEC) - System.out.println("Launching import, CWD=" + cwd + "\n\t" + EString.implode(cmdarray, "\n\t")); - - process = Runtime.getRuntime().exec(cmdarray, null, cwd); - } - - long startTime = System.nanoTime(); - int exitValue = Integer.MIN_VALUE; - InputStream is = process.getInputStream(); - InputStream es = process.getErrorStream(); - while (true) { - try { - long endTime = System.nanoTime(); - //System.out.println("Checking for process exit value"); - exitValue = process.exitValue(); - System.out.println("finished in " + (endTime-startTime)*1e-6 + "ms"); - System.out.println("exit value: " + exitValue); - } catch (IllegalThreadStateException e) { - try { - int n = is.available(); - if (n > 0) { - byte[] bytes = new byte[n]; - int nr = is.read(bytes); - if (nr > 0) - System.out.println("DEBUG: STDOUT:" + org.simantics.team.Utils.bytesToStringASCII(bytes, 0, nr)); - } - n = es.available(); - if (n > 0) { - byte[] bytes = new byte[n]; - int nr = es.read(bytes); - if (nr > 0) - System.out.println("DEBUG: STDERR:" + org.simantics.team.Utils.bytesToStringASCII(bytes, 0, nr)); - } - Thread.sleep(100); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - continue; - } - String ins = FileUtils.getContents(is); - if (!ins.isEmpty()) - System.out.println("--- STDOUT ---\n" + ins); - String errs = FileUtils.getContents(es); - if (!errs.isEmpty()) - System.out.println("--- STDERR ---\n" + errs); - break; - } - - // #5849 workaround -// xs.mergeClusterIdMap(stagingConfig.workspaceRoot.getAbsolutePath()); - - return new StagingResult(exitValue, logFile, null); - } finally { - faContext.ungetService(ref); - } - } - - private static Set startUpBundles = new HashSet(); - static { - //startUpBundles.add("org.eclipse.equinox.ds"); - startUpBundles.add("org.eclipse.equinox.simpleconfigurator"); - } - - private static Set startedBundles = new HashSet(); - static { - startedBundles.add("org.eclipse.core.runtime"); - } - - private static boolean isStartUpBundle(BundleInfo bi) { - return startUpBundles.contains(bi.getSymbolicName()); - } - - private static boolean isMarkedAsStarted(BundleInfo bi) { - // Prevent unnecessary bundles from being - // activated by only marking as started the plug-ins that - // are vital to the environment, which always have lower - // start level than the default 4. - return bi.isMarkedAsStarted() && (bi.getStartLevel() < 4 || startedBundles.contains(bi.getSymbolicName())); - } - - private static void writeProperties(Properties properties, File target, String comment) throws IOException { - FileWriter writer = new FileWriter(target); - try { - properties.store(writer, comment); - } finally { - writer.close(); - } - } - - private static void writeFile(String string, File target) throws IOException { - FileWriter writer = new FileWriter(target); - try { - writer.write(string); - } finally { - writer.close(); - } - } - static public final class StagingResult { - - private final int exitValue; - - private final File logFile; - - private final String messageLog; - - public StagingResult(String message) { - this.exitValue = Integer.MIN_VALUE; - this.logFile = null; - this.messageLog = message; - } - public StagingResult(int exitValue, File logFile, String messageLog) { - this.exitValue = exitValue; - this.logFile = logFile; - this.messageLog = messageLog; - } - - public int getExitValue() { - return exitValue; - } - - public File getLogFile() { - return logFile; - } - - public String getMessageLog() { - return messageLog; - } - - } - public static final class Config { - public final Session session; - public final Resource targetLibrary; - public final File workspaceRoot; - public final File clusterMapFolder; - public final File teamFolder; - public final PrintStream out; - // Outputs - public Resource createdModel; - public Resource createdState; - public List messages = new ArrayList(); - public String titlePrefix = "Staging"; - - public Config(Session session, Resource library, File workspaceRoot, File clusterMapFolder) - throws DatabaseException { - this(session, library, workspaceRoot, clusterMapFolder, null); - } - - public Config( Session session, Resource library, File workspaceRoot, File clusterMapFolder, PrintStream out) - throws DatabaseException { - this.session = session; - this.targetLibrary = library; - this.workspaceRoot = workspaceRoot; - this.clusterMapFolder = clusterMapFolder; - this.teamFolder = org.simantics.team.Utils.getTeamFolder(); - this.out = out; - } - } - static final class Constants { - - /** - * Tells the launched application to dump all its system properties into the - * standard output / log. - */ - public static final String PROP_DUMP_PROPERTIES = "dump.properties"; - - /** - * Controls where the launched application log is written. Specified as an URI. - */ - public static final String PROP_LOGFILE = "staging.logfile"; - - /** - * Prefix for the window title. - */ - public static final String PROP_WINDOW_TITLE = "staging.window.title"; - - /** - * Tells the launched application where its team data comes from. - */ - public static final String PROP_TEAM_FOLDER = "staging.team.folder"; - - /** - * Workspace root directory of the workbench process that launched the - * import process. - */ - public static final String PROP_WORKSPACE_ROOT = "import.workspace.root"; - } -} +package org.simantics.team.internal; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.equinox.frameworkadmin.BundleInfo; +import org.eclipse.equinox.internal.frameworkadmin.equinox.EquinoxConstants; +import org.eclipse.equinox.internal.frameworkadmin.utils.Utils; +import org.eclipse.equinox.internal.provisional.frameworkadmin.ConfigData; +import org.eclipse.equinox.internal.provisional.frameworkadmin.FrameworkAdmin; +import org.eclipse.equinox.internal.provisional.frameworkadmin.FrameworkAdminRuntimeException; +import org.eclipse.equinox.internal.provisional.frameworkadmin.LauncherData; +import org.eclipse.equinox.internal.provisional.frameworkadmin.Manipulator; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.simantics.application.db.SocketUtils; +import org.simantics.databoard.binding.error.BindingConstructionException; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.exception.DatabaseException; +import org.simantics.utils.FileUtils; +import org.simantics.utils.strings.EString; + +@SuppressWarnings("restriction") +public final class StagingLauncher { + private static final boolean DEBUG = true; + private static final boolean DEBUG_EXEC = true; + private static final boolean REMOTE_DEBUG_DISABLED = true; + public static StagingResult launch( + final Config stagingConfig, + String serverAddress, + String targetResourceId) + throws InvalidSyntaxException, IllegalArgumentException, + FrameworkAdminRuntimeException, IOException, BindingConstructionException, DatabaseException { + Bundle dsBundle = Platform.getBundle("org.eclipse.equinox.ds"); + try { + dsBundle.start(/*Bundle.START_TRANSIENT*/); + if (DEBUG) + System.out.println("state="+dsBundle.getState()); + } catch (BundleException ex) { + throw new StagingException("Could not start org.eclipse.equinox.ds.", ex); + } + Bundle faBundle = FrameworkUtil.getBundle(FrameworkAdmin.class); + if (null == faBundle) + throw new StagingException("Bundle for FrameworkAdmin not available."); + BundleContext faContext = faBundle.getBundleContext(); + if (null == faContext) + throw new StagingException("Context for FrameworkAdmin not available."); + ServiceReference ref = faContext.getServiceReference(FrameworkAdmin.class); + if (ref == null) + throw new StagingException("Reference for FrameworkAdmin not available."); + FrameworkAdmin admin = (FrameworkAdmin)faContext.getService(ref); + if (null == admin) + throw new StagingException("FrameworkAdmin not available."); + try { + Manipulator rmanip = admin.getRunningManipulator(); + if (rmanip == null) + throw new StagingException("No FrameworkAdmin Manipulator available for the currently running environment."); + if (DEBUG) + System.out.println("FrameworkAdmin Manipulator of the running environment:\n" + rmanip); + Properties system = System.getProperties(); + ConfigData rcd = rmanip.getConfigData(); + LauncherData rld = rmanip.getLauncherData(); + Manipulator manip = admin.getManipulator(); + manip.setConfigData(rcd); + manip.setLauncherData(rld); + ConfigData cd = manip.getConfigData(); + LauncherData ld = manip.getLauncherData(); + Properties config = new Properties(); + StringBuilder osgiBundles = new StringBuilder(1024); + StringBuilder bundlesInfo = new StringBuilder(1024); + bundlesInfo.append("#version=1\n"); + for (BundleInfo bi : cd.getBundles()) { + boolean started = isMarkedAsStarted(bi); + bundlesInfo + .append(bi.getSymbolicName()) + .append(",") + .append(bi.getVersion()) + .append(",") + //.append(bi.getLocation().toString()) + .append(URLDecoder.decode(bi.getLocation().toString(), "UTF-8")) + .append(",") + .append(bi.getStartLevel()) + .append(",") + .append(started) + .append("\n"); + if (DEBUG) { + System.out.println("bundle: " + bi.getSymbolicName() + "\n\t" + bi.getLocation().toString() + "\n\t" + started); + if (started) + System.out.println("IS STARTED: bundle: " + bi.getSymbolicName() + "\n\t" + bi.getLocation().toString()); + if (!started && bi.isMarkedAsStarted()) + System.out.println("NOT STARTED, BUT WAS MARKED AS STARTED: bundle: " + bi.getSymbolicName() + "\n\t" + bi.getLocation().toString()); + } + if (isStartUpBundle(bi)) { + if (osgiBundles.length() > 0) { + osgiBundles.append(","); + } + osgiBundles + .append("reference:") + .append(URLDecoder.decode(bi.getLocation().toString(), "UTF-8")) + .append("@") + .append(bi.getStartLevel()) + .append(":start"); + } + } + //File cwd = new File(system.getProperty("user.dir")); + File javaHome = new File(system.getProperty("java.home")); + String installArea = system.getProperty("osgi.install.area"); + config.setProperty("eclipse.application", "org.simantics.workbench.application"); + config.setProperty("eclipse.product", "org.simantics.devs3.ui.product"); + //config.setProperty("eclipse.consoleLog", ""); + config.setProperty("org.eclipse.update.reconcile", "false"); + config.setProperty("osgi.bundles", osgiBundles.toString()); + config.setProperty("osgi.bundles.defaultStartLevel", "4"); + //config.setProperty("osgi.clean", "true"); + //config.setProperty("osgi.configuration.area", "@default"); + config.setProperty("osgi.configuration.cascaded", "false"); + //config.setProperty("osgi.console", ""); + //config.setProperty("osgi.debug", ""); + config.setProperty("osgi.framework", URLDecoder.decode(ld.getFwJar().toURI().toString(), "UTF-8")); + //config.setProperty("osgi.noShutdown", ""); + config.setProperty("osgi.install.area", installArea); + config.setProperty("osgi.instance.area", stagingConfig.workspaceRoot.getAbsolutePath()); +// cd.setProperty("osgi.instance.area", "@none"); + config.setProperty("osgi.user.area", "@none"); + // Eclipse 3.6, not sure what this is for but modern apps have it. + config.setProperty("equinox.use.ds", "true"); + // Ignore INFO level log messages + config.setProperty("eclipse.log.level", "WARNING"); + File configDir = new File(stagingConfig.workspaceRoot, "configuration"); + File simpleConfiguratorDir = new File(configDir, "org.eclipse.equinox.simpleconfigurator"); + simpleConfiguratorDir.mkdirs(); + File bundlesInfoFile = new File(simpleConfiguratorDir, "bundles.info"); + config.setProperty("org.eclipse.equinox.simpleconfigurator.configUrl", URLDecoder.decode(bundlesInfoFile.toURI().toString(), "UTF-8")); + File logFile = new File(stagingConfig.workspaceRoot, "db-client.log"); + writeProperties(config, new File(configDir, "config.ini"), "This configuration file was written by: " + StagingLauncher.class.getCanonicalName()); + writeFile(bundlesInfo.toString(), bundlesInfoFile); + + ld.setJvm(new File(new File(javaHome, "bin"), "java")); + ld.setFwConfigLocation(configDir); + ld.setFwPersistentDataLocation(configDir, false); + ld.setLauncher(null); + int maxHeap = 768; /*prefs.getInt(Activator.PLUGIN_ID, ImportPreferences.PREF_IMPORT_PROCESS_MAX_HEAP, + ImportPreferences.getDefaultImportProcessMaxHeap(), preferenceScopes); + // Just a safety if preferences have not been properly initialized for some reason. + if (maxHeap == 0) + maxHeap = ImportPreferences.getDefaultImportProcessMaxHeap();*/ + ld.addJvmArg("-Xmx" + maxHeap + "m"); + ld.addJvmArg("-Xms" + maxHeap + "m"); + // Enable assertions to have faster failure in db client routines with improper input. + ld.addJvmArg("-ea"); + // For supporting OSGi dev mode (launched from IDE) + if (Platform.inDevelopmentMode()) { + // TODO: %osgi.dev is not escaped, it can contain whitespace + // but this doesn't seem to matter ? + ld.addJvmArg("-Dosgi.dev=" + system.getProperty("osgi.dev")); + } + ld.addJvmArg("-Dosgi.arch=" + rcd.getProperty("osgi.arch")); + ld.addJvmArg("-Dosgi.os=" + rcd.getProperty("osgi.os")); + ld.addJvmArg("-Dosgi.ws=" + rcd.getProperty("osgi.ws")); + ld.addJvmArg("-Dosgi.nl=" + rcd.getProperty("osgi.nl")); + + // WORKAROUND for a problem in org.eclipse.ecf fragment org.eclipse.ecf.ssl. + // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=316500 + // Either one of these works, THESE: + //ld.addJvmArg("-Dosgi.java.profile.bootdelegation=override"); + //ld.addJvmArg("-Dorg.osgi.framework.bootdelegation=sun.*, com.sun.*, javax.*"); + // OR: + ld.addJvmArg("-Dosgi.compatibility.bootdelegation=true"); + + // Enable remote debugging when in osgi dev mode. + if (Platform.inDevelopmentMode()) + if (!REMOTE_DEBUG_DISABLED) { + ld.addJvmArg("-Xdebug"); + ld.addJvmArg("-Xnoagent"); + int port = SocketUtils.getFreeEphemeralPort(); + ld.addJvmArg("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=" + port); + } + + ld.addJvmArg("-D" + Constants.PROP_DUMP_PROPERTIES); + ld.addJvmArg("-D" + Constants.PROP_LOGFILE + "=" + logFile.toURI().toString()); + String titleArgument = System.getProperty(Constants.PROP_WINDOW_TITLE); + if (null != titleArgument && !titleArgument.equals("")) + titleArgument = stagingConfig.titlePrefix + " " + titleArgument; + else + titleArgument = stagingConfig.titlePrefix; + ld.addJvmArg("-D" + Constants.PROP_WINDOW_TITLE + "=" + titleArgument); + if (null != stagingConfig.teamFolder) + ld.addJvmArg("-D" + Constants.PROP_TEAM_FOLDER + "=" + stagingConfig.teamFolder.getAbsolutePath()); + ld.addJvmArg("-D" + Constants.PROP_WORKSPACE_ROOT + "=" + stagingConfig.workspaceRoot.toURI().toString()); + if (DEBUG) + System.out.println("JVM ARGS: " + Arrays.toString(ld.getJvmArgs())); + + // Using this means that + // * config.ini must not be written self + // * parent program bundles.info can be reused (this could be done in any case) + // * running platform configuration must not be copied completely, only selected parts of + //manip.save(false); + + // #5849 workaround +// XSupport xs = stagingConfig.session.getService(XSupport.class); +// xs.initClusterIdMap(stagingConfig.workspaceRoot.getAbsolutePath()); + if (null != stagingConfig.clusterMapFolder) { + String file = "clusterIdMap.dat"; + File f = new File(stagingConfig.clusterMapFolder, file); + File tFolder = new File(stagingConfig.workspaceRoot, ".metadata/.plugins/org.simantics.db.procore"); + tFolder.mkdirs(); + FileUtils.copyFile(f, new File(tFolder, file)); + String file2 = "nextId.dat"; + File f2 = new File(stagingConfig.clusterMapFolder, file2); + File tFolder2 = new File(stagingConfig.workspaceRoot, "db"); + FileUtils.copyFile(f2, new File(tFolder2, file2)); + } + if (DEBUG) + System.out.println("LAUNCHING\n" + manip); + Process process; + { + LauncherData launcherData = ld; + if (DEBUG) + System.out.println("Framework JAR: " + ld.getFwJar().toURI().toString()); + Utils.checkAbsoluteFile(launcherData.getFwJar(), "fwJar"); //$NON-NLS-1$ + File cwd = stagingConfig.workspaceRoot; + Utils.checkAbsoluteDir(cwd, "cwd"); //$NON-NLS-1$ + + List cmdList = new LinkedList(); + if (launcherData.getJvm() != null) + cmdList.add(launcherData.getJvm().getAbsolutePath()); + else + cmdList.add("java"); //$NON-NLS-1$ + + if (launcherData.getJvmArgs() != null) + for (int i = 0; i < launcherData.getJvmArgs().length; i++) + cmdList.add(launcherData.getJvmArgs()[i]); + + cmdList.add("-jar"); //$NON-NLS-1$ + cmdList.add("\"" + launcherData.getFwJar().getAbsolutePath() + "\""); + + //EquinoxManipulatorImpl.checkConsistencyOfFwConfigLocAndFwPersistentDataLoc(launcherData); + cmdList.add(EquinoxConstants.OPTION_CONFIGURATION); + cmdList.add("\"" + launcherData.getFwPersistentDataLocation().getAbsolutePath() + "\""); + + cmdList.add("-data"); + cmdList.add(stagingConfig.workspaceRoot.getAbsolutePath()); + + if (launcherData.isClean()) + cmdList.add(EquinoxConstants.OPTION_CLEAN); + + String[] cmdarray = cmdList.toArray(new String[cmdList.size()]); + + if (DEBUG_EXEC) + System.out.println("Launching import, CWD=" + cwd + "\n\t" + EString.implode(cmdarray, "\n\t")); + + process = Runtime.getRuntime().exec(cmdarray, null, cwd); + } + + long startTime = System.nanoTime(); + int exitValue = Integer.MIN_VALUE; + InputStream is = process.getInputStream(); + InputStream es = process.getErrorStream(); + while (true) { + try { + long endTime = System.nanoTime(); + //System.out.println("Checking for process exit value"); + exitValue = process.exitValue(); + System.out.println("finished in " + (endTime-startTime)*1e-6 + "ms"); + System.out.println("exit value: " + exitValue); + } catch (IllegalThreadStateException e) { + try { + int n = is.available(); + if (n > 0) { + byte[] bytes = new byte[n]; + int nr = is.read(bytes); + if (nr > 0) + System.out.println("DEBUG: STDOUT:" + org.simantics.team.Utils.bytesToStringASCII(bytes, 0, nr)); + } + n = es.available(); + if (n > 0) { + byte[] bytes = new byte[n]; + int nr = es.read(bytes); + if (nr > 0) + System.out.println("DEBUG: STDERR:" + org.simantics.team.Utils.bytesToStringASCII(bytes, 0, nr)); + } + Thread.sleep(100); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + continue; + } + String ins = FileUtils.getContents(is); + if (!ins.isEmpty()) + System.out.println("--- STDOUT ---\n" + ins); + String errs = FileUtils.getContents(es); + if (!errs.isEmpty()) + System.out.println("--- STDERR ---\n" + errs); + break; + } + + // #5849 workaround +// xs.mergeClusterIdMap(stagingConfig.workspaceRoot.getAbsolutePath()); + + return new StagingResult(exitValue, logFile, null); + } finally { + faContext.ungetService(ref); + } + } + + private static Set startUpBundles = new HashSet(); + static { + //startUpBundles.add("org.eclipse.equinox.ds"); + startUpBundles.add("org.eclipse.equinox.simpleconfigurator"); + } + + private static Set startedBundles = new HashSet(); + static { + startedBundles.add("org.eclipse.core.runtime"); + } + + private static boolean isStartUpBundle(BundleInfo bi) { + return startUpBundles.contains(bi.getSymbolicName()); + } + + private static boolean isMarkedAsStarted(BundleInfo bi) { + // Prevent unnecessary bundles from being + // activated by only marking as started the plug-ins that + // are vital to the environment, which always have lower + // start level than the default 4. + return bi.isMarkedAsStarted() && (bi.getStartLevel() < 4 || startedBundles.contains(bi.getSymbolicName())); + } + + private static void writeProperties(Properties properties, File target, String comment) throws IOException { + FileWriter writer = new FileWriter(target); + try { + properties.store(writer, comment); + } finally { + writer.close(); + } + } + + private static void writeFile(String string, File target) throws IOException { + FileWriter writer = new FileWriter(target); + try { + writer.write(string); + } finally { + writer.close(); + } + } + static public final class StagingResult { + + private final int exitValue; + + private final File logFile; + + private final String messageLog; + + public StagingResult(String message) { + this.exitValue = Integer.MIN_VALUE; + this.logFile = null; + this.messageLog = message; + } + public StagingResult(int exitValue, File logFile, String messageLog) { + this.exitValue = exitValue; + this.logFile = logFile; + this.messageLog = messageLog; + } + + public int getExitValue() { + return exitValue; + } + + public File getLogFile() { + return logFile; + } + + public String getMessageLog() { + return messageLog; + } + + } + public static final class Config { + public final Session session; + public final Resource targetLibrary; + public final File workspaceRoot; + public final File clusterMapFolder; + public final File teamFolder; + public final PrintStream out; + // Outputs + public Resource createdModel; + public Resource createdState; + public List messages = new ArrayList(); + public String titlePrefix = "Staging"; + + public Config(Session session, Resource library, File workspaceRoot, File clusterMapFolder) + throws DatabaseException { + this(session, library, workspaceRoot, clusterMapFolder, null); + } + + public Config( Session session, Resource library, File workspaceRoot, File clusterMapFolder, PrintStream out) + throws DatabaseException { + this.session = session; + this.targetLibrary = library; + this.workspaceRoot = workspaceRoot; + this.clusterMapFolder = clusterMapFolder; + this.teamFolder = org.simantics.team.Utils.getTeamFolder(); + this.out = out; + } + } + static final class Constants { + + /** + * Tells the launched application to dump all its system properties into the + * standard output / log. + */ + public static final String PROP_DUMP_PROPERTIES = "dump.properties"; + + /** + * Controls where the launched application log is written. Specified as an URI. + */ + public static final String PROP_LOGFILE = "staging.logfile"; + + /** + * Prefix for the window title. + */ + public static final String PROP_WINDOW_TITLE = "staging.window.title"; + + /** + * Tells the launched application where its team data comes from. + */ + public static final String PROP_TEAM_FOLDER = "staging.team.folder"; + + /** + * Workspace root directory of the workbench process that launched the + * import process. + */ + public static final String PROP_WORKSPACE_ROOT = "import.workspace.root"; + } +}