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