]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Adding configuration logging for Simantics platform with SLF4J and 90/90/2
authorjsimomaa <jani.simomaa@gmail.com>
Fri, 23 Sep 2016 13:14:33 +0000 (16:14 +0300)
committerJani Simomaa <jani.simomaa@semantum.fi>
Fri, 23 Sep 2016 13:23:17 +0000 (16:23 +0300)
Logback

Adding logback.xml file to org.simantics.logback.configuration bundle
for configuring logback logging

refs #6705

Change-Id: I67abe04ed0d6a54b6a45fb3591bbb6b5a3991b2a

13 files changed:
bundles/org.simantics.logback.configuration/.classpath [new file with mode: 0644]
bundles/org.simantics.logback.configuration/.project [new file with mode: 0644]
bundles/org.simantics.logback.configuration/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
bundles/org.simantics.logback.configuration/META-INF/MANIFEST.MF [new file with mode: 0644]
bundles/org.simantics.logback.configuration/build.properties [new file with mode: 0644]
bundles/org.simantics.logback.configuration/logback.xml [new file with mode: 0644]
bundles/org.simantics.workbench/META-INF/MANIFEST.MF
bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java
bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchApplication.java
bundles/org.simantics/META-INF/MANIFEST.MF
bundles/org.simantics/src/org/simantics/SimanticsPlatform.java
bundles/pom.xml
features/org.simantics.rcp.feature/feature.xml

diff --git a/bundles/org.simantics.logback.configuration/.classpath b/bundles/org.simantics.logback.configuration/.classpath
new file mode 100644 (file)
index 0000000..eca7bdb
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.simantics.logback.configuration/.project b/bundles/org.simantics.logback.configuration/.project
new file mode 100644 (file)
index 0000000..3fdee56
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.simantics.logback.configuration</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/bundles/org.simantics.logback.configuration/.settings/org.eclipse.jdt.core.prefs b/bundles/org.simantics.logback.configuration/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..0c68a61
--- /dev/null
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/bundles/org.simantics.logback.configuration/META-INF/MANIFEST.MF b/bundles/org.simantics.logback.configuration/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..504d772
--- /dev/null
@@ -0,0 +1,7 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Configuration
+Bundle-SymbolicName: org.simantics.logback.configuration
+Bundle-Version: 1.0.0.qualifier
+Fragment-Host: ch.qos.logback.classic;bundle-version="1.1.7"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/bundles/org.simantics.logback.configuration/build.properties b/bundles/org.simantics.logback.configuration/build.properties
new file mode 100644 (file)
index 0000000..f9c2504
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               logback.xml
diff --git a/bundles/org.simantics.logback.configuration/logback.xml b/bundles/org.simantics.logback.configuration/logback.xml
new file mode 100644 (file)
index 0000000..38dc393
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+    <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+    <encoder>
+      <pattern>%-5p [%d] %c: %m%n%rEx</pattern>
+    </encoder>
+  </appender>
+
+  <appender name="async-console" class="ch.qos.logback.classic.AsyncAppender">
+    <appender-ref ref="console" />
+  </appender>
+
+  <root level="debug">
+    <appender-ref ref="async-console" />
+  </root>
+</configuration>
\ No newline at end of file
index 76a575878ffa1269840ce056c75447a296ec8d67..887f4937787def2c787a766b73656269d20dc89d 100644 (file)
@@ -6,8 +6,8 @@ Bundle-Version: 1.5.1.qualifier
 Bundle-Activator: org.simantics.workbench.internal.Activator
 Bundle-Vendor: VTT Technical Research Centre of Finland
 Bundle-Localization: plugin
 Bundle-Activator: org.simantics.workbench.internal.Activator
 Bundle-Vendor: VTT Technical Research Centre of Finland
 Bundle-Localization: plugin
-Export-Package: org.simantics.workbench,\r
- org.simantics.workbench.internal,\r
+Export-Package: org.simantics.workbench,
+ org.simantics.workbench.internal,
  org.simantics.workbench.internal.contributions.search
 Require-Bundle: com.ibm.icu,
  org.eclipse.core.runtime,
  org.simantics.workbench.internal.contributions.search
 Require-Bundle: com.ibm.icu,
  org.eclipse.core.runtime,
@@ -44,6 +44,10 @@ Require-Bundle: com.ibm.icu,
  org.eclipse.e4.core.di;bundle-version="1.5.0",
  org.eclipse.e4.ui.di;bundle-version="1.1.0",
  org.eclipse.e4.core.contexts,
  org.eclipse.e4.core.di;bundle-version="1.5.0",
  org.eclipse.e4.ui.di;bundle-version="1.1.0",
  org.eclipse.e4.core.contexts,
- org.eclipse.e4.ui.services
+ org.eclipse.e4.ui.services,
+ org.slf4j.api;bundle-version="1.7.20",
+ ch.qos.logback.classic;bundle-version="1.1.7",
+ ch.qos.logback.core;bundle-version="1.1.7"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ActivationPolicy: lazy
+Bundle-ClassPath: .
index 67a8101cf7a87ff7e0a8e9d8e2b68bde52279bef..0bce2a5680cc57cc0af696be3faf7953cd1bb0db 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.workbench.internal;\r
-\r
-import java.io.IOException;\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.net.URL;\r
-import java.text.Collator;\r
-import java.util.ArrayList;\r
-import java.util.Iterator;\r
-import java.util.Map;\r
-import java.util.TreeMap;\r
-\r
-import org.eclipse.core.internal.resources.Workspace;\r
-import org.eclipse.core.net.proxy.IProxyService;\r
-import org.eclipse.core.resources.IContainer;\r
-import org.eclipse.core.resources.IResource;\r
-import org.eclipse.core.resources.ResourcesPlugin;\r
-import org.eclipse.core.resources.WorkspaceJob;\r
-import org.eclipse.core.runtime.CoreException;\r
-import org.eclipse.core.runtime.FileLocator;\r
-import org.eclipse.core.runtime.IAdaptable;\r
-import org.eclipse.core.runtime.IBundleGroup;\r
-import org.eclipse.core.runtime.IBundleGroupProvider;\r
-import org.eclipse.core.runtime.ILog;\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.core.runtime.IStatus;\r
-import org.eclipse.core.runtime.MultiStatus;\r
-import org.eclipse.core.runtime.Path;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.eclipse.core.runtime.ProgressMonitorWrapper;\r
-import org.eclipse.core.runtime.Status;\r
-import org.eclipse.core.runtime.SubMonitor;\r
-import org.eclipse.core.runtime.jobs.Job;\r
-import org.eclipse.e4.core.contexts.IEclipseContext;\r
-import org.eclipse.e4.ui.internal.workbench.E4Workbench;\r
-import org.eclipse.jface.dialogs.ErrorDialog;\r
-import org.eclipse.jface.dialogs.IDialogSettings;\r
-import org.eclipse.jface.dialogs.MessageDialog;\r
-import org.eclipse.jface.dialogs.TrayDialog;\r
-import org.eclipse.jface.operation.IRunnableWithProgress;\r
-import org.eclipse.jface.preference.IPreferenceStore;\r
-import org.eclipse.jface.resource.ImageDescriptor;\r
-import org.eclipse.jface.util.Policy;\r
-import org.eclipse.jface.window.Window;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Event;\r
-import org.eclipse.swt.widgets.Listener;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.ui.IPerspectiveDescriptor;\r
-import org.eclipse.ui.PlatformUI;\r
-import org.eclipse.ui.application.IWorkbenchConfigurer;\r
-import org.eclipse.ui.application.IWorkbenchWindowConfigurer;\r
-import org.eclipse.ui.application.WorkbenchAdvisor;\r
-import org.eclipse.ui.application.WorkbenchWindowAdvisor;\r
-import org.eclipse.ui.ide.IDE;\r
-import org.eclipse.ui.internal.ISelectionConversionService;\r
-import org.eclipse.ui.internal.Workbench;\r
-import org.eclipse.ui.internal.ide.AboutInfo;\r
-import org.eclipse.ui.internal.ide.IDEInternalPreferences;\r
-import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;\r
-import org.eclipse.ui.internal.ide.IDESelectionConversionService;\r
-import org.eclipse.ui.internal.ide.IDEWorkbenchActivityHelper;\r
-import org.eclipse.ui.internal.ide.IDEWorkbenchErrorHandler;\r
-import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;\r
-import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;\r
-import org.eclipse.ui.internal.ide.undo.WorkspaceUndoMonitor;\r
-import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;\r
-import org.eclipse.ui.keys.IBindingService;\r
-import org.eclipse.ui.progress.IProgressService;\r
-import org.eclipse.ui.statushandlers.AbstractStatusHandler;\r
-import org.osgi.framework.Bundle;\r
-import org.osgi.framework.ServiceReference;\r
-import org.osgi.framework.Version;\r
-import org.simantics.CancelStartupException;\r
-import org.simantics.PlatformException;\r
-import org.simantics.Simantics;\r
-import org.simantics.SimanticsPlatform;\r
-import org.simantics.SimanticsPlatform.OntologyRecoveryPolicy;\r
-import org.simantics.SimanticsPlatform.RecoveryPolicy;\r
-import org.simantics.application.arguments.IArguments;\r
-import org.simantics.application.arguments.SimanticsArguments;\r
-import org.simantics.db.common.Indexing;\r
-import org.simantics.db.indexing.DatabaseIndexing;\r
-import org.simantics.db.procore.server.environment.RebootRequiredException;\r
-import org.simantics.db.procore.server.environment.windows.Product;\r
-import org.simantics.internal.TimedSessionCache;\r
-import org.simantics.project.IProject;\r
-import org.simantics.project.ProjectKeys;\r
-import org.simantics.ui.SimanticsUI;\r
-import org.simantics.ui.jobs.SessionGarbageCollectorJob;\r
-import org.simantics.ui.workbench.PerspectiveBarsActivator;\r
-import org.simantics.ui.workbench.PerspectiveContextActivator;\r
-import org.simantics.utils.logging.TimeLogger;\r
-import org.simantics.utils.threads.ThreadUtils;\r
-import org.simantics.utils.ui.dialogs.ShowError;\r
-import org.simantics.utils.ui.dialogs.ShowMessage;\r
-\r
-\r
-/**\r
- * @author Tuukka Lehtonen\r
- */\r
-public class SimanticsWorkbenchAdvisor extends WorkbenchAdvisor {\r
-\r
-    private static final boolean PROFILE_PLATFORM_STARTUP = false;\r
-\r
-    private static final String SHUT_DOWN_TASK = "Shutting down...";\r
-\r
-    private static final String SHUT_DOWN_PLATFORM_TASK = "Shutting down platform...";\r
-\r
-    private static final String WORKBENCH_PREFERENCE_CATEGORY_ID = "org.eclipse.ui.preferencePages.Workbench"; //$NON-NLS-1$\r
-\r
-    /**\r
-     * The dialog setting key to access the known installed features since the\r
-     * last time the workbench was run.\r
-     */\r
-    private static final String INSTALLED_FEATURES = "installedFeatures"; //$NON-NLS-1$\r
-\r
-    /**\r
-     * The arguments received by the application.\r
-     */\r
-    protected final IArguments args;\r
-\r
-    protected final boolean restoredPreviousSession = false;\r
-\r
-    /**\r
-     * Only true while opening the initial windows during {@link #openWindows()}.\r
-     * Used by {@link SimanticsWorkbenchWindowAdvisor#postWindowOpen()} to\r
-     * recognize when to skip all one-time initialization.\r
-     */\r
-    protected boolean workbenchWindowsInitialized = false;\r
-\r
-    /**\r
-     * Whether or not to save unsaved database changes before exiting the\r
-     * workbench.\r
-     */\r
-    protected boolean saveAtExit = false;\r
-\r
-    /**\r
-     * Ordered map of versioned feature ids -> info that are new for this\r
-     * session; <code>null</code> if uninitialized. Key type:\r
-     * <code>String</code>, Value type: <code>AboutInfo</code>.\r
-     */\r
-    private Map<String, AboutInfo> newlyAddedBundleGroups;\r
-\r
-    /**\r
-     * Array of <code>AboutInfo</code> for all new installed features that\r
-     * specify a welcome perspective.\r
-     */\r
-    private AboutInfo[] welcomePerspectiveInfos = null;\r
-\r
-    /**\r
-     * Helper for managing activites in response to workspace changes.\r
-     */\r
-    private IDEWorkbenchActivityHelper activityHelper = null;\r
-\r
-    /**\r
-     * Helper for managing work that is performed when the system is otherwise\r
-     * idle.\r
-     */\r
-    private IDEIdleHelper idleHelper;\r
-\r
-    private Listener settingsChangeListener;\r
-\r
-    /**\r
-     * Support class for monitoring workspace changes and periodically\r
-     * validating the undo history\r
-     */\r
-    private WorkspaceUndoMonitor workspaceUndoMonitor;\r
-\r
-    /**\r
-     * The IDE workbench error handler.\r
-     */\r
-    private AbstractStatusHandler ideWorkbenchErrorHandler;\r
-\r
-    /**\r
-     * Helper class used to process delayed events.\r
-     */\r
-    private DelayedEventsProcessor delayedEventsProcessor;\r
-    \r
-    /**\r
-     * Creates a new workbench advisor instance.\r
-     * @param processor\r
-     */\r
-    public SimanticsWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) {\r
-        super();\r
-        this.args = args;\r
-        this.delayedEventsProcessor = processor;\r
-\r
-        Listener closeListener = new Listener() {\r
-            public void handleEvent(Event event) {\r
-                boolean doExit = SimanticsWorkbenchWindowAdvisor.promptOnExit(null);\r
-                event.doit = doExit;\r
-                if (!doExit)\r
-                    event.type = SWT.None;\r
-            }\r
-        };\r
-        Display.getDefault().addListener(SWT.Close, closeListener);\r
-    }\r
-\r
-    public IArguments getArguments() {\r
-        return args;\r
-    }\r
-\r
-    public boolean workbenchInitialized() {\r
-        return workbenchWindowsInitialized;\r
-    }\r
-\r
-    public boolean restoredPreviousSession() {\r
-        return restoredPreviousSession;\r
-    }\r
-\r
-    boolean saveAtExit() {\r
-        return saveAtExit;\r
-    }\r
-\r
-    void setSaveAtExit(boolean saveAtExit) {\r
-        this.saveAtExit = saveAtExit;\r
-    }\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     *\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor#initialize\r
-     */\r
-    @Override\r
-    public void initialize(IWorkbenchConfigurer configurer) {\r
-        // By default, we always save and restore the workbench state.\r
-        configurer.setSaveAndRestore(true);\r
-\r
-        checkWorkspaceDatabaseIndexes();\r
-\r
-        // Start tracking the active perspective to activate contexts based on it.\r
-        new PerspectiveContextActivator();\r
-        new PerspectiveBarsActivator();\r
-\r
-        // register workspace adapters\r
-        IDE.registerAdapters();\r
-\r
-        // register shared images\r
-        declareWorkbenchImages();\r
-\r
-        // initialize the activity helper\r
-        activityHelper = IDEWorkbenchActivityHelper.getInstance();\r
-\r
-        // initialize idle handler\r
-        idleHelper = new IDEIdleHelper(configurer);\r
-\r
-        // initialize the workspace undo monitor\r
-        workspaceUndoMonitor = WorkspaceUndoMonitor.getInstance();\r
-\r
-        // show Help button in JFace dialogs\r
-        TrayDialog.setDialogHelpAvailable(true);\r
-\r
-        Policy.setComparator(Collator.getInstance());\r
-    }\r
-\r
-    private void checkWorkspaceDatabaseIndexes() {\r
-        try {\r
-            DatabaseIndexing.validateIndexes();\r
-        } catch (IOException e) {\r
-            Activator.logError("Problems encountered while checking database indexes, see exception for details.", e);\r
-        }\r
-    }\r
-\r
-    public WorkbenchWindowAdvisor createWorkbenchWindowAdvisorClass(SimanticsWorkbenchAdvisor advisor, IWorkbenchWindowConfigurer configurer) {\r
-        return new SimanticsWorkbenchWindowAdvisor(this, configurer);\r
-    }\r
-\r
-    @Override\r
-    public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {\r
-        // Attach database session watchdog.\r
-        new SessionWatchdog().attach( Simantics.getSessionContextProvider() );\r
-\r
-        return createWorkbenchWindowAdvisorClass(this, configurer);\r
-    }\r
-\r
-    /**\r
-     * For gaining direct access to super.openWindows() in implementations\r
-     * inheriting this one.\r
-     */\r
-    public boolean openWindowsSuper() {\r
-        return super.openWindows();\r
-    }\r
-\r
-    /**\r
-     * Sadly we do not know why key bindings are lost and why this helps. But it\r
-     * does. Visiting the <code>Keys</code> preference page and pressing OK uses\r
-     * this the same call and it seems to salvage the bindings that have been in\r
-     * some cases destroyed by <code>BindingToModelProcessor</code>.\r
-     * \r
-     * <p>\r
-     * Related links:\r
-     * https://techblog.ralph-schuster.eu/2013/10/13/eclipsee4-problem-with-key-bindings/comment-page-1/\r
-     * https://www.eclipse.org/forums/index.php/t/550175/\r
-     * https://bugs.eclipse.org/bugs/show_bug.cgi?id=461037\r
-     * \r
-     * @see platform issue #6353\r
-     */\r
-    private void fixBindings() {\r
-        try {\r
-            IBindingService bs = PlatformUI.getWorkbench().getAdapter(IBindingService.class);\r
-            bs.savePreferences(bs.getActiveScheme(), bs.getBindings());\r
-        } catch (IOException e) {\r
-            Activator.logError(getClass().getSimpleName() + ".fixBindings failed", e);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public boolean openWindows() {\r
-        boolean platformOk = startPlatform();\r
-        TimeLogger.log("SimanticsWorkbenchAdvisor.startPlatform finished");\r
-\r
-        if (platformOk) {\r
-            // At this point workbenchConfigurer.getSaveAndRestore()\r
-            // returns false iff something has gone terribly wrong\r
-            // before this. Currently saveAndRestore is always true.\r
-            boolean windowsOpened = super.openWindows();\r
-            TimeLogger.log("Opened windows");\r
-            if (windowsOpened) {\r
-                workbenchWindowsInitialized = true;\r
-\r
-                // Start the database garbage collector after a short while.\r
-                SessionGarbageCollectorJob.getInstance().scheduleAfterQuietTime();\r
-\r
-                // Discard database session undo history at this point to prevent\r
-                // the user from undoing any initialization operations performed\r
-                // by the platform startup.\r
-                SimanticsPlatform.INSTANCE.discardSessionUndoHistory();\r
-                TimeLogger.log("Discarded session undo history");\r
-\r
-                // #6353: Workaround for  \r
-                fixBindings();\r
-\r
-                return true;\r
-            }\r
-        }\r
-\r
-        // Make sure platform shutdown is ran if window opening fails.\r
-        try {\r
-            platformShutdownRunnable.run(null);\r
-        } catch (InvocationTargetException e) {\r
-            Activator.logError(getClass().getSimpleName() + ".openWindows failed", e);\r
-        } catch (InterruptedException e) {\r
-            Activator.logError(getClass().getSimpleName() + ".openWindows failed", e);\r
-        }\r
-        return false;\r
-    }\r
-\r
-    protected boolean startPlatform() {\r
-        // Verify selected perspective\r
-        if (args.contains(SimanticsArguments.PERSPECTIVE)) {\r
-            String perspectiveId = args.get(SimanticsArguments.PERSPECTIVE);\r
-            IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(perspectiveId);\r
-            if (perspective == null) {\r
-                StringBuilder msg = new StringBuilder();\r
-                msg.append("Requested perspective not found: '" + perspectiveId + "'\n");\r
-                msg.append("Valid alternatives are:\n");\r
-                for (IPerspectiveDescriptor pd : PlatformUI.getWorkbench().getPerspectiveRegistry().getPerspectives()) {\r
-                    msg.append("    " + pd.getId() + "\n");\r
-                }\r
-\r
-                ShowMessage.syncShowError("Invalid Perspective", msg.toString());\r
-                return false;\r
-            }\r
-        }\r
-\r
-        ILog log = Platform.getLog(Activator.getDefault().getBundle());\r
-\r
-        try {\r
-            //\r
-            //\r
-            // Create Simantics Platform Helper.\r
-            //\r
-            // If Simantics is started from Eclipse IDE or with -fixerrors option,\r
-            // there is an attempt to fix errors.\r
-            //\r
-            // On ontology mismatch, there is an attempt to merge new ontology to the\r
-            // existing database. With -reinstall, the database is cleaned and\r
-            // reinstalled.\r
-            //\r
-            //\r
-\r
-            RecoveryPolicy workspacePolicy = Platform.inDevelopmentMode() ? RecoveryPolicy.FixError : RecoveryPolicy.ThrowError;\r
-            OntologyRecoveryPolicy ontologyPolicy = Platform.inDevelopmentMode() ? OntologyRecoveryPolicy.Merge : OntologyRecoveryPolicy.ThrowError;\r
-\r
-            if (args.contains(SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS)) {\r
-                workspacePolicy = RecoveryPolicy.FixError;\r
-                ontologyPolicy = OntologyRecoveryPolicy.Merge;\r
-            }\r
-\r
-            boolean requireSynchronize = true;\r
-\r
-            if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) {\r
-                ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase;\r
-            }\r
-\r
-            if (args.contains(SimanticsArguments.DO_NOT_SYNCHRONIZE_ONTOLOGIES)) {\r
-                requireSynchronize = false;\r
-            }\r
-            \r
-            if (args.contains(SimanticsArguments.DISABLE_INDEX)) {\r
-               Indexing.setDefaultDependenciesIndexingEnabled(false);\r
-            }\r
-\r
-            if (args.contains(SimanticsArguments.SERVER)) {\r
-                String serverAddress = args.get(SimanticsArguments.SERVER);\r
-                throw new PlatformException("Argument not supported: " + SimanticsArguments.SERVER + " " + serverAddress);\r
-            }\r
-\r
-            String databaseDriverId = Simantics.getDefaultDatabaseDriver();\r
-            if (args.contains(SimanticsArguments.DATABASE_ID)) {\r
-                databaseDriverId = args.get(SimanticsArguments.DATABASE_ID);\r
-                Simantics.setDefaultDatabaseDriver(databaseDriverId);\r
-            }\r
-            \r
-            IProgressMonitor mon = null;\r
-            if (PROFILE_PLATFORM_STARTUP)\r
-                mon = new TimingProgressMonitor();\r
-            SimanticsPlatform.INSTANCE.startUp(databaseDriverId, mon, workspacePolicy, ontologyPolicy, requireSynchronize, new JFaceUserAgent());\r
-\r
-            // Make sure that the default perspective comes from the project if\r
-            // the project has set ProjectKeys#DEFAULT_PERSPECTIVE.\r
-            // This might go wrong if project features interact with\r
-            // PerspectiveRegistry while configuring themselves, since that will\r
-            // cause an invocation to #getInitialWindowPerspectiveId() while\r
-            // the project has not yet been properly initialized.\r
-            getWorkbenchConfigurer().getWorkbench().getPerspectiveRegistry().setDefaultPerspective(getInitialWindowPerspectiveId());\r
-            TimeLogger.log("Completed setting default perspective");\r
-\r
-            return true;\r
-        } catch (CancelStartupException e) {\r
-            return false;\r
-        } catch (PlatformException e) {\r
-            boolean hasStackTrace = e.getStackTrace().length > 0;\r
-            Throwable ee = e;\r
-            while (ee.getCause() != null) {\r
-                ee = ee.getCause();\r
-                hasStackTrace = ee.getStackTrace().length > 0;\r
-            }\r
-\r
-            log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), hasStackTrace ? e : null));\r
-            if (hasStackTrace) {\r
-                new ShowError("Platform Initialization Failed", "Simantics Platform initialization failed:\n\n" + e.getMessage(), e, true);\r
-            } else {\r
-                StringBuilder sb = new StringBuilder(256);\r
-                sb.append(e.getMessage());\r
-                for (Throwable c=e.getCause(); null != c && null != c.getMessage(); c=c.getCause())\r
-                    sb.append("\ncause: ").append(c.getMessage());\r
-                new ShowError("Startup Failed", sb.toString(), (Exception) null, true);\r
-            }\r
-\r
-            return false;\r
-        } catch (Exception e) {\r
-            log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));\r
-\r
-            Throwable cause = e.getCause();\r
-            if (cause instanceof RebootRequiredException) {\r
-                RebootRequiredException rre = (RebootRequiredException) cause;\r
-                StringBuilder msg = new StringBuilder();\r
-                msg.append("The application must be restarted after installing the following products:\n");\r
-                for (Product product : rre.products)\r
-                    msg.append("\t" + product + "\n");\r
-                msg.append("\nThe application will now close.");\r
-                MessageDialog.openInformation(null, "Restart Required", msg.toString());\r
-            } else {\r
-                new ShowError("Platform Startup Failed", "Simantics Platform startup failed:\n\n" + e.getMessage(), e, true);\r
-            }\r
-            return false;\r
-        }\r
-\r
-    }\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     *\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor#preStartup()\r
-     */\r
-    @Override\r
-    public void preStartup() {\r
-\r
-        // Suspend background jobs while we startup\r
-        Job.getJobManager().suspend();\r
-\r
-        // Register the build actions\r
-        IProgressService service = PlatformUI.getWorkbench()\r
-        .getProgressService();\r
-        ImageDescriptor newImage = IDEInternalWorkbenchImages\r
-        .getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC);\r
-        service.registerIconForFamily(newImage,\r
-                ResourcesPlugin.FAMILY_MANUAL_BUILD);\r
-        service.registerIconForFamily(newImage,\r
-                ResourcesPlugin.FAMILY_AUTO_BUILD);\r
-    }\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     *\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor#postStartup()\r
-     */\r
-    @Override\r
-    public void postStartup() {\r
-        try {\r
-            refreshFromLocal();\r
-            activateProxyService();\r
-            ((Workbench) PlatformUI.getWorkbench()).registerService(\r
-                    ISelectionConversionService.class,\r
-                    new IDESelectionConversionService());\r
-\r
-            initializeSettingsChangeListener();\r
-            Display.getCurrent().addListener(SWT.Settings,\r
-                    settingsChangeListener);\r
-        } finally {// Resume background jobs after we startup\r
-            Job.getJobManager().resume();\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Activate the proxy service by obtaining it.\r
-     */\r
-    private void activateProxyService() {\r
-        Bundle bundle = Platform.getBundle("org.eclipse.ui.ide"); //$NON-NLS-1$\r
-        Object proxyService = null;\r
-        if (bundle != null) {\r
-            ServiceReference<?> ref = bundle.getBundleContext().getServiceReference(IProxyService.class.getName());\r
-            if (ref != null)\r
-                proxyService = bundle.getBundleContext().getService(ref);\r
-        }\r
-        if (proxyService == null) {\r
-            IDEWorkbenchPlugin.log("Proxy service could not be found."); //$NON-NLS-1$\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Initialize the listener for settings changes.\r
-     */\r
-    private void initializeSettingsChangeListener() {\r
-        settingsChangeListener = new Listener() {\r
-\r
-            boolean currentHighContrast = Display.getCurrent()\r
-            .getHighContrast();\r
-\r
-            @Override\r
-            public void handleEvent(org.eclipse.swt.widgets.Event event) {\r
-                if (Display.getCurrent().getHighContrast() == currentHighContrast)\r
-                    return;\r
-\r
-                currentHighContrast = !currentHighContrast;\r
-\r
-                // make sure they really want to do this\r
-                if (new MessageDialog(null,\r
-                        IDEWorkbenchMessages.SystemSettingsChange_title, null,\r
-                        IDEWorkbenchMessages.SystemSettingsChange_message,\r
-                        MessageDialog.QUESTION, new String[] {\r
-                        IDEWorkbenchMessages.SystemSettingsChange_yes,\r
-                        IDEWorkbenchMessages.SystemSettingsChange_no },\r
-                        1).open() == Window.OK) {\r
-                    PlatformUI.getWorkbench().restart();\r
-                }\r
-            }\r
-        };\r
-\r
-    }\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     *\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor#postShutdown\r
-     */\r
-    @Override\r
-    public void postShutdown() {\r
-        if (activityHelper != null) {\r
-            activityHelper.shutdown();\r
-            activityHelper = null;\r
-        }\r
-        if (idleHelper != null) {\r
-            idleHelper.shutdown();\r
-            idleHelper = null;\r
-        }\r
-        if (workspaceUndoMonitor != null) {\r
-            workspaceUndoMonitor.shutdown();\r
-            workspaceUndoMonitor = null;\r
-        }\r
-        if (IDEWorkbenchPlugin.getPluginWorkspace() != null) {\r
-            disconnectFromWorkspace();\r
-        }\r
-    }\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     *\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor#preShutdown()\r
-     */\r
-    @Override\r
-    public boolean preShutdown() {\r
-        Display.getCurrent().removeListener(SWT.Settings,\r
-                settingsChangeListener);\r
-        return super.preShutdown();\r
-    }\r
-\r
-    /**\r
-     * Return true if the intro plugin is present and false otherwise.\r
-     *\r
-     * @return boolean\r
-     */\r
-    public boolean hasIntro() {\r
-        return getWorkbenchConfigurer().getWorkbench().getIntroManager()\r
-                .hasIntro();\r
-    }\r
-\r
-    private void refreshFromLocal() {\r
-        String[] commandLineArgs = Platform.getCommandLineArgs();\r
-        IPreferenceStore store = IDEWorkbenchPlugin.getDefault()\r
-                .getPreferenceStore();\r
-        boolean refresh = store\r
-                .getBoolean(IDEInternalPreferences.REFRESH_WORKSPACE_ON_STARTUP);\r
-        if (!refresh) {\r
-            return;\r
-        }\r
-\r
-        // Do not refresh if it was already done by core on startup.\r
-        for (int i = 0; i < commandLineArgs.length; i++) {\r
-            if (commandLineArgs[i].equalsIgnoreCase("-refresh")) { //$NON-NLS-1$\r
-                return;\r
-            }\r
-        }\r
-\r
-        final IContainer root = ResourcesPlugin.getWorkspace().getRoot();\r
-        Job job = new WorkspaceJob(IDEWorkbenchMessages.Workspace_refreshing) {\r
-            @Override\r
-            public IStatus runInWorkspace(IProgressMonitor monitor)\r
-                    throws CoreException {\r
-                root.refreshLocal(IResource.DEPTH_INFINITE, monitor);\r
-                return Status.OK_STATUS;\r
-            }\r
-        };\r
-        job.setRule(root);\r
-        job.schedule();\r
-    }\r
-\r
-    private static class CancelableProgressMonitorWrapper extends ProgressMonitorWrapper {\r
-        private double total = 0;\r
-        private ProgressMonitorJobsDialog dialog;\r
-\r
-        CancelableProgressMonitorWrapper(IProgressMonitor monitor,\r
-                ProgressMonitorJobsDialog dialog) {\r
-            super(monitor);\r
-            this.dialog = dialog;\r
-        }\r
-\r
-        /*\r
-         * (non-Javadoc)\r
-         * @see org.eclipse.core.runtime.ProgressMonitorWrapper#internalWorked(double)\r
-         */\r
-        public void internalWorked(double work) {\r
-            super.internalWorked(work);\r
-            total += work;\r
-            updateProgressDetails();\r
-        }\r
-\r
-        /*\r
-         * (non-Javadoc)\r
-         * @see org.eclipse.core.runtime.ProgressMonitorWrapper#worked(int)\r
-         */\r
-        public void worked(int work) {\r
-            super.worked(work);\r
-            total += work;\r
-            updateProgressDetails();\r
-        }\r
-\r
-        public void beginTask(String name, int totalWork) {\r
-            super.beginTask(name, totalWork);\r
-            subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_preHistoryCompaction);\r
-        }\r
-\r
-        private void updateProgressDetails() {\r
-            if (!isCanceled() && Math.abs(total - 4.0) < 0.0001 /* right before history compacting */) {\r
-                subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_cancelHistoryPruning);\r
-                dialog.setCancelable(true);\r
-            }\r
-            if (Math.abs(total - 5.0) < 0.0001 /* history compacting finished */) {\r
-                subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_postHistoryCompaction);\r
-                dialog.setCancelable(false);\r
-            }\r
-        }\r
-    }\r
-\r
-    private static class CancelableProgressMonitorJobsDialog extends ProgressMonitorJobsDialog {\r
-\r
-        public CancelableProgressMonitorJobsDialog(Shell parent) {\r
-            super(parent);\r
-        }\r
-\r
-        /*\r
-         * (non-Javadoc)\r
-         * @see org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog#createDetailsButton(org.eclipse.swt.widgets.Composite)\r
-         */\r
-        protected void createButtonsForButtonBar(Composite parent) {\r
-            super.createButtonsForButtonBar(parent);\r
-            registerCancelButtonListener();\r
-        }\r
-\r
-        public void registerCancelButtonListener() {\r
-            cancel.addSelectionListener(new SelectionAdapter() {\r
-                public void widgetSelected(SelectionEvent e) {\r
-                    subTaskLabel.setText(""); //$NON-NLS-1$\r
-                }\r
-            });\r
-        }\r
-    }\r
-\r
-\r
-    final IRunnableWithProgress platformShutdownRunnable = new IRunnableWithProgress() {\r
-        /**\r
-         * @param monitor\r
-         *            the progress monitor to use for reporting progress to the\r
-         *            user, or <code>null</code> indicating that no progress\r
-         *            should be reported and the operation cannot be cancelled.\r
-         */\r
-        @Override\r
-        public void run(IProgressMonitor monitor) {\r
-            SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_PLATFORM_TASK, 100);\r
-            try {\r
-                try {\r
-                    progress.subTask("Platform");\r
-                    SimanticsPlatform.INSTANCE.shutdown(progress.newChild(50));\r
-                } catch (PlatformException e) {\r
-                    Activator.logError("Problems encountered while shutting down Simantics platform, see exception for details.", e);\r
-                }\r
-\r
-                progress.subTask("Remaining database connections");\r
-                SimanticsUI.closeSessions();\r
-                progress.worked(20);\r
-                TimedSessionCache.close();\r
-                progress.worked(20);\r
-\r
-                progress.subTask("Thread pools");\r
-                ThreadUtils.shutdown();\r
-                progress.worked(5);\r
-\r
-                progress.subTask("Clear index status");\r
-                try {\r
-                    // Everything ok, clear index dirty state.\r
-                    DatabaseIndexing.clearAllDirty();\r
-                } catch (IOException e) {\r
-                    Activator.logError("Problems encountered while refreshing database index states, see exception for details.", e);\r
-                }\r
-                progress.worked(5);\r
-\r
-                progress.setWorkRemaining(0);\r
-            } finally {\r
-                if (monitor != null) {\r
-                    monitor.done();\r
-                }\r
-            }\r
-        }\r
-    };\r
-\r
-    /**\r
-     * Disconnect from the workspace and close ProCore sessions.\r
-     */\r
-    private void disconnectFromWorkspace() {\r
-        // save the workspace\r
-        final MultiStatus status = new MultiStatus(\r
-                IDEWorkbenchPlugin.IDE_WORKBENCH, 1,\r
-                IDEWorkbenchMessages.ProblemSavingWorkbench, null);\r
-\r
-        final ProgressMonitorJobsDialog p = new CancelableProgressMonitorJobsDialog(\r
-                null);\r
-\r
-        final boolean applyPolicy = ResourcesPlugin.getWorkspace()\r
-                .getDescription().isApplyFileStatePolicy();\r
-\r
-        final IRunnableWithProgress workspaceShutdownRunnable = new IRunnableWithProgress() {\r
-            @Override\r
-            public void run(IProgressMonitor monitor) {\r
-                try {\r
-                    status.merge(((Workspace) ResourcesPlugin.getWorkspace()).save(true, true, monitor));\r
-                } catch (CoreException e) {\r
-                    status.merge(e.getStatus());\r
-                }\r
-            }\r
-        };\r
-\r
-        IRunnableWithProgress shutdownRunnable = new IRunnableWithProgress() {\r
-            @Override\r
-            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {\r
-                if (applyPolicy)\r
-                    monitor = new CancelableProgressMonitorWrapper(\r
-                            monitor, p);\r
-\r
-                SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_TASK, 2);\r
-                try {\r
-                    workspaceShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE));\r
-                    platformShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE));\r
-                } finally {\r
-                    monitor.done();\r
-                }\r
-            }\r
-        };\r
-\r
-        try {\r
-            new ProgressMonitorJobsDialog(null).run(true, false, shutdownRunnable);\r
-        } catch (InvocationTargetException e) {\r
-            status.merge(new Status(IStatus.ERROR,\r
-                    IDEWorkbenchPlugin.IDE_WORKBENCH, 1,\r
-                    IDEWorkbenchMessages.InternalError, e.getTargetException()));\r
-        } catch (InterruptedException e) {\r
-            status.merge(new Status(IStatus.ERROR,\r
-                    IDEWorkbenchPlugin.IDE_WORKBENCH, 1,\r
-                    IDEWorkbenchMessages.InternalError, e));\r
-        }\r
-        ErrorDialog.openError(null,\r
-                IDEWorkbenchMessages.ProblemsSavingWorkspace, null, status,\r
-                IStatus.ERROR | IStatus.WARNING);\r
-        if (!status.isOK()) {\r
-            IDEWorkbenchPlugin.log(\r
-                    IDEWorkbenchMessages.ProblemsSavingWorkspace, status);\r
-        }\r
-    }\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     *\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor#getDefaultPageInput\r
-     */\r
-    @Override\r
-    public IAdaptable getDefaultPageInput() {\r
-        return ResourcesPlugin.getWorkspace().getRoot();\r
-    }\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     *\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor\r
-     */\r
-    @Override\r
-    public String getInitialWindowPerspectiveId() {\r
-        int index = PlatformUI.getWorkbench().getWorkbenchWindowCount() - 1;\r
-\r
-        String perspectiveId = null;\r
-        AboutInfo[] welcomeInfos = getWelcomePerspectiveInfos();\r
-        if (index >= 0 && welcomeInfos != null && index < welcomeInfos.length) {\r
-            perspectiveId = welcomeInfos[index].getWelcomePerspectiveId();\r
-        }\r
-\r
-        if (perspectiveId == null && args.contains(SimanticsArguments.PERSPECTIVE)) {\r
-            String id = args.get(SimanticsArguments.PERSPECTIVE);\r
-            IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(id);\r
-            if (perspective != null)\r
-                perspectiveId = id;\r
-        }\r
-\r
-        if (perspectiveId == null) {\r
-            IProject project = SimanticsUI.peekProject();\r
-            if (project != null)\r
-                perspectiveId = project.getHint(ProjectKeys.DEFAULT_PERSPECTIVE);\r
-        }\r
-\r
-        //System.out.println("Initial perspective: " + perspectiveId);\r
-\r
-        return perspectiveId;\r
-    }\r
-\r
-    /**\r
-     * Returns the map of versioned feature ids -> info object for all installed\r
-     * features. The format of the versioned feature id (the key of the map) is\r
-     * featureId + ":" + versionId.\r
-     *\r
-     * @return map of versioned feature ids -> info object (key type:\r
-     *         <code>String</code>, value type: <code>AboutInfo</code>)\r
-     * @since 3.0\r
-     */\r
-    private Map<String, AboutInfo> computeBundleGroupMap() {\r
-        // use tree map to get predicable order\r
-        Map<String, AboutInfo> ids = new TreeMap<String, AboutInfo>();\r
-\r
-        IBundleGroupProvider[] providers = Platform.getBundleGroupProviders();\r
-        for (int i = 0; i < providers.length; ++i) {\r
-            IBundleGroup[] groups = providers[i].getBundleGroups();\r
-            for (int j = 0; j < groups.length; ++j) {\r
-                IBundleGroup group = groups[j];\r
-                AboutInfo info = new AboutInfo(group);\r
-\r
-                String version = info.getVersionId();\r
-                version = version == null ? "0.0.0" //$NON-NLS-1$\r
-                        : new Version(version).toString();\r
-                String versionedFeature = group.getIdentifier() + ":" + version; //$NON-NLS-1$\r
-\r
-                ids.put(versionedFeature, info);\r
-            }\r
-        }\r
-\r
-        return ids;\r
-    }\r
-\r
-    /**\r
-     * Returns the ordered map of versioned feature ids -> AboutInfo that are\r
-     * new for this session.\r
-     *\r
-     * @return ordered map of versioned feature ids (key type:\r
-     *         <code>String</code>) -> infos (value type:\r
-     *         <code>AboutInfo</code>).\r
-     */\r
-    public Map<String, AboutInfo> getNewlyAddedBundleGroups() {\r
-        if (newlyAddedBundleGroups == null) {\r
-            newlyAddedBundleGroups = createNewBundleGroupsMap();\r
-        }\r
-        return newlyAddedBundleGroups;\r
-    }\r
-\r
-    /**\r
-     * Updates the old features setting and returns a map of new features.\r
-     */\r
-    private Map<String, AboutInfo> createNewBundleGroupsMap() {\r
-        // retrieve list of installed bundle groups from last session\r
-        IDialogSettings settings = IDEWorkbenchPlugin.getDefault()\r
-                .getDialogSettings();\r
-        String[] previousFeaturesArray = settings.getArray(INSTALLED_FEATURES);\r
-\r
-        // get a map of currently installed bundle groups and store it for next\r
-        // session\r
-        Map<String, AboutInfo> bundleGroups = computeBundleGroupMap();\r
-        String[] currentFeaturesArray = new String[bundleGroups.size()];\r
-        bundleGroups.keySet().toArray(currentFeaturesArray);\r
-        settings.put(INSTALLED_FEATURES, currentFeaturesArray);\r
-\r
-        // remove the previously known from the current set\r
-        if (previousFeaturesArray != null) {\r
-            for (int i = 0; i < previousFeaturesArray.length; ++i) {\r
-                bundleGroups.remove(previousFeaturesArray[i]);\r
-            }\r
-        }\r
-\r
-        return bundleGroups;\r
-    }\r
-\r
-    /**\r
-     * Declares all IDE-specific workbench images. This includes both "shared"\r
-     * images (named in {@link IDE.SharedImages}) and internal images (named in\r
-     * {@link org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages}).\r
-     *\r
-     * @see IWorkbenchConfigurer#declareImage\r
-     */\r
-    private void declareWorkbenchImages() {\r
-\r
-        final String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$\r
-        final String PATH_ELOCALTOOL = ICONS_PATH + "elcl16/"; // Enabled //$NON-NLS-1$\r
-\r
-        // toolbar\r
-        // icons.\r
-        final String PATH_DLOCALTOOL = ICONS_PATH + "dlcl16/"; // Disabled //$NON-NLS-1$\r
-        // //$NON-NLS-1$\r
-        // toolbar\r
-        // icons.\r
-        final String PATH_ETOOL = ICONS_PATH + "etool16/"; // Enabled toolbar //$NON-NLS-1$\r
-        // //$NON-NLS-1$\r
-        // icons.\r
-        final String PATH_DTOOL = ICONS_PATH + "dtool16/"; // Disabled toolbar //$NON-NLS-1$\r
-        // //$NON-NLS-1$\r
-        // icons.\r
-        final String PATH_OBJECT = ICONS_PATH + "obj16/"; // Model object //$NON-NLS-1$\r
-        // //$NON-NLS-1$\r
-        // icons\r
-        final String PATH_WIZBAN = ICONS_PATH + "wizban/"; // Wizard //$NON-NLS-1$\r
-        // //$NON-NLS-1$\r
-        // icons\r
-\r
-        Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH);\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC, PATH_ETOOL\r
-                + "build_exec.gif", false); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_HOVER,\r
-                PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED,\r
-                PATH_DTOOL + "build_exec.gif", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC, PATH_ETOOL\r
-                + "search_src.gif", false); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_HOVER,\r
-                PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_DISABLED,\r
-                PATH_DTOOL + "search_src.gif", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ETOOL_NEXT_NAV, PATH_ETOOL\r
-                + "next_nav.gif", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ETOOL_PREVIOUS_NAV, PATH_ETOOL\r
-                + "prev_nav.gif", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_WIZBAN_NEWPRJ_WIZ, PATH_WIZBAN\r
-                + "newprj_wiz.png", false); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFOLDER_WIZ,\r
-                PATH_WIZBAN + "newfolder_wiz.png", false); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFILE_WIZ, PATH_WIZBAN\r
-                + "newfile_wiz.png", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTDIR_WIZ,\r
-                PATH_WIZBAN + "importdir_wiz.png", false); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTZIP_WIZ,\r
-                PATH_WIZBAN + "importzip_wiz.png", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTDIR_WIZ,\r
-                PATH_WIZBAN + "exportdir_wiz.png", false); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTZIP_WIZ,\r
-                PATH_WIZBAN + "exportzip_wiz.png", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ,\r
-                PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN\r
-                + "saveas_wiz.png", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG, PATH_WIZBAN\r
-                + "quick_fix.png", false); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT,\r
-                PATH_OBJECT + "prj_obj.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT\r
-                + "cprj_obj.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OPEN_MARKER,\r
-                PATH_ELOCALTOOL + "gotoobj_tsk.gif", true); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ELCL_QUICK_FIX_ENABLED,\r
-                PATH_ELOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_DLCL_QUICK_FIX_DISABLED,\r
-                PATH_DLOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$\r
-\r
-        // task objects\r
-        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_HPRIO_TSK,\r
-        // PATH_OBJECT+"hprio_tsk.gif");\r
-        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_MPRIO_TSK,\r
-        // PATH_OBJECT+"mprio_tsk.gif");\r
-        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LPRIO_TSK,\r
-        // PATH_OBJECT+"lprio_tsk.gif");\r
-\r
-        declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_TASK_TSK,\r
-                PATH_OBJECT + "taskmrk_tsk.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_BKMRK_TSK,\r
-                PATH_OBJECT + "bkmrk_tsk.gif", true); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_OBJS_COMPLETE_TSK, PATH_OBJECT\r
-                + "complete_tsk.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_OBJS_INCOMPLETE_TSK, PATH_OBJECT\r
-                + "incomplete_tsk.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM, PATH_OBJECT\r
-                + "welcome_item.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER, PATH_OBJECT\r
-                + "welcome_banner.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_OBJS_ERROR_PATH, PATH_OBJECT\r
-                + "error_tsk.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_OBJS_WARNING_PATH, PATH_OBJECT\r
-                + "warn_tsk.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_OBJS_INFO_PATH, PATH_OBJECT\r
-                + "info_tsk.gif", true); //$NON-NLS-1$\r
-\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_LCL_FLAT_LAYOUT, PATH_ELOCALTOOL\r
-                + "flatLayout.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_LCL_HIERARCHICAL_LAYOUT,\r
-                PATH_ELOCALTOOL + "hierarchicalLayout.gif", true); //$NON-NLS-1$\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY,\r
-                PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$\r
-        /*\r
-        declareWorkbenchImage(ideBundle,\r
-                IDEInternalWorkbenchImages.IMG_LCL_LINKTO_HELP, PATH_ELOCALTOOL\r
-                        + "linkto_help.gif", false); //$NON-NLS-1$\r
-         */\r
-\r
-        // synchronization indicator objects\r
-        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT,\r
-        // PATH_OVERLAY+"wbet_stat.gif");\r
-        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_SBET_STAT,\r
-        // PATH_OVERLAY+"sbet_stat.gif");\r
-        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_CONFLICT_STAT,\r
-        // PATH_OVERLAY+"conflict_stat.gif");\r
-\r
-        // content locality indicator objects\r
-        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_NOTLOCAL_STAT,\r
-        // PATH_STAT+"notlocal_stat.gif");\r
-        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LOCAL_STAT,\r
-        // PATH_STAT+"local_stat.gif");\r
-        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_FILLLOCAL_STAT,\r
-        // PATH_STAT+"filllocal_stat.gif");\r
-    }\r
-\r
-    /**\r
-     * Declares an IDE-specific workbench image.\r
-     *\r
-     * @param symbolicName\r
-     *            the symbolic name of the image\r
-     * @param path\r
-     *            the path of the image file; this path is relative to the base\r
-     *            of the IDE plug-in\r
-     * @param shared\r
-     *            <code>true</code> if this is a shared image, and\r
-     *            <code>false</code> if this is not a shared image\r
-     * @see IWorkbenchConfigurer#declareImage\r
-     */\r
-    private void declareWorkbenchImage(Bundle ideBundle, String symbolicName,\r
-            String path, boolean shared) {\r
-        URL url = FileLocator.find(ideBundle, new Path(path), null);\r
-        ImageDescriptor desc = ImageDescriptor.createFromURL(url);\r
-        getWorkbenchConfigurer().declareImage(symbolicName, desc, shared);\r
-    }\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     *\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor#getMainPreferencePageId\r
-     */\r
-    @Override\r
-    public String getMainPreferencePageId() {\r
-        // indicate that we want the Workench preference page to be prominent\r
-        return WORKBENCH_PREFERENCE_CATEGORY_ID;\r
-    }\r
-\r
-    /**\r
-     * @return the workspace location string, or <code>null</code> if the\r
-     *         location is not being shown\r
-     */\r
-    public String getWorkspaceLocation() {\r
-               // read command line, which has priority\r
-               IEclipseContext context = getWorkbenchConfigurer().getWorkbench().getService(IEclipseContext.class);\r
-               String location = context != null ? (String) context.get(E4Workbench.FORCED_SHOW_LOCATION) : null;\r
-               if (location != null) {\r
-                       return location;\r
-               }\r
-               // read the preference\r
-               if (IDEWorkbenchPlugin.getDefault().getPreferenceStore().getBoolean(IDEInternalPreferences.SHOW_LOCATION)) {\r
-                       return Platform.getLocation().toOSString();\r
-               }\r
-               return null;\r
-    }\r
-\r
-    /**\r
-     * @return the welcome perspective infos, or <code>null</code> if none or\r
-     *         if they should be ignored due to the new intro being present\r
-     */\r
-    public AboutInfo[] getWelcomePerspectiveInfos() {\r
-        if (welcomePerspectiveInfos == null) {\r
-            // support old welcome perspectives if intro plugin is not present\r
-            if (!hasIntro()) {\r
-                Map<String, AboutInfo> m = getNewlyAddedBundleGroups();\r
-                ArrayList<AboutInfo> list = new ArrayList<AboutInfo>(m.size());\r
-                for (Iterator<AboutInfo> i = m.values().iterator(); i.hasNext();) {\r
-                    AboutInfo info = i.next();\r
-                    if (info != null && info.getWelcomePerspectiveId() != null\r
-                            && info.getWelcomePageURL() != null) {\r
-                        list.add(info);\r
-                    }\r
-                }\r
-                welcomePerspectiveInfos = new AboutInfo[list.size()];\r
-                list.toArray(welcomePerspectiveInfos);\r
-            }\r
-        }\r
-        return welcomePerspectiveInfos;\r
-    }\r
-\r
-    /*\r
-     * (non-Javadoc)\r
-     *\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor#getWorkbenchErrorHandler()\r
-     */\r
-    @Override\r
-    public AbstractStatusHandler getWorkbenchErrorHandler() {\r
-        if (ideWorkbenchErrorHandler == null) {\r
-            ideWorkbenchErrorHandler = new IDEWorkbenchErrorHandler(\r
-                    getWorkbenchConfigurer());\r
-        }\r
-        return ideWorkbenchErrorHandler;\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.ui.application.WorkbenchAdvisor#eventLoopIdle(org.eclipse.swt.widgets.Display)\r
-     */\r
-    @Override\r
-    public void eventLoopIdle(Display display) {\r
-        if (delayedEventsProcessor != null)\r
-            delayedEventsProcessor.catchUp(display);\r
-        super.eventLoopIdle(display);\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * 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:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.workbench.internal;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.eclipse.core.internal.resources.Workspace;
+import org.eclipse.core.net.proxy.IProxyService;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.resources.WorkspaceJob;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IBundleGroup;
+import org.eclipse.core.runtime.IBundleGroupProvider;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.ProgressMonitorWrapper;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.E4Workbench;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.Policy;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.application.IWorkbenchConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.internal.ISelectionConversionService;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.ide.AboutInfo;
+import org.eclipse.ui.internal.ide.IDEInternalPreferences;
+import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
+import org.eclipse.ui.internal.ide.IDESelectionConversionService;
+import org.eclipse.ui.internal.ide.IDEWorkbenchActivityHelper;
+import org.eclipse.ui.internal.ide.IDEWorkbenchErrorHandler;
+import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
+import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
+import org.eclipse.ui.internal.ide.undo.WorkspaceUndoMonitor;
+import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.progress.IProgressService;
+import org.eclipse.ui.statushandlers.AbstractStatusHandler;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.simantics.CancelStartupException;
+import org.simantics.PlatformException;
+import org.simantics.Simantics;
+import org.simantics.SimanticsPlatform;
+import org.simantics.SimanticsPlatform.OntologyRecoveryPolicy;
+import org.simantics.SimanticsPlatform.RecoveryPolicy;
+import org.simantics.application.arguments.IArguments;
+import org.simantics.application.arguments.SimanticsArguments;
+import org.simantics.db.common.Indexing;
+import org.simantics.db.indexing.DatabaseIndexing;
+import org.simantics.db.procore.server.environment.RebootRequiredException;
+import org.simantics.db.procore.server.environment.windows.Product;
+import org.simantics.internal.TimedSessionCache;
+import org.simantics.project.IProject;
+import org.simantics.project.ProjectKeys;
+import org.simantics.ui.SimanticsUI;
+import org.simantics.ui.jobs.SessionGarbageCollectorJob;
+import org.simantics.ui.workbench.PerspectiveBarsActivator;
+import org.simantics.ui.workbench.PerspectiveContextActivator;
+import org.simantics.utils.logging.TimeLogger;
+import org.simantics.utils.threads.ThreadUtils;
+import org.simantics.utils.ui.dialogs.ShowError;
+import org.simantics.utils.ui.dialogs.ShowMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class SimanticsWorkbenchAdvisor extends WorkbenchAdvisor {
+    
+    private static final Logger LOGGER = LoggerFactory.getLogger(SimanticsWorkbenchAdvisor.class);
+
+    private static final boolean PROFILE_PLATFORM_STARTUP = false;
+
+    private static final String SHUT_DOWN_TASK = "Shutting down...";
+
+    private static final String SHUT_DOWN_PLATFORM_TASK = "Shutting down platform...";
+
+    private static final String WORKBENCH_PREFERENCE_CATEGORY_ID = "org.eclipse.ui.preferencePages.Workbench"; //$NON-NLS-1$
+
+    /**
+     * The dialog setting key to access the known installed features since the
+     * last time the workbench was run.
+     */
+    private static final String INSTALLED_FEATURES = "installedFeatures"; //$NON-NLS-1$
+
+    /**
+     * The arguments received by the application.
+     */
+    protected final IArguments args;
+
+    protected final boolean restoredPreviousSession = false;
+
+    /**
+     * Only true while opening the initial windows during {@link #openWindows()}.
+     * Used by {@link SimanticsWorkbenchWindowAdvisor#postWindowOpen()} to
+     * recognize when to skip all one-time initialization.
+     */
+    protected boolean workbenchWindowsInitialized = false;
+
+    /**
+     * Whether or not to save unsaved database changes before exiting the
+     * workbench.
+     */
+    protected boolean saveAtExit = false;
+
+    /**
+     * Ordered map of versioned feature ids -> info that are new for this
+     * session; <code>null</code> if uninitialized. Key type:
+     * <code>String</code>, Value type: <code>AboutInfo</code>.
+     */
+    private Map<String, AboutInfo> newlyAddedBundleGroups;
+
+    /**
+     * Array of <code>AboutInfo</code> for all new installed features that
+     * specify a welcome perspective.
+     */
+    private AboutInfo[] welcomePerspectiveInfos = null;
+
+    /**
+     * Helper for managing activites in response to workspace changes.
+     */
+    private IDEWorkbenchActivityHelper activityHelper = null;
+
+    /**
+     * Helper for managing work that is performed when the system is otherwise
+     * idle.
+     */
+    private IDEIdleHelper idleHelper;
+
+    private Listener settingsChangeListener;
+
+    /**
+     * Support class for monitoring workspace changes and periodically
+     * validating the undo history
+     */
+    private WorkspaceUndoMonitor workspaceUndoMonitor;
+
+    /**
+     * The IDE workbench error handler.
+     */
+    private AbstractStatusHandler ideWorkbenchErrorHandler;
+
+    /**
+     * Helper class used to process delayed events.
+     */
+    private DelayedEventsProcessor delayedEventsProcessor;
+    
+    /**
+     * Creates a new workbench advisor instance.
+     * @param processor
+     */
+    public SimanticsWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) {
+        super();
+        this.args = args;
+        this.delayedEventsProcessor = processor;
+
+        Listener closeListener = new Listener() {
+            public void handleEvent(Event event) {
+                boolean doExit = SimanticsWorkbenchWindowAdvisor.promptOnExit(null);
+                event.doit = doExit;
+                if (!doExit)
+                    event.type = SWT.None;
+            }
+        };
+        Display.getDefault().addListener(SWT.Close, closeListener);
+    }
+
+    public IArguments getArguments() {
+        return args;
+    }
+
+    public boolean workbenchInitialized() {
+        return workbenchWindowsInitialized;
+    }
+
+    public boolean restoredPreviousSession() {
+        return restoredPreviousSession;
+    }
+
+    boolean saveAtExit() {
+        return saveAtExit;
+    }
+
+    void setSaveAtExit(boolean saveAtExit) {
+        this.saveAtExit = saveAtExit;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.ui.application.WorkbenchAdvisor#initialize
+     */
+    @Override
+    public void initialize(IWorkbenchConfigurer configurer) {
+        // By default, we always save and restore the workbench state.
+        configurer.setSaveAndRestore(true);
+
+        checkWorkspaceDatabaseIndexes();
+
+        // Start tracking the active perspective to activate contexts based on it.
+        new PerspectiveContextActivator();
+        new PerspectiveBarsActivator();
+
+        // register workspace adapters
+        IDE.registerAdapters();
+
+        // register shared images
+        declareWorkbenchImages();
+
+        // initialize the activity helper
+        activityHelper = IDEWorkbenchActivityHelper.getInstance();
+
+        // initialize idle handler
+        idleHelper = new IDEIdleHelper(configurer);
+
+        // initialize the workspace undo monitor
+        workspaceUndoMonitor = WorkspaceUndoMonitor.getInstance();
+
+        // show Help button in JFace dialogs
+        TrayDialog.setDialogHelpAvailable(true);
+
+        Policy.setComparator(Collator.getInstance());
+    }
+
+    private void checkWorkspaceDatabaseIndexes() {
+        try {
+            DatabaseIndexing.validateIndexes();
+        } catch (IOException e) {
+            Activator.logError("Problems encountered while checking database indexes, see exception for details.", e);
+        }
+    }
+
+    public WorkbenchWindowAdvisor createWorkbenchWindowAdvisorClass(SimanticsWorkbenchAdvisor advisor, IWorkbenchWindowConfigurer configurer) {
+        return new SimanticsWorkbenchWindowAdvisor(this, configurer);
+    }
+
+    @Override
+    public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
+        // Attach database session watchdog.
+        new SessionWatchdog().attach( Simantics.getSessionContextProvider() );
+
+        return createWorkbenchWindowAdvisorClass(this, configurer);
+    }
+
+    /**
+     * For gaining direct access to super.openWindows() in implementations
+     * inheriting this one.
+     */
+    public boolean openWindowsSuper() {
+        return super.openWindows();
+    }
+
+    /**
+     * Sadly we do not know why key bindings are lost and why this helps. But it
+     * does. Visiting the <code>Keys</code> preference page and pressing OK uses
+     * this the same call and it seems to salvage the bindings that have been in
+     * some cases destroyed by <code>BindingToModelProcessor</code>.
+     * 
+     * <p>
+     * Related links:
+     * https://techblog.ralph-schuster.eu/2013/10/13/eclipsee4-problem-with-key-bindings/comment-page-1/
+     * https://www.eclipse.org/forums/index.php/t/550175/
+     * https://bugs.eclipse.org/bugs/show_bug.cgi?id=461037
+     * 
+     * @see platform issue #6353
+     */
+    private void fixBindings() {
+        try {
+            IBindingService bs = PlatformUI.getWorkbench().getAdapter(IBindingService.class);
+            bs.savePreferences(bs.getActiveScheme(), bs.getBindings());
+        } catch (IOException e) {
+            Activator.logError(getClass().getSimpleName() + ".fixBindings failed", e);
+        }
+    }
+
+    @Override
+    public boolean openWindows() {
+        boolean platformOk = startPlatform();
+        LOGGER.info("startPlatform finished");
+        TimeLogger.log("SimanticsWorkbenchAdvisor.startPlatform finished");
+
+        if (platformOk) {
+            // At this point workbenchConfigurer.getSaveAndRestore()
+            // returns false iff something has gone terribly wrong
+            // before this. Currently saveAndRestore is always true.
+            boolean windowsOpened = super.openWindows();
+            TimeLogger.log("Opened windows");
+            if (windowsOpened) {
+                workbenchWindowsInitialized = true;
+
+                // Start the database garbage collector after a short while.
+                SessionGarbageCollectorJob.getInstance().scheduleAfterQuietTime();
+
+                // Discard database session undo history at this point to prevent
+                // the user from undoing any initialization operations performed
+                // by the platform startup.
+                SimanticsPlatform.INSTANCE.discardSessionUndoHistory();
+                TimeLogger.log("Discarded session undo history");
+
+                // #6353: Workaround for  
+                fixBindings();
+
+                return true;
+            }
+        }
+
+        // Make sure platform shutdown is ran if window opening fails.
+        try {
+            platformShutdownRunnable.run(null);
+        } catch (InvocationTargetException e) {
+            Activator.logError(getClass().getSimpleName() + ".openWindows failed", e);
+        } catch (InterruptedException e) {
+            Activator.logError(getClass().getSimpleName() + ".openWindows failed", e);
+        }
+        return false;
+    }
+
+    protected boolean startPlatform() {
+        // Verify selected perspective
+        if (args.contains(SimanticsArguments.PERSPECTIVE)) {
+            String perspectiveId = args.get(SimanticsArguments.PERSPECTIVE);
+            IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(perspectiveId);
+            if (perspective == null) {
+                StringBuilder msg = new StringBuilder();
+                msg.append("Requested perspective not found: '" + perspectiveId + "'\n");
+                msg.append("Valid alternatives are:\n");
+                for (IPerspectiveDescriptor pd : PlatformUI.getWorkbench().getPerspectiveRegistry().getPerspectives()) {
+                    msg.append("    " + pd.getId() + "\n");
+                }
+
+                ShowMessage.syncShowError("Invalid Perspective", msg.toString());
+                return false;
+            }
+        }
+
+        ILog log = Platform.getLog(Activator.getDefault().getBundle());
+
+        try {
+            //
+            //
+            // Create Simantics Platform Helper.
+            //
+            // If Simantics is started from Eclipse IDE or with -fixerrors option,
+            // there is an attempt to fix errors.
+            //
+            // On ontology mismatch, there is an attempt to merge new ontology to the
+            // existing database. With -reinstall, the database is cleaned and
+            // reinstalled.
+            //
+            //
+
+            RecoveryPolicy workspacePolicy = Platform.inDevelopmentMode() ? RecoveryPolicy.FixError : RecoveryPolicy.ThrowError;
+            OntologyRecoveryPolicy ontologyPolicy = Platform.inDevelopmentMode() ? OntologyRecoveryPolicy.Merge : OntologyRecoveryPolicy.ThrowError;
+
+            if (args.contains(SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS)) {
+                workspacePolicy = RecoveryPolicy.FixError;
+                ontologyPolicy = OntologyRecoveryPolicy.Merge;
+            }
+
+            boolean requireSynchronize = true;
+
+            if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) {
+                ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase;
+            }
+
+            if (args.contains(SimanticsArguments.DO_NOT_SYNCHRONIZE_ONTOLOGIES)) {
+                requireSynchronize = false;
+            }
+            
+            if (args.contains(SimanticsArguments.DISABLE_INDEX)) {
+               Indexing.setDefaultDependenciesIndexingEnabled(false);
+            }
+
+            if (args.contains(SimanticsArguments.SERVER)) {
+                String serverAddress = args.get(SimanticsArguments.SERVER);
+                throw new PlatformException("Argument not supported: " + SimanticsArguments.SERVER + " " + serverAddress);
+            }
+
+            String databaseDriverId = Simantics.getDefaultDatabaseDriver();
+            if (args.contains(SimanticsArguments.DATABASE_ID)) {
+                databaseDriverId = args.get(SimanticsArguments.DATABASE_ID);
+                Simantics.setDefaultDatabaseDriver(databaseDriverId);
+            }
+            
+            IProgressMonitor mon = null;
+            if (PROFILE_PLATFORM_STARTUP)
+                mon = new TimingProgressMonitor();
+            SimanticsPlatform.INSTANCE.startUp(databaseDriverId, mon, workspacePolicy, ontologyPolicy, requireSynchronize, new JFaceUserAgent());
+
+            // Make sure that the default perspective comes from the project if
+            // the project has set ProjectKeys#DEFAULT_PERSPECTIVE.
+            // This might go wrong if project features interact with
+            // PerspectiveRegistry while configuring themselves, since that will
+            // cause an invocation to #getInitialWindowPerspectiveId() while
+            // the project has not yet been properly initialized.
+            getWorkbenchConfigurer().getWorkbench().getPerspectiveRegistry().setDefaultPerspective(getInitialWindowPerspectiveId());
+            TimeLogger.log("Completed setting default perspective");
+
+            return true;
+        } catch (CancelStartupException e) {
+            return false;
+        } catch (PlatformException e) {
+            boolean hasStackTrace = e.getStackTrace().length > 0;
+            Throwable ee = e;
+            while (ee.getCause() != null) {
+                ee = ee.getCause();
+                hasStackTrace = ee.getStackTrace().length > 0;
+            }
+
+            log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), hasStackTrace ? e : null));
+            if (hasStackTrace) {
+                new ShowError("Platform Initialization Failed", "Simantics Platform initialization failed:\n\n" + e.getMessage(), e, true);
+            } else {
+                StringBuilder sb = new StringBuilder(256);
+                sb.append(e.getMessage());
+                for (Throwable c=e.getCause(); null != c && null != c.getMessage(); c=c.getCause())
+                    sb.append("\ncause: ").append(c.getMessage());
+                new ShowError("Startup Failed", sb.toString(), (Exception) null, true);
+            }
+
+            return false;
+        } catch (Exception e) {
+            log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
+
+            Throwable cause = e.getCause();
+            if (cause instanceof RebootRequiredException) {
+                RebootRequiredException rre = (RebootRequiredException) cause;
+                StringBuilder msg = new StringBuilder();
+                msg.append("The application must be restarted after installing the following products:\n");
+                for (Product product : rre.products)
+                    msg.append("\t" + product + "\n");
+                msg.append("\nThe application will now close.");
+                MessageDialog.openInformation(null, "Restart Required", msg.toString());
+            } else {
+                new ShowError("Platform Startup Failed", "Simantics Platform startup failed:\n\n" + e.getMessage(), e, true);
+            }
+            return false;
+        }
+
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.ui.application.WorkbenchAdvisor#preStartup()
+     */
+    @Override
+    public void preStartup() {
+
+        // Suspend background jobs while we startup
+        Job.getJobManager().suspend();
+
+        // Register the build actions
+        IProgressService service = PlatformUI.getWorkbench()
+        .getProgressService();
+        ImageDescriptor newImage = IDEInternalWorkbenchImages
+        .getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC);
+        service.registerIconForFamily(newImage,
+                ResourcesPlugin.FAMILY_MANUAL_BUILD);
+        service.registerIconForFamily(newImage,
+                ResourcesPlugin.FAMILY_AUTO_BUILD);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.ui.application.WorkbenchAdvisor#postStartup()
+     */
+    @Override
+    public void postStartup() {
+        try {
+            refreshFromLocal();
+            activateProxyService();
+            ((Workbench) PlatformUI.getWorkbench()).registerService(
+                    ISelectionConversionService.class,
+                    new IDESelectionConversionService());
+
+            initializeSettingsChangeListener();
+            Display.getCurrent().addListener(SWT.Settings,
+                    settingsChangeListener);
+        } finally {// Resume background jobs after we startup
+            Job.getJobManager().resume();
+        }
+    }
+
+    /**
+     * Activate the proxy service by obtaining it.
+     */
+    private void activateProxyService() {
+        Bundle bundle = Platform.getBundle("org.eclipse.ui.ide"); //$NON-NLS-1$
+        Object proxyService = null;
+        if (bundle != null) {
+            ServiceReference<?> ref = bundle.getBundleContext().getServiceReference(IProxyService.class.getName());
+            if (ref != null)
+                proxyService = bundle.getBundleContext().getService(ref);
+        }
+        if (proxyService == null) {
+            IDEWorkbenchPlugin.log("Proxy service could not be found."); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Initialize the listener for settings changes.
+     */
+    private void initializeSettingsChangeListener() {
+        settingsChangeListener = new Listener() {
+
+            boolean currentHighContrast = Display.getCurrent()
+            .getHighContrast();
+
+            @Override
+            public void handleEvent(org.eclipse.swt.widgets.Event event) {
+                if (Display.getCurrent().getHighContrast() == currentHighContrast)
+                    return;
+
+                currentHighContrast = !currentHighContrast;
+
+                // make sure they really want to do this
+                if (new MessageDialog(null,
+                        IDEWorkbenchMessages.SystemSettingsChange_title, null,
+                        IDEWorkbenchMessages.SystemSettingsChange_message,
+                        MessageDialog.QUESTION, new String[] {
+                        IDEWorkbenchMessages.SystemSettingsChange_yes,
+                        IDEWorkbenchMessages.SystemSettingsChange_no },
+                        1).open() == Window.OK) {
+                    PlatformUI.getWorkbench().restart();
+                }
+            }
+        };
+
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.ui.application.WorkbenchAdvisor#postShutdown
+     */
+    @Override
+    public void postShutdown() {
+        if (activityHelper != null) {
+            activityHelper.shutdown();
+            activityHelper = null;
+        }
+        if (idleHelper != null) {
+            idleHelper.shutdown();
+            idleHelper = null;
+        }
+        if (workspaceUndoMonitor != null) {
+            workspaceUndoMonitor.shutdown();
+            workspaceUndoMonitor = null;
+        }
+        if (IDEWorkbenchPlugin.getPluginWorkspace() != null) {
+            disconnectFromWorkspace();
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.ui.application.WorkbenchAdvisor#preShutdown()
+     */
+    @Override
+    public boolean preShutdown() {
+        Display.getCurrent().removeListener(SWT.Settings,
+                settingsChangeListener);
+        return super.preShutdown();
+    }
+
+    /**
+     * Return true if the intro plugin is present and false otherwise.
+     *
+     * @return boolean
+     */
+    public boolean hasIntro() {
+        return getWorkbenchConfigurer().getWorkbench().getIntroManager()
+                .hasIntro();
+    }
+
+    private void refreshFromLocal() {
+        String[] commandLineArgs = Platform.getCommandLineArgs();
+        IPreferenceStore store = IDEWorkbenchPlugin.getDefault()
+                .getPreferenceStore();
+        boolean refresh = store
+                .getBoolean(IDEInternalPreferences.REFRESH_WORKSPACE_ON_STARTUP);
+        if (!refresh) {
+            return;
+        }
+
+        // Do not refresh if it was already done by core on startup.
+        for (int i = 0; i < commandLineArgs.length; i++) {
+            if (commandLineArgs[i].equalsIgnoreCase("-refresh")) { //$NON-NLS-1$
+                return;
+            }
+        }
+
+        final IContainer root = ResourcesPlugin.getWorkspace().getRoot();
+        Job job = new WorkspaceJob(IDEWorkbenchMessages.Workspace_refreshing) {
+            @Override
+            public IStatus runInWorkspace(IProgressMonitor monitor)
+                    throws CoreException {
+                root.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+                return Status.OK_STATUS;
+            }
+        };
+        job.setRule(root);
+        job.schedule();
+    }
+
+    private static class CancelableProgressMonitorWrapper extends ProgressMonitorWrapper {
+        private double total = 0;
+        private ProgressMonitorJobsDialog dialog;
+
+        CancelableProgressMonitorWrapper(IProgressMonitor monitor,
+                ProgressMonitorJobsDialog dialog) {
+            super(monitor);
+            this.dialog = dialog;
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see org.eclipse.core.runtime.ProgressMonitorWrapper#internalWorked(double)
+         */
+        public void internalWorked(double work) {
+            super.internalWorked(work);
+            total += work;
+            updateProgressDetails();
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see org.eclipse.core.runtime.ProgressMonitorWrapper#worked(int)
+         */
+        public void worked(int work) {
+            super.worked(work);
+            total += work;
+            updateProgressDetails();
+        }
+
+        public void beginTask(String name, int totalWork) {
+            super.beginTask(name, totalWork);
+            subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_preHistoryCompaction);
+        }
+
+        private void updateProgressDetails() {
+            if (!isCanceled() && Math.abs(total - 4.0) < 0.0001 /* right before history compacting */) {
+                subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_cancelHistoryPruning);
+                dialog.setCancelable(true);
+            }
+            if (Math.abs(total - 5.0) < 0.0001 /* history compacting finished */) {
+                subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_postHistoryCompaction);
+                dialog.setCancelable(false);
+            }
+        }
+    }
+
+    private static class CancelableProgressMonitorJobsDialog extends ProgressMonitorJobsDialog {
+
+        public CancelableProgressMonitorJobsDialog(Shell parent) {
+            super(parent);
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog#createDetailsButton(org.eclipse.swt.widgets.Composite)
+         */
+        protected void createButtonsForButtonBar(Composite parent) {
+            super.createButtonsForButtonBar(parent);
+            registerCancelButtonListener();
+        }
+
+        public void registerCancelButtonListener() {
+            cancel.addSelectionListener(new SelectionAdapter() {
+                public void widgetSelected(SelectionEvent e) {
+                    subTaskLabel.setText(""); //$NON-NLS-1$
+                }
+            });
+        }
+    }
+
+
+    final IRunnableWithProgress platformShutdownRunnable = new IRunnableWithProgress() {
+        /**
+         * @param monitor
+         *            the progress monitor to use for reporting progress to the
+         *            user, or <code>null</code> indicating that no progress
+         *            should be reported and the operation cannot be cancelled.
+         */
+        @Override
+        public void run(IProgressMonitor monitor) {
+            SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_PLATFORM_TASK, 100);
+            try {
+                try {
+                    progress.subTask("Platform");
+                    SimanticsPlatform.INSTANCE.shutdown(progress.newChild(50));
+                } catch (PlatformException e) {
+                    Activator.logError("Problems encountered while shutting down Simantics platform, see exception for details.", e);
+                }
+
+                progress.subTask("Remaining database connections");
+                SimanticsUI.closeSessions();
+                progress.worked(20);
+                TimedSessionCache.close();
+                progress.worked(20);
+
+                progress.subTask("Thread pools");
+                ThreadUtils.shutdown();
+                progress.worked(5);
+
+                progress.subTask("Clear index status");
+                try {
+                    // Everything ok, clear index dirty state.
+                    DatabaseIndexing.clearAllDirty();
+                } catch (IOException e) {
+                    Activator.logError("Problems encountered while refreshing database index states, see exception for details.", e);
+                }
+                progress.worked(5);
+
+                progress.setWorkRemaining(0);
+            } finally {
+                if (monitor != null) {
+                    monitor.done();
+                }
+            }
+        }
+    };
+
+    /**
+     * Disconnect from the workspace and close ProCore sessions.
+     */
+    private void disconnectFromWorkspace() {
+        // save the workspace
+        final MultiStatus status = new MultiStatus(
+                IDEWorkbenchPlugin.IDE_WORKBENCH, 1,
+                IDEWorkbenchMessages.ProblemSavingWorkbench, null);
+
+        final ProgressMonitorJobsDialog p = new CancelableProgressMonitorJobsDialog(
+                null);
+
+        final boolean applyPolicy = ResourcesPlugin.getWorkspace()
+                .getDescription().isApplyFileStatePolicy();
+
+        final IRunnableWithProgress workspaceShutdownRunnable = new IRunnableWithProgress() {
+            @Override
+            public void run(IProgressMonitor monitor) {
+                try {
+                    status.merge(((Workspace) ResourcesPlugin.getWorkspace()).save(true, true, monitor));
+                } catch (CoreException e) {
+                    status.merge(e.getStatus());
+                }
+            }
+        };
+
+        IRunnableWithProgress shutdownRunnable = new IRunnableWithProgress() {
+            @Override
+            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+                if (applyPolicy)
+                    monitor = new CancelableProgressMonitorWrapper(
+                            monitor, p);
+
+                SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_TASK, 2);
+                try {
+                    workspaceShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE));
+                    platformShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE));
+                } finally {
+                    monitor.done();
+                }
+            }
+        };
+
+        try {
+            new ProgressMonitorJobsDialog(null).run(true, false, shutdownRunnable);
+        } catch (InvocationTargetException e) {
+            status.merge(new Status(IStatus.ERROR,
+                    IDEWorkbenchPlugin.IDE_WORKBENCH, 1,
+                    IDEWorkbenchMessages.InternalError, e.getTargetException()));
+        } catch (InterruptedException e) {
+            status.merge(new Status(IStatus.ERROR,
+                    IDEWorkbenchPlugin.IDE_WORKBENCH, 1,
+                    IDEWorkbenchMessages.InternalError, e));
+        }
+        ErrorDialog.openError(null,
+                IDEWorkbenchMessages.ProblemsSavingWorkspace, null, status,
+                IStatus.ERROR | IStatus.WARNING);
+        if (!status.isOK()) {
+            IDEWorkbenchPlugin.log(
+                    IDEWorkbenchMessages.ProblemsSavingWorkspace, status);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.ui.application.WorkbenchAdvisor#getDefaultPageInput
+     */
+    @Override
+    public IAdaptable getDefaultPageInput() {
+        return ResourcesPlugin.getWorkspace().getRoot();
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.ui.application.WorkbenchAdvisor
+     */
+    @Override
+    public String getInitialWindowPerspectiveId() {
+        int index = PlatformUI.getWorkbench().getWorkbenchWindowCount() - 1;
+
+        String perspectiveId = null;
+        AboutInfo[] welcomeInfos = getWelcomePerspectiveInfos();
+        if (index >= 0 && welcomeInfos != null && index < welcomeInfos.length) {
+            perspectiveId = welcomeInfos[index].getWelcomePerspectiveId();
+        }
+
+        if (perspectiveId == null && args.contains(SimanticsArguments.PERSPECTIVE)) {
+            String id = args.get(SimanticsArguments.PERSPECTIVE);
+            IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(id);
+            if (perspective != null)
+                perspectiveId = id;
+        }
+
+        if (perspectiveId == null) {
+            IProject project = SimanticsUI.peekProject();
+            if (project != null)
+                perspectiveId = project.getHint(ProjectKeys.DEFAULT_PERSPECTIVE);
+        }
+
+        //System.out.println("Initial perspective: " + perspectiveId);
+
+        return perspectiveId;
+    }
+
+    /**
+     * Returns the map of versioned feature ids -> info object for all installed
+     * features. The format of the versioned feature id (the key of the map) is
+     * featureId + ":" + versionId.
+     *
+     * @return map of versioned feature ids -> info object (key type:
+     *         <code>String</code>, value type: <code>AboutInfo</code>)
+     * @since 3.0
+     */
+    private Map<String, AboutInfo> computeBundleGroupMap() {
+        // use tree map to get predicable order
+        Map<String, AboutInfo> ids = new TreeMap<String, AboutInfo>();
+
+        IBundleGroupProvider[] providers = Platform.getBundleGroupProviders();
+        for (int i = 0; i < providers.length; ++i) {
+            IBundleGroup[] groups = providers[i].getBundleGroups();
+            for (int j = 0; j < groups.length; ++j) {
+                IBundleGroup group = groups[j];
+                AboutInfo info = new AboutInfo(group);
+
+                String version = info.getVersionId();
+                version = version == null ? "0.0.0" //$NON-NLS-1$
+                        : new Version(version).toString();
+                String versionedFeature = group.getIdentifier() + ":" + version; //$NON-NLS-1$
+
+                ids.put(versionedFeature, info);
+            }
+        }
+
+        return ids;
+    }
+
+    /**
+     * Returns the ordered map of versioned feature ids -> AboutInfo that are
+     * new for this session.
+     *
+     * @return ordered map of versioned feature ids (key type:
+     *         <code>String</code>) -> infos (value type:
+     *         <code>AboutInfo</code>).
+     */
+    public Map<String, AboutInfo> getNewlyAddedBundleGroups() {
+        if (newlyAddedBundleGroups == null) {
+            newlyAddedBundleGroups = createNewBundleGroupsMap();
+        }
+        return newlyAddedBundleGroups;
+    }
+
+    /**
+     * Updates the old features setting and returns a map of new features.
+     */
+    private Map<String, AboutInfo> createNewBundleGroupsMap() {
+        // retrieve list of installed bundle groups from last session
+        IDialogSettings settings = IDEWorkbenchPlugin.getDefault()
+                .getDialogSettings();
+        String[] previousFeaturesArray = settings.getArray(INSTALLED_FEATURES);
+
+        // get a map of currently installed bundle groups and store it for next
+        // session
+        Map<String, AboutInfo> bundleGroups = computeBundleGroupMap();
+        String[] currentFeaturesArray = new String[bundleGroups.size()];
+        bundleGroups.keySet().toArray(currentFeaturesArray);
+        settings.put(INSTALLED_FEATURES, currentFeaturesArray);
+
+        // remove the previously known from the current set
+        if (previousFeaturesArray != null) {
+            for (int i = 0; i < previousFeaturesArray.length; ++i) {
+                bundleGroups.remove(previousFeaturesArray[i]);
+            }
+        }
+
+        return bundleGroups;
+    }
+
+    /**
+     * Declares all IDE-specific workbench images. This includes both "shared"
+     * images (named in {@link IDE.SharedImages}) and internal images (named in
+     * {@link org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages}).
+     *
+     * @see IWorkbenchConfigurer#declareImage
+     */
+    private void declareWorkbenchImages() {
+
+        final String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$
+        final String PATH_ELOCALTOOL = ICONS_PATH + "elcl16/"; // Enabled //$NON-NLS-1$
+
+        // toolbar
+        // icons.
+        final String PATH_DLOCALTOOL = ICONS_PATH + "dlcl16/"; // Disabled //$NON-NLS-1$
+        // //$NON-NLS-1$
+        // toolbar
+        // icons.
+        final String PATH_ETOOL = ICONS_PATH + "etool16/"; // Enabled toolbar //$NON-NLS-1$
+        // //$NON-NLS-1$
+        // icons.
+        final String PATH_DTOOL = ICONS_PATH + "dtool16/"; // Disabled toolbar //$NON-NLS-1$
+        // //$NON-NLS-1$
+        // icons.
+        final String PATH_OBJECT = ICONS_PATH + "obj16/"; // Model object //$NON-NLS-1$
+        // //$NON-NLS-1$
+        // icons
+        final String PATH_WIZBAN = ICONS_PATH + "wizban/"; // Wizard //$NON-NLS-1$
+        // //$NON-NLS-1$
+        // icons
+
+        Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH);
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC, PATH_ETOOL
+                + "build_exec.gif", false); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_HOVER,
+                PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED,
+                PATH_DTOOL + "build_exec.gif", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC, PATH_ETOOL
+                + "search_src.gif", false); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_HOVER,
+                PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_DISABLED,
+                PATH_DTOOL + "search_src.gif", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ETOOL_NEXT_NAV, PATH_ETOOL
+                + "next_nav.gif", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ETOOL_PREVIOUS_NAV, PATH_ETOOL
+                + "prev_nav.gif", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_WIZBAN_NEWPRJ_WIZ, PATH_WIZBAN
+                + "newprj_wiz.png", false); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFOLDER_WIZ,
+                PATH_WIZBAN + "newfolder_wiz.png", false); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFILE_WIZ, PATH_WIZBAN
+                + "newfile_wiz.png", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTDIR_WIZ,
+                PATH_WIZBAN + "importdir_wiz.png", false); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTZIP_WIZ,
+                PATH_WIZBAN + "importzip_wiz.png", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTDIR_WIZ,
+                PATH_WIZBAN + "exportdir_wiz.png", false); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTZIP_WIZ,
+                PATH_WIZBAN + "exportzip_wiz.png", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ,
+                PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN
+                + "saveas_wiz.png", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG, PATH_WIZBAN
+                + "quick_fix.png", false); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT,
+                PATH_OBJECT + "prj_obj.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT
+                + "cprj_obj.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OPEN_MARKER,
+                PATH_ELOCALTOOL + "gotoobj_tsk.gif", true); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ELCL_QUICK_FIX_ENABLED,
+                PATH_ELOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_DLCL_QUICK_FIX_DISABLED,
+                PATH_DLOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$
+
+        // task objects
+        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_HPRIO_TSK,
+        // PATH_OBJECT+"hprio_tsk.gif");
+        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_MPRIO_TSK,
+        // PATH_OBJECT+"mprio_tsk.gif");
+        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LPRIO_TSK,
+        // PATH_OBJECT+"lprio_tsk.gif");
+
+        declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_TASK_TSK,
+                PATH_OBJECT + "taskmrk_tsk.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_BKMRK_TSK,
+                PATH_OBJECT + "bkmrk_tsk.gif", true); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_OBJS_COMPLETE_TSK, PATH_OBJECT
+                + "complete_tsk.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_OBJS_INCOMPLETE_TSK, PATH_OBJECT
+                + "incomplete_tsk.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM, PATH_OBJECT
+                + "welcome_item.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER, PATH_OBJECT
+                + "welcome_banner.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_OBJS_ERROR_PATH, PATH_OBJECT
+                + "error_tsk.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_OBJS_WARNING_PATH, PATH_OBJECT
+                + "warn_tsk.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_OBJS_INFO_PATH, PATH_OBJECT
+                + "info_tsk.gif", true); //$NON-NLS-1$
+
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_LCL_FLAT_LAYOUT, PATH_ELOCALTOOL
+                + "flatLayout.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_LCL_HIERARCHICAL_LAYOUT,
+                PATH_ELOCALTOOL + "hierarchicalLayout.gif", true); //$NON-NLS-1$
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY,
+                PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$
+        /*
+        declareWorkbenchImage(ideBundle,
+                IDEInternalWorkbenchImages.IMG_LCL_LINKTO_HELP, PATH_ELOCALTOOL
+                        + "linkto_help.gif", false); //$NON-NLS-1$
+         */
+
+        // synchronization indicator objects
+        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT,
+        // PATH_OVERLAY+"wbet_stat.gif");
+        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_SBET_STAT,
+        // PATH_OVERLAY+"sbet_stat.gif");
+        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_CONFLICT_STAT,
+        // PATH_OVERLAY+"conflict_stat.gif");
+
+        // content locality indicator objects
+        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_NOTLOCAL_STAT,
+        // PATH_STAT+"notlocal_stat.gif");
+        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LOCAL_STAT,
+        // PATH_STAT+"local_stat.gif");
+        // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_FILLLOCAL_STAT,
+        // PATH_STAT+"filllocal_stat.gif");
+    }
+
+    /**
+     * Declares an IDE-specific workbench image.
+     *
+     * @param symbolicName
+     *            the symbolic name of the image
+     * @param path
+     *            the path of the image file; this path is relative to the base
+     *            of the IDE plug-in
+     * @param shared
+     *            <code>true</code> if this is a shared image, and
+     *            <code>false</code> if this is not a shared image
+     * @see IWorkbenchConfigurer#declareImage
+     */
+    private void declareWorkbenchImage(Bundle ideBundle, String symbolicName,
+            String path, boolean shared) {
+        URL url = FileLocator.find(ideBundle, new Path(path), null);
+        ImageDescriptor desc = ImageDescriptor.createFromURL(url);
+        getWorkbenchConfigurer().declareImage(symbolicName, desc, shared);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.ui.application.WorkbenchAdvisor#getMainPreferencePageId
+     */
+    @Override
+    public String getMainPreferencePageId() {
+        // indicate that we want the Workench preference page to be prominent
+        return WORKBENCH_PREFERENCE_CATEGORY_ID;
+    }
+
+    /**
+     * @return the workspace location string, or <code>null</code> if the
+     *         location is not being shown
+     */
+    public String getWorkspaceLocation() {
+               // read command line, which has priority
+               IEclipseContext context = getWorkbenchConfigurer().getWorkbench().getService(IEclipseContext.class);
+               String location = context != null ? (String) context.get(E4Workbench.FORCED_SHOW_LOCATION) : null;
+               if (location != null) {
+                       return location;
+               }
+               // read the preference
+               if (IDEWorkbenchPlugin.getDefault().getPreferenceStore().getBoolean(IDEInternalPreferences.SHOW_LOCATION)) {
+                       return Platform.getLocation().toOSString();
+               }
+               return null;
+    }
+
+    /**
+     * @return the welcome perspective infos, or <code>null</code> if none or
+     *         if they should be ignored due to the new intro being present
+     */
+    public AboutInfo[] getWelcomePerspectiveInfos() {
+        if (welcomePerspectiveInfos == null) {
+            // support old welcome perspectives if intro plugin is not present
+            if (!hasIntro()) {
+                Map<String, AboutInfo> m = getNewlyAddedBundleGroups();
+                ArrayList<AboutInfo> list = new ArrayList<AboutInfo>(m.size());
+                for (Iterator<AboutInfo> i = m.values().iterator(); i.hasNext();) {
+                    AboutInfo info = i.next();
+                    if (info != null && info.getWelcomePerspectiveId() != null
+                            && info.getWelcomePageURL() != null) {
+                        list.add(info);
+                    }
+                }
+                welcomePerspectiveInfos = new AboutInfo[list.size()];
+                list.toArray(welcomePerspectiveInfos);
+            }
+        }
+        return welcomePerspectiveInfos;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.ui.application.WorkbenchAdvisor#getWorkbenchErrorHandler()
+     */
+    @Override
+    public AbstractStatusHandler getWorkbenchErrorHandler() {
+        if (ideWorkbenchErrorHandler == null) {
+            ideWorkbenchErrorHandler = new IDEWorkbenchErrorHandler(
+                    getWorkbenchConfigurer());
+        }
+        return ideWorkbenchErrorHandler;
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.application.WorkbenchAdvisor#eventLoopIdle(org.eclipse.swt.widgets.Display)
+     */
+    @Override
+    public void eventLoopIdle(Display display) {
+        if (delayedEventsProcessor != null)
+            delayedEventsProcessor.catchUp(display);
+        super.eventLoopIdle(display);
+    }
+
+}
index cc0cc024e3314925b24b4b31e607d71dce28e4f9..8b0431f38e9cde7d6236b146ab5d239034eca37a 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.workbench.internal;\r
-\r
-import java.io.File;\r
-import java.io.FileInputStream;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.io.OutputStream;\r
-import java.net.MalformedURLException;\r
-import java.net.URL;\r
-import java.util.Map;\r
-import java.util.Properties;\r
-\r
-import org.eclipse.core.runtime.IConfigurationElement;\r
-import org.eclipse.core.runtime.IExecutableExtension;\r
-import org.eclipse.core.runtime.IStatus;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.eclipse.core.runtime.Status;\r
-import org.eclipse.equinox.app.IApplication;\r
-import org.eclipse.equinox.app.IApplicationContext;\r
-import org.eclipse.jface.dialogs.Dialog;\r
-import org.eclipse.jface.dialogs.MessageDialog;\r
-import org.eclipse.osgi.service.datalocation.Location;\r
-import org.eclipse.osgi.util.NLS;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.MessageBox;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.ui.IWorkbench;\r
-import org.eclipse.ui.PlatformUI;\r
-import org.eclipse.ui.application.WorkbenchAdvisor;\r
-import org.eclipse.ui.internal.WorkbenchPlugin;\r
-import org.eclipse.ui.internal.ide.ChooseWorkspaceData;\r
-import org.eclipse.ui.internal.ide.ChooseWorkspaceDialog;\r
-import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;\r
-import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;\r
-import org.eclipse.ui.internal.ide.StatusUtil;\r
-import org.simantics.application.arguments.ApplicationUtils;\r
-import org.simantics.application.arguments.Arguments;\r
-import org.simantics.application.arguments.IArgumentFactory;\r
-import org.simantics.application.arguments.IArguments;\r
-import org.simantics.application.arguments.SimanticsArguments;\r
-import org.simantics.db.management.ISessionContextProvider;\r
-import org.simantics.db.management.ISessionContextProviderSource;\r
-import org.simantics.db.management.SessionContextProvider;\r
-import org.simantics.db.management.SingleSessionContextProviderSource;\r
-import org.simantics.ui.SimanticsUI;\r
-import org.simantics.ui.WorkbenchWindowSessionContextProviderSource;\r
-import org.simantics.utils.ui.BundleUtils;\r
-\r
-\r
-/**\r
- * The "main program" for the Eclipse IDE.\r
- * \r
- * @since 3.0\r
- */\r
-public class SimanticsWorkbenchApplication implements IApplication, IExecutableExtension {\r
-\r
-    /**\r
-     * The name of the folder containing metadata information for the workspace.\r
-     */\r
-    public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$\r
-\r
-    private static final String VERSION_FILENAME = "version.ini"; //$NON-NLS-1$\r
-\r
-    private static final String WORKSPACE_VERSION_KEY = "org.eclipse.core.runtime"; //$NON-NLS-1$\r
-\r
-    private static final String WORKSPACE_VERSION_VALUE = "1"; //$NON-NLS-1$\r
-\r
-    private static final String PROP_EXIT_CODE = "eclipse.exitcode"; //$NON-NLS-1$\r
-\r
-    /**\r
-     * A special return code that will be recognized by the launcher and used to\r
-     * restart the workbench.\r
-     */\r
-    private static final Integer EXIT_RELAUNCH = new Integer(24);\r
-\r
-    /**\r
-     * A special return code that will be recognized by the PDE launcher and used to\r
-     * show an error dialog if the workspace is locked.\r
-     */\r
-    private static final Integer EXIT_WORKSPACE_LOCKED = new Integer(15);\r
-\r
-    /**\r
-     * Creates a new IDE application.\r
-     */\r
-    public SimanticsWorkbenchApplication() {\r
-        // There is nothing to do for WorkbenchApplication\r
-    }\r
-\r
-    public WorkbenchAdvisor createWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) {\r
-        return new SimanticsWorkbenchAdvisor(args, processor);\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext context)\r
-     */\r
-    @Override\r
-    public Object start(IApplicationContext appContext) throws Exception {\r
-        ApplicationUtils.loadSystemProperties(BundleUtils.find(Activator.PLUGIN_ID, "system.properties"));\r
-        IArguments args = parseArguments((String[]) appContext.getArguments().get(IApplicationContext.APPLICATION_ARGS));\r
-\r
-        Display display = createDisplay();\r
-        // processor must be created before we start event loop\r
-        DelayedEventsProcessor processor = new DelayedEventsProcessor(display);\r
-\r
-        try {\r
-            Object argCheck = verifyArguments(args);\r
-            if (argCheck != null)\r
-                return argCheck;\r
-\r
-            // look and see if there's a splash shell we can parent off of\r
-            Shell shell = WorkbenchPlugin.getSplashShell(display);\r
-            if (shell != null) {\r
-                // should should set the icon and message for this shell to be the \r
-                // same as the chooser dialog - this will be the guy that lives in\r
-                // the task bar and without these calls you'd have the default icon \r
-                // with no message.\r
-                shell.setText(ChooseWorkspaceDialog.getWindowTitle());\r
-                shell.setImages(Dialog.getDefaultImages());\r
-            }\r
-\r
-            Object instanceLocationCheck = checkInstanceLocation(shell, appContext.getArguments(), args);\r
-            if (instanceLocationCheck != null) {\r
-                WorkbenchPlugin.unsetSplashShell(display);\r
-                Platform.endSplash();\r
-                return instanceLocationCheck;\r
-            }\r
-\r
-            final ISessionContextProvider provider = new SessionContextProvider(null);\r
-            final ISessionContextProviderSource contextProviderSource = new SingleSessionContextProviderSource(provider);\r
-            //final ISessionContextProviderSource contextProviderSource = new WorkbenchWindowSessionContextProviderSource(PlatformUI.getWorkbench());\r
-            SimanticsUI.setSessionContextProviderSource(contextProviderSource);\r
-            org.simantics.db.layer0.internal.SimanticsInternal.setSessionContextProviderSource(contextProviderSource);\r
-            org.simantics.Simantics.setSessionContextProviderSource(contextProviderSource);\r
-            \r
-            // create the workbench with this advisor and run it until it exits\r
-            // N.B. createWorkbench remembers the advisor, and also registers\r
-            // the workbench globally so that all UI plug-ins can find it using\r
-            // PlatformUI.getWorkbench() or AbstractUIPlugin.getWorkbench()\r
-            int returnCode = PlatformUI.createAndRunWorkbench(display,\r
-                    createWorkbenchAdvisor(args, processor));\r
-\r
-            // the workbench doesn't support relaunch yet (bug 61809) so\r
-            // for now restart is used, and exit data properties are checked\r
-            // here to substitute in the relaunch return code if needed\r
-            if (returnCode != PlatformUI.RETURN_RESTART) {\r
-                return EXIT_OK;\r
-            }\r
-\r
-            // if the exit code property has been set to the relaunch code, then\r
-            // return that code now, otherwise this is a normal restart\r
-            return EXIT_RELAUNCH.equals(Integer.getInteger(PROP_EXIT_CODE)) ? EXIT_RELAUNCH\r
-                    : EXIT_RESTART;\r
-        } finally {\r
-            if (display != null) {\r
-                display.dispose();\r
-            }\r
-            Location instanceLoc = Platform.getInstanceLocation();\r
-            if (instanceLoc != null)\r
-                instanceLoc.release();\r
-        }\r
-    }\r
-\r
-    /*************************************************************************/\r
-\r
-    private IArguments parseArguments(String[] args) {\r
-        IArgumentFactory<?>[] accepted = {\r
-                SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS,\r
-                SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL,\r
-                SimanticsArguments.DEFAULT_WORKSPACE_LOCATION,\r
-                SimanticsArguments.WORKSPACE_CHOOSER,\r
-                SimanticsArguments.WORKSPACE_NO_REMEMBER,\r
-                SimanticsArguments.PERSPECTIVE,\r
-                SimanticsArguments.SERVER,\r
-                SimanticsArguments.NEW_MODEL,\r
-                SimanticsArguments.EXPERIMENT,\r
-                SimanticsArguments.DISABLE_INDEX,\r
-                SimanticsArguments.DATABASE_ID,\r
-        };\r
-        IArguments result = Arguments.parse(args, accepted);\r
-        return result;\r
-    }\r
-\r
-    private Object verifyArguments(IArguments args) {\r
-        StringBuilder report = new StringBuilder();\r
-\r
-//        if (args.contains(SimanticsArguments.NEW_PROJECT)) {\r
-//            if (args.contains(SimanticsArguments.PROJECT)) {\r
-//                exclusiveArguments(report, SimanticsArguments.PROJECT, SimanticsArguments.NEW_PROJECT);\r
-//            }\r
-//            // Must have a server to checkout from when creating a new\r
-//            // project right from the beginning.\r
-//            if (!args.contains(SimanticsArguments.SERVER)) {\r
-//                missingArgument(report, SimanticsArguments.SERVER);\r
-//            }\r
-//        } else if (args.contains(SimanticsArguments.PROJECT)) {\r
-//            // To load a project, a server must be defined to checkout from\r
-//            if (!args.contains(SimanticsArguments.SERVER)) {\r
-//                missingArgument(report, SimanticsArguments.SERVER);\r
-//            }\r
-//        }\r
-\r
-        // NEW_MODEL and MODEL arguments are optional\r
-        // EXPERIMENT argument is optional\r
-\r
-        String result = report.toString();\r
-        boolean valid = result.length() == 0;\r
-\r
-        if (!valid) {\r
-            String msg = NLS.bind(Messages.Application_1, result);\r
-            MessageDialog.openInformation(null, Messages.Application_2, msg);\r
-        }\r
-        return valid ? null : EXIT_OK;\r
-    }\r
-\r
-//    private void exclusiveArguments(StringBuilder sb, IArgumentFactory<?> arg1, IArgumentFactory<?> arg2) {\r
-//        sb.append(NLS.bind(Messages.Application_3, arg1.getArgument(), arg2.getArgument()));\r
-//        sb.append('\n');\r
-//    }\r
-//\r
-//    private void missingArgument(StringBuilder sb, IArgumentFactory<?> arg) {\r
-//        sb.append(NLS.bind(Messages.Application_0, arg.getArgument()));\r
-//        sb.append('\n');\r
-//    }\r
-\r
-    /*************************************************************************/\r
-\r
-    /**\r
-     * Creates the display used by the application.\r
-     * \r
-     * @return the display used by the application\r
-     */\r
-    protected Display createDisplay() {\r
-        return PlatformUI.createDisplay();\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)\r
-     */\r
-    @Override\r
-    public void setInitializationData(IConfigurationElement config,\r
-            String propertyName, Object data) {\r
-        // There is nothing to do for ProConfApplication\r
-    }\r
-\r
-    /**\r
-     * Return true if a valid workspace path has been set and false otherwise.\r
-     * Prompt for and set the path if possible and required.\r
-     * @param applicationArguments \r
-     * \r
-     * @return true if a valid instance location has been set and false\r
-     *         otherwise\r
-     */\r
-    private Object checkInstanceLocation(Shell shell, Map<?,?> applicationArguments, IArguments args) {\r
-        // -data @none was specified but an ide requires workspace\r
-        Location instanceLoc = Platform.getInstanceLocation();\r
-        if (instanceLoc == null) {\r
-            MessageDialog\r
-            .openError(\r
-                    shell,\r
-                    IDEWorkbenchMessages.IDEApplication_workspaceMandatoryTitle,\r
-                    IDEWorkbenchMessages.IDEApplication_workspaceMandatoryMessage);\r
-            return EXIT_OK;\r
-        }\r
-\r
-        // -data "/valid/path", workspace already set\r
-        // This information is stored in configuration/.settings/org.eclipse.ui.ide.prefs\r
-        if (instanceLoc.isSet()) {\r
-            // make sure the meta data version is compatible (or the user has\r
-            // chosen to overwrite it).\r
-            if (!checkValidWorkspace(shell, instanceLoc.getURL())) {\r
-                return EXIT_OK;\r
-            }\r
-\r
-            // at this point its valid, so try to lock it and update the\r
-            // metadata version information if successful\r
-            try {\r
-                if (instanceLoc.lock()) {\r
-                    writeWorkspaceVersion();\r
-                    return null;\r
-                }\r
-\r
-                // we failed to create the directory.\r
-                // Two possibilities:\r
-                // 1. directory is already in use\r
-                // 2. directory could not be created\r
-                File workspaceDirectory = new File(instanceLoc.getURL().getFile());\r
-                if (workspaceDirectory.exists()) {\r
-                    if (isDevLaunchMode(applicationArguments)) {\r
-                        return EXIT_WORKSPACE_LOCKED;\r
-                    }\r
-                    MessageDialog.openError(\r
-                            shell,\r
-                            IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle,\r
-                            IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage);\r
-                } else {\r
-                    MessageDialog.openError(\r
-                            shell,\r
-                            IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,\r
-                            IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);\r
-                }\r
-            } catch (IOException e) {\r
-                IDEWorkbenchPlugin.log("Could not obtain lock for workspace location", //$NON-NLS-1$\r
-                        e);\r
-                MessageDialog\r
-                .openError(\r
-                        shell,\r
-                        IDEWorkbenchMessages.InternalError,\r
-                        e.getMessage());\r
-            }\r
-            return EXIT_OK;\r
-        }\r
-\r
-        // -data @noDefault or -data not specified, prompt and set\r
-        ChooseWorkspaceData launchData = null;\r
-        if (args.contains(SimanticsArguments.DEFAULT_WORKSPACE_LOCATION)) {\r
-            launchData = new ChooseWorkspaceData(args.get(SimanticsArguments.DEFAULT_WORKSPACE_LOCATION));\r
-        } else {\r
-            launchData = new ChooseWorkspaceData(instanceLoc.getDefault());\r
-        }\r
-\r
-        boolean force = args.contains(SimanticsArguments.WORKSPACE_CHOOSER);\r
-        boolean suppressAskAgain = args.contains(SimanticsArguments.WORKSPACE_NO_REMEMBER);\r
-\r
-        while (true) {\r
-            URL workspaceUrl = promptForWorkspace(shell, launchData, force, suppressAskAgain);\r
-            if (workspaceUrl == null) {\r
-                return EXIT_OK;\r
-            }\r
-\r
-            // if there is an error with the first selection, then force the\r
-            // dialog to open to give the user a chance to correct\r
-            force = true;\r
-\r
-            try {\r
-                // the operation will fail if the url is not a valid\r
-                // instance data area, so other checking is unneeded\r
-                if (instanceLoc.setURL(workspaceUrl, true)) {\r
-                    launchData.writePersistedData();\r
-                    writeWorkspaceVersion();\r
-                    return null;\r
-                }\r
-            } catch (IllegalStateException e) {\r
-                MessageDialog\r
-                .openError(\r
-                        shell,\r
-                        IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,\r
-                        IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);\r
-                return EXIT_OK;\r
-            }\r
-\r
-            // by this point it has been determined that the workspace is\r
-            // already in use -- force the user to choose again\r
-            MessageDialog.openError(shell, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle,\r
-                    IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage);\r
-        }\r
-    }\r
-\r
-    private static boolean isDevLaunchMode(Map<?,?> args) {\r
-        // see org.eclipse.pde.internal.core.PluginPathFinder.isDevLaunchMode()\r
-        if (Boolean.getBoolean("eclipse.pde.launch")) //$NON-NLS-1$\r
-            return true;\r
-        return args.containsKey("-pdelaunch"); //$NON-NLS-1$\r
-    }\r
-\r
-    /**\r
-     * Open a workspace selection dialog on the argument shell, populating the\r
-     * argument data with the user's selection. Perform first level validation\r
-     * on the selection by comparing the version information. This method does\r
-     * not examine the runtime state (e.g., is the workspace already locked?).\r
-     * \r
-     * @param shell\r
-     * @param launchData\r
-     * @param force\r
-     *            setting to true makes the dialog open regardless of the\r
-     *            showDialog value\r
-     * @return An URL storing the selected workspace or null if the user has\r
-     *         canceled the launch operation.\r
-     */\r
-    private URL promptForWorkspace(Shell shell, ChooseWorkspaceData launchData,\r
-            boolean force, boolean suppressAskAgain) {\r
-        URL url = null;\r
-        do {\r
-            // okay to use the shell now - this is the splash shell\r
-            new ChooseWorkspaceDialog(shell, launchData, suppressAskAgain, true).prompt(force);\r
-            String instancePath = launchData.getSelection();\r
-            if (instancePath == null) {\r
-                return null;\r
-            }\r
-\r
-            // the dialog is not forced on the first iteration, but is on every\r
-            // subsequent one -- if there was an error then the user needs to be\r
-            // allowed to fix it\r
-            force = true;\r
-\r
-            // 70576: don't accept empty input\r
-            if (instancePath.length() <= 0) {\r
-                MessageDialog\r
-                .openError(\r
-                        shell,\r
-                        IDEWorkbenchMessages.IDEApplication_workspaceEmptyTitle,\r
-                        IDEWorkbenchMessages.IDEApplication_workspaceEmptyMessage);\r
-                continue;\r
-            }\r
-\r
-            // create the workspace if it does not already exist\r
-            File workspace = new File(instancePath);\r
-            if (!workspace.exists()) {\r
-                workspace.mkdir();\r
-            }\r
-\r
-            try {\r
-                // Don't use File.toURL() since it adds a leading slash that Platform does not\r
-                // handle properly.  See bug 54081 for more details.\r
-                String path = workspace.getAbsolutePath().replace(\r
-                        File.separatorChar, '/');\r
-                url = new URL("file", null, path); //$NON-NLS-1$\r
-            } catch (MalformedURLException e) {\r
-                MessageDialog\r
-                .openError(\r
-                        shell,\r
-                        IDEWorkbenchMessages.IDEApplication_workspaceInvalidTitle,\r
-                        IDEWorkbenchMessages.IDEApplication_workspaceInvalidMessage);\r
-                continue;\r
-            }\r
-        } while (!checkValidWorkspace(shell, url));\r
-\r
-        return url;\r
-    }\r
-\r
-    /**\r
-     * Return true if the argument directory is ok to use as a workspace and\r
-     * false otherwise. A version check will be performed, and a confirmation\r
-     * box may be displayed on the argument shell if an older version is\r
-     * detected.\r
-     * \r
-     * @return true if the argument URL is ok to use as a workspace and false\r
-     *         otherwise.\r
-     */\r
-    private boolean checkValidWorkspace(Shell shell, URL url) {\r
-        // a null url is not a valid workspace\r
-        if (url == null) {\r
-            return false;\r
-        }\r
-\r
-        String version = readWorkspaceVersion(url);\r
-\r
-        // if the version could not be read, then there is not any existing\r
-        // workspace data to trample, e.g., perhaps its a new directory that\r
-        // is just starting to be used as a workspace\r
-        if (version == null) {\r
-            return true;\r
-        }\r
-\r
-        final int ide_version = Integer.parseInt(WORKSPACE_VERSION_VALUE);\r
-        int workspace_version = Integer.parseInt(version);\r
-\r
-        // equality test is required since any version difference (newer\r
-        // or older) may result in data being trampled\r
-        if (workspace_version == ide_version) {\r
-            return true;\r
-        }\r
-\r
-        // At this point workspace has been detected to be from a version\r
-        // other than the current ide version -- find out if the user wants\r
-        // to use it anyhow.\r
-               int severity;\r
-               String title;\r
-               String message;\r
-               if (workspace_version < ide_version) {\r
-                       // Workspace < IDE. Update must be possible without issues,\r
-                       // so only inform user about it.\r
-                       severity = MessageDialog.INFORMATION;\r
-                       title = IDEWorkbenchMessages.IDEApplication_versionTitle_olderWorkspace;\r
-                       message = NLS.bind(IDEWorkbenchMessages.IDEApplication_versionMessage_olderWorkspace, url.getFile());\r
-               } else {\r
-                       // Workspace > IDE. It must have been opened with a newer IDE version.\r
-                       // Downgrade might be problematic, so warn user about it.\r
-                       severity = MessageDialog.WARNING;\r
-                       title = IDEWorkbenchMessages.IDEApplication_versionTitle_newerWorkspace;\r
-                       message = NLS.bind(IDEWorkbenchMessages.IDEApplication_versionMessage_newerWorkspace, url.getFile());\r
-               }\r
-\r
-        MessageBox mbox = new MessageBox(shell, SWT.OK | SWT.CANCEL\r
-                | SWT.ICON_WARNING | SWT.APPLICATION_MODAL);\r
-        mbox.setText(title);\r
-        mbox.setMessage(message);\r
-        return mbox.open() == SWT.OK;\r
-    }\r
-\r
-    /**\r
-     * Look at the argument URL for the workspace's version information. Return\r
-     * that version if found and null otherwise.\r
-     */\r
-    private static String readWorkspaceVersion(URL workspace) {\r
-        File versionFile = getVersionFile(workspace, false);\r
-        if (versionFile == null || !versionFile.exists()) {\r
-            return null;\r
-        }\r
-\r
-        try {\r
-            // Although the version file is not spec'ed to be a Java properties\r
-            // file, it happens to follow the same format currently, so using\r
-            // Properties to read it is convenient.\r
-            Properties props = new Properties();\r
-            FileInputStream is = new FileInputStream(versionFile);\r
-            try {\r
-                props.load(is);\r
-            } finally {\r
-                is.close();\r
-            }\r
-\r
-            return props.getProperty(WORKSPACE_VERSION_KEY);\r
-        } catch (IOException e) {\r
-            IDEWorkbenchPlugin.log("Could not read version file", new Status( //$NON-NLS-1$\r
-                    IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH,\r
-                    IStatus.ERROR,\r
-                    e.getMessage() == null ? "" : e.getMessage(), //$NON-NLS-1$,\r
-                            e));\r
-            return null;\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Write the version of the metadata into a known file overwriting any\r
-     * existing file contents. Writing the version file isn't really crucial,\r
-     * so the function is silent about failure\r
-     */\r
-    private static void writeWorkspaceVersion() {\r
-        Location instanceLoc = Platform.getInstanceLocation();\r
-        if (instanceLoc == null || instanceLoc.isReadOnly()) {\r
-            return;\r
-        }\r
-\r
-        File versionFile = getVersionFile(instanceLoc.getURL(), true);\r
-        if (versionFile == null) {\r
-            return;\r
-        }\r
-\r
-        OutputStream output = null;\r
-        try {\r
-            String versionLine = WORKSPACE_VERSION_KEY + '='\r
-            + WORKSPACE_VERSION_VALUE;\r
-\r
-            output = new FileOutputStream(versionFile);\r
-            output.write(versionLine.getBytes("UTF-8")); //$NON-NLS-1$\r
-        } catch (IOException e) {\r
-            IDEWorkbenchPlugin.log("Could not write version file", //$NON-NLS-1$\r
-                    StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e));\r
-        } finally {\r
-            try {\r
-                if (output != null) {\r
-                    output.close();\r
-                }\r
-            } catch (IOException e) {\r
-                // do nothing\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * The version file is stored in the metadata area of the workspace. This\r
-     * method returns an URL to the file or null if the directory or file does\r
-     * not exist (and the create parameter is false).\r
-     * \r
-     * @param create\r
-     *            If the directory and file does not exist this parameter\r
-     *            controls whether it will be created.\r
-     * @return An url to the file or null if the version file does not exist or\r
-     *         could not be created.\r
-     */\r
-    private static File getVersionFile(URL workspaceUrl, boolean create) {\r
-        if (workspaceUrl == null) {\r
-            return null;\r
-        }\r
-\r
-        try {\r
-            // make sure the directory exists\r
-            File metaDir = new File(workspaceUrl.getPath(), METADATA_FOLDER);\r
-            if (!metaDir.exists() && (!create || !metaDir.mkdir())) {\r
-                return null;\r
-            }\r
-\r
-            // make sure the file exists\r
-            File versionFile = new File(metaDir, VERSION_FILENAME);\r
-            if (!versionFile.exists()\r
-                    && (!create || !versionFile.createNewFile())) {\r
-                return null;\r
-            }\r
-\r
-            return versionFile;\r
-        } catch (IOException e) {\r
-            // cannot log because instance area has not been set\r
-            return null;\r
-        }\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.equinox.app.IApplication#stop()\r
-     */\r
-    @Override\r
-    public void stop() {\r
-        final IWorkbench workbench = PlatformUI.getWorkbench();\r
-        if (workbench == null)\r
-            return;\r
-        final Display display = workbench.getDisplay();\r
-        display.syncExec(new Runnable() {\r
-            @Override\r
-            public void run() {\r
-                if (!display.isDisposed())\r
-                    workbench.close();\r
-            }\r
-        });\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * 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:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.workbench.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.service.datalocation.Location;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.ide.ChooseWorkspaceData;
+import org.eclipse.ui.internal.ide.ChooseWorkspaceDialog;
+import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
+import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
+import org.eclipse.ui.internal.ide.StatusUtil;
+import org.simantics.application.arguments.ApplicationUtils;
+import org.simantics.application.arguments.Arguments;
+import org.simantics.application.arguments.IArgumentFactory;
+import org.simantics.application.arguments.IArguments;
+import org.simantics.application.arguments.SimanticsArguments;
+import org.simantics.db.management.ISessionContextProvider;
+import org.simantics.db.management.ISessionContextProviderSource;
+import org.simantics.db.management.SessionContextProvider;
+import org.simantics.db.management.SingleSessionContextProviderSource;
+import org.simantics.ui.SimanticsUI;
+import org.simantics.utils.ui.BundleUtils;
+
+
+/**
+ * The "main program" for the Eclipse IDE.
+ * 
+ * @since 3.0
+ */
+public class SimanticsWorkbenchApplication implements IApplication, IExecutableExtension {
+
+    /**
+     * The name of the folder containing metadata information for the workspace.
+     */
+    public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$
+
+    private static final String VERSION_FILENAME = "version.ini"; //$NON-NLS-1$
+
+    private static final String WORKSPACE_VERSION_KEY = "org.eclipse.core.runtime"; //$NON-NLS-1$
+
+    private static final String WORKSPACE_VERSION_VALUE = "1"; //$NON-NLS-1$
+
+    private static final String PROP_EXIT_CODE = "eclipse.exitcode"; //$NON-NLS-1$
+
+    /**
+     * A special return code that will be recognized by the launcher and used to
+     * restart the workbench.
+     */
+    private static final Integer EXIT_RELAUNCH = new Integer(24);
+
+    /**
+     * A special return code that will be recognized by the PDE launcher and used to
+     * show an error dialog if the workspace is locked.
+     */
+    private static final Integer EXIT_WORKSPACE_LOCKED = new Integer(15);
+
+    /**
+     * Creates a new IDE application.
+     */
+    public SimanticsWorkbenchApplication() {
+        // There is nothing to do for WorkbenchApplication
+    }
+
+    public WorkbenchAdvisor createWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) {
+        return new SimanticsWorkbenchAdvisor(args, processor);
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext context)
+     */
+    @Override
+    public Object start(IApplicationContext appContext) throws Exception {
+        ApplicationUtils.loadSystemProperties(BundleUtils.find(Activator.PLUGIN_ID, "system.properties"));
+        IArguments args = parseArguments((String[]) appContext.getArguments().get(IApplicationContext.APPLICATION_ARGS));
+
+        Display display = createDisplay();
+        // processor must be created before we start event loop
+        DelayedEventsProcessor processor = new DelayedEventsProcessor(display);
+
+        try {
+            Object argCheck = verifyArguments(args);
+            if (argCheck != null)
+                return argCheck;
+
+            // look and see if there's a splash shell we can parent off of
+            Shell shell = WorkbenchPlugin.getSplashShell(display);
+            if (shell != null) {
+                // should should set the icon and message for this shell to be the 
+                // same as the chooser dialog - this will be the guy that lives in
+                // the task bar and without these calls you'd have the default icon 
+                // with no message.
+                shell.setText(ChooseWorkspaceDialog.getWindowTitle());
+                shell.setImages(Dialog.getDefaultImages());
+            }
+
+            Object instanceLocationCheck = checkInstanceLocation(shell, appContext.getArguments(), args);
+            if (instanceLocationCheck != null) {
+                WorkbenchPlugin.unsetSplashShell(display);
+                Platform.endSplash();
+                return instanceLocationCheck;
+            }
+
+            final ISessionContextProvider provider = new SessionContextProvider(null);
+            final ISessionContextProviderSource contextProviderSource = new SingleSessionContextProviderSource(provider);
+            //final ISessionContextProviderSource contextProviderSource = new WorkbenchWindowSessionContextProviderSource(PlatformUI.getWorkbench());
+            SimanticsUI.setSessionContextProviderSource(contextProviderSource);
+            org.simantics.db.layer0.internal.SimanticsInternal.setSessionContextProviderSource(contextProviderSource);
+            org.simantics.Simantics.setSessionContextProviderSource(contextProviderSource);
+            
+            // create the workbench with this advisor and run it until it exits
+            // N.B. createWorkbench remembers the advisor, and also registers
+            // the workbench globally so that all UI plug-ins can find it using
+            // PlatformUI.getWorkbench() or AbstractUIPlugin.getWorkbench()
+            int returnCode = PlatformUI.createAndRunWorkbench(display,
+                    createWorkbenchAdvisor(args, processor));
+
+            // the workbench doesn't support relaunch yet (bug 61809) so
+            // for now restart is used, and exit data properties are checked
+            // here to substitute in the relaunch return code if needed
+            if (returnCode != PlatformUI.RETURN_RESTART) {
+                return EXIT_OK;
+            }
+
+            // if the exit code property has been set to the relaunch code, then
+            // return that code now, otherwise this is a normal restart
+            return EXIT_RELAUNCH.equals(Integer.getInteger(PROP_EXIT_CODE)) ? EXIT_RELAUNCH
+                    : EXIT_RESTART;
+        } finally {
+            if (display != null) {
+                display.dispose();
+            }
+            Location instanceLoc = Platform.getInstanceLocation();
+            if (instanceLoc != null)
+                instanceLoc.release();
+        }
+    }
+
+    /*************************************************************************/
+
+    private IArguments parseArguments(String[] args) {
+        IArgumentFactory<?>[] accepted = {
+                SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS,
+                SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL,
+                SimanticsArguments.DEFAULT_WORKSPACE_LOCATION,
+                SimanticsArguments.WORKSPACE_CHOOSER,
+                SimanticsArguments.WORKSPACE_NO_REMEMBER,
+                SimanticsArguments.PERSPECTIVE,
+                SimanticsArguments.SERVER,
+                SimanticsArguments.NEW_MODEL,
+                SimanticsArguments.EXPERIMENT,
+                SimanticsArguments.DISABLE_INDEX,
+                SimanticsArguments.DATABASE_ID,
+        };
+        IArguments result = Arguments.parse(args, accepted);
+        return result;
+    }
+
+    private Object verifyArguments(IArguments args) {
+        StringBuilder report = new StringBuilder();
+
+//        if (args.contains(SimanticsArguments.NEW_PROJECT)) {
+//            if (args.contains(SimanticsArguments.PROJECT)) {
+//                exclusiveArguments(report, SimanticsArguments.PROJECT, SimanticsArguments.NEW_PROJECT);
+//            }
+//            // Must have a server to checkout from when creating a new
+//            // project right from the beginning.
+//            if (!args.contains(SimanticsArguments.SERVER)) {
+//                missingArgument(report, SimanticsArguments.SERVER);
+//            }
+//        } else if (args.contains(SimanticsArguments.PROJECT)) {
+//            // To load a project, a server must be defined to checkout from
+//            if (!args.contains(SimanticsArguments.SERVER)) {
+//                missingArgument(report, SimanticsArguments.SERVER);
+//            }
+//        }
+
+        // NEW_MODEL and MODEL arguments are optional
+        // EXPERIMENT argument is optional
+
+        String result = report.toString();
+        boolean valid = result.length() == 0;
+
+        if (!valid) {
+            String msg = NLS.bind(Messages.Application_1, result);
+            MessageDialog.openInformation(null, Messages.Application_2, msg);
+        }
+        return valid ? null : EXIT_OK;
+    }
+
+//    private void exclusiveArguments(StringBuilder sb, IArgumentFactory<?> arg1, IArgumentFactory<?> arg2) {
+//        sb.append(NLS.bind(Messages.Application_3, arg1.getArgument(), arg2.getArgument()));
+//        sb.append('\n');
+//    }
+//
+//    private void missingArgument(StringBuilder sb, IArgumentFactory<?> arg) {
+//        sb.append(NLS.bind(Messages.Application_0, arg.getArgument()));
+//        sb.append('\n');
+//    }
+
+    /*************************************************************************/
+
+    /**
+     * Creates the display used by the application.
+     * 
+     * @return the display used by the application
+     */
+    protected Display createDisplay() {
+        return PlatformUI.createDisplay();
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)
+     */
+    @Override
+    public void setInitializationData(IConfigurationElement config,
+            String propertyName, Object data) {
+        // There is nothing to do for ProConfApplication
+    }
+
+    /**
+     * Return true if a valid workspace path has been set and false otherwise.
+     * Prompt for and set the path if possible and required.
+     * @param applicationArguments 
+     * 
+     * @return true if a valid instance location has been set and false
+     *         otherwise
+     */
+    private Object checkInstanceLocation(Shell shell, Map<?,?> applicationArguments, IArguments args) {
+        // -data @none was specified but an ide requires workspace
+        Location instanceLoc = Platform.getInstanceLocation();
+        if (instanceLoc == null) {
+            MessageDialog
+            .openError(
+                    shell,
+                    IDEWorkbenchMessages.IDEApplication_workspaceMandatoryTitle,
+                    IDEWorkbenchMessages.IDEApplication_workspaceMandatoryMessage);
+            return EXIT_OK;
+        }
+
+        // -data "/valid/path", workspace already set
+        // This information is stored in configuration/.settings/org.eclipse.ui.ide.prefs
+        if (instanceLoc.isSet()) {
+            // make sure the meta data version is compatible (or the user has
+            // chosen to overwrite it).
+            if (!checkValidWorkspace(shell, instanceLoc.getURL())) {
+                return EXIT_OK;
+            }
+
+            // at this point its valid, so try to lock it and update the
+            // metadata version information if successful
+            try {
+                if (instanceLoc.lock()) {
+                    writeWorkspaceVersion();
+                    return null;
+                }
+
+                // we failed to create the directory.
+                // Two possibilities:
+                // 1. directory is already in use
+                // 2. directory could not be created
+                File workspaceDirectory = new File(instanceLoc.getURL().getFile());
+                if (workspaceDirectory.exists()) {
+                    if (isDevLaunchMode(applicationArguments)) {
+                        return EXIT_WORKSPACE_LOCKED;
+                    }
+                    MessageDialog.openError(
+                            shell,
+                            IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle,
+                            IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage);
+                } else {
+                    MessageDialog.openError(
+                            shell,
+                            IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,
+                            IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);
+                }
+            } catch (IOException e) {
+                IDEWorkbenchPlugin.log("Could not obtain lock for workspace location", //$NON-NLS-1$
+                        e);
+                MessageDialog
+                .openError(
+                        shell,
+                        IDEWorkbenchMessages.InternalError,
+                        e.getMessage());
+            }
+            return EXIT_OK;
+        }
+
+        // -data @noDefault or -data not specified, prompt and set
+        ChooseWorkspaceData launchData = null;
+        if (args.contains(SimanticsArguments.DEFAULT_WORKSPACE_LOCATION)) {
+            launchData = new ChooseWorkspaceData(args.get(SimanticsArguments.DEFAULT_WORKSPACE_LOCATION));
+        } else {
+            launchData = new ChooseWorkspaceData(instanceLoc.getDefault());
+        }
+
+        boolean force = args.contains(SimanticsArguments.WORKSPACE_CHOOSER);
+        boolean suppressAskAgain = args.contains(SimanticsArguments.WORKSPACE_NO_REMEMBER);
+
+        while (true) {
+            URL workspaceUrl = promptForWorkspace(shell, launchData, force, suppressAskAgain);
+            if (workspaceUrl == null) {
+                return EXIT_OK;
+            }
+
+            // if there is an error with the first selection, then force the
+            // dialog to open to give the user a chance to correct
+            force = true;
+
+            try {
+                // the operation will fail if the url is not a valid
+                // instance data area, so other checking is unneeded
+                if (instanceLoc.setURL(workspaceUrl, true)) {
+                    launchData.writePersistedData();
+                    writeWorkspaceVersion();
+                    return null;
+                }
+            } catch (IllegalStateException e) {
+                MessageDialog
+                .openError(
+                        shell,
+                        IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,
+                        IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);
+                return EXIT_OK;
+            }
+
+            // by this point it has been determined that the workspace is
+            // already in use -- force the user to choose again
+            MessageDialog.openError(shell, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle,
+                    IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage);
+        }
+    }
+
+    private static boolean isDevLaunchMode(Map<?,?> args) {
+        // see org.eclipse.pde.internal.core.PluginPathFinder.isDevLaunchMode()
+        if (Boolean.getBoolean("eclipse.pde.launch")) //$NON-NLS-1$
+            return true;
+        return args.containsKey("-pdelaunch"); //$NON-NLS-1$
+    }
+
+    /**
+     * Open a workspace selection dialog on the argument shell, populating the
+     * argument data with the user's selection. Perform first level validation
+     * on the selection by comparing the version information. This method does
+     * not examine the runtime state (e.g., is the workspace already locked?).
+     * 
+     * @param shell
+     * @param launchData
+     * @param force
+     *            setting to true makes the dialog open regardless of the
+     *            showDialog value
+     * @return An URL storing the selected workspace or null if the user has
+     *         canceled the launch operation.
+     */
+    private URL promptForWorkspace(Shell shell, ChooseWorkspaceData launchData,
+            boolean force, boolean suppressAskAgain) {
+        URL url = null;
+        do {
+            // okay to use the shell now - this is the splash shell
+            new ChooseWorkspaceDialog(shell, launchData, suppressAskAgain, true).prompt(force);
+            String instancePath = launchData.getSelection();
+            if (instancePath == null) {
+                return null;
+            }
+
+            // the dialog is not forced on the first iteration, but is on every
+            // subsequent one -- if there was an error then the user needs to be
+            // allowed to fix it
+            force = true;
+
+            // 70576: don't accept empty input
+            if (instancePath.length() <= 0) {
+                MessageDialog
+                .openError(
+                        shell,
+                        IDEWorkbenchMessages.IDEApplication_workspaceEmptyTitle,
+                        IDEWorkbenchMessages.IDEApplication_workspaceEmptyMessage);
+                continue;
+            }
+
+            // create the workspace if it does not already exist
+            File workspace = new File(instancePath);
+            if (!workspace.exists()) {
+                workspace.mkdir();
+            }
+
+            try {
+                // Don't use File.toURL() since it adds a leading slash that Platform does not
+                // handle properly.  See bug 54081 for more details.
+                String path = workspace.getAbsolutePath().replace(
+                        File.separatorChar, '/');
+                url = new URL("file", null, path); //$NON-NLS-1$
+            } catch (MalformedURLException e) {
+                MessageDialog
+                .openError(
+                        shell,
+                        IDEWorkbenchMessages.IDEApplication_workspaceInvalidTitle,
+                        IDEWorkbenchMessages.IDEApplication_workspaceInvalidMessage);
+                continue;
+            }
+        } while (!checkValidWorkspace(shell, url));
+
+        return url;
+    }
+
+    /**
+     * Return true if the argument directory is ok to use as a workspace and
+     * false otherwise. A version check will be performed, and a confirmation
+     * box may be displayed on the argument shell if an older version is
+     * detected.
+     * 
+     * @return true if the argument URL is ok to use as a workspace and false
+     *         otherwise.
+     */
+    private boolean checkValidWorkspace(Shell shell, URL url) {
+        // a null url is not a valid workspace
+        if (url == null) {
+            return false;
+        }
+
+        String version = readWorkspaceVersion(url);
+
+        // if the version could not be read, then there is not any existing
+        // workspace data to trample, e.g., perhaps its a new directory that
+        // is just starting to be used as a workspace
+        if (version == null) {
+            return true;
+        }
+
+        final int ide_version = Integer.parseInt(WORKSPACE_VERSION_VALUE);
+        int workspace_version = Integer.parseInt(version);
+
+        // equality test is required since any version difference (newer
+        // or older) may result in data being trampled
+        if (workspace_version == ide_version) {
+            return true;
+        }
+
+        // At this point workspace has been detected to be from a version
+        // other than the current ide version -- find out if the user wants
+        // to use it anyhow.
+               int severity;
+               String title;
+               String message;
+               if (workspace_version < ide_version) {
+                       // Workspace < IDE. Update must be possible without issues,
+                       // so only inform user about it.
+                       severity = MessageDialog.INFORMATION;
+                       title = IDEWorkbenchMessages.IDEApplication_versionTitle_olderWorkspace;
+                       message = NLS.bind(IDEWorkbenchMessages.IDEApplication_versionMessage_olderWorkspace, url.getFile());
+               } else {
+                       // Workspace > IDE. It must have been opened with a newer IDE version.
+                       // Downgrade might be problematic, so warn user about it.
+                       severity = MessageDialog.WARNING;
+                       title = IDEWorkbenchMessages.IDEApplication_versionTitle_newerWorkspace;
+                       message = NLS.bind(IDEWorkbenchMessages.IDEApplication_versionMessage_newerWorkspace, url.getFile());
+               }
+
+        MessageBox mbox = new MessageBox(shell, SWT.OK | SWT.CANCEL
+                | SWT.ICON_WARNING | SWT.APPLICATION_MODAL);
+        mbox.setText(title);
+        mbox.setMessage(message);
+        return mbox.open() == SWT.OK;
+    }
+
+    /**
+     * Look at the argument URL for the workspace's version information. Return
+     * that version if found and null otherwise.
+     */
+    private static String readWorkspaceVersion(URL workspace) {
+        File versionFile = getVersionFile(workspace, false);
+        if (versionFile == null || !versionFile.exists()) {
+            return null;
+        }
+
+        try {
+            // Although the version file is not spec'ed to be a Java properties
+            // file, it happens to follow the same format currently, so using
+            // Properties to read it is convenient.
+            Properties props = new Properties();
+            FileInputStream is = new FileInputStream(versionFile);
+            try {
+                props.load(is);
+            } finally {
+                is.close();
+            }
+
+            return props.getProperty(WORKSPACE_VERSION_KEY);
+        } catch (IOException e) {
+            IDEWorkbenchPlugin.log("Could not read version file", new Status( //$NON-NLS-1$
+                    IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH,
+                    IStatus.ERROR,
+                    e.getMessage() == null ? "" : e.getMessage(), //$NON-NLS-1$,
+                            e));
+            return null;
+        }
+    }
+
+    /**
+     * Write the version of the metadata into a known file overwriting any
+     * existing file contents. Writing the version file isn't really crucial,
+     * so the function is silent about failure
+     */
+    private static void writeWorkspaceVersion() {
+        Location instanceLoc = Platform.getInstanceLocation();
+        if (instanceLoc == null || instanceLoc.isReadOnly()) {
+            return;
+        }
+
+        File versionFile = getVersionFile(instanceLoc.getURL(), true);
+        if (versionFile == null) {
+            return;
+        }
+
+        OutputStream output = null;
+        try {
+            String versionLine = WORKSPACE_VERSION_KEY + '='
+            + WORKSPACE_VERSION_VALUE;
+
+            output = new FileOutputStream(versionFile);
+            output.write(versionLine.getBytes("UTF-8")); //$NON-NLS-1$
+        } catch (IOException e) {
+            IDEWorkbenchPlugin.log("Could not write version file", //$NON-NLS-1$
+                    StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e));
+        } finally {
+            try {
+                if (output != null) {
+                    output.close();
+                }
+            } catch (IOException e) {
+                // do nothing
+            }
+        }
+    }
+
+    /**
+     * The version file is stored in the metadata area of the workspace. This
+     * method returns an URL to the file or null if the directory or file does
+     * not exist (and the create parameter is false).
+     * 
+     * @param create
+     *            If the directory and file does not exist this parameter
+     *            controls whether it will be created.
+     * @return An url to the file or null if the version file does not exist or
+     *         could not be created.
+     */
+    private static File getVersionFile(URL workspaceUrl, boolean create) {
+        if (workspaceUrl == null) {
+            return null;
+        }
+
+        try {
+            // make sure the directory exists
+            File metaDir = new File(workspaceUrl.getPath(), METADATA_FOLDER);
+            if (!metaDir.exists() && (!create || !metaDir.mkdir())) {
+                return null;
+            }
+
+            // make sure the file exists
+            File versionFile = new File(metaDir, VERSION_FILENAME);
+            if (!versionFile.exists()
+                    && (!create || !versionFile.createNewFile())) {
+                return null;
+            }
+
+            return versionFile;
+        } catch (IOException e) {
+            // cannot log because instance area has not been set
+            return null;
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.equinox.app.IApplication#stop()
+     */
+    @Override
+    public void stop() {
+        final IWorkbench workbench = PlatformUI.getWorkbench();
+        if (workbench == null)
+            return;
+        final Display display = workbench.getDisplay();
+        display.syncExec(new Runnable() {
+            @Override
+            public void run() {
+                if (!display.isDisposed())
+                    workbench.close();
+            }
+        });
+    }
+
+}
index 5cd86db54f43ec0302ddec108f6b40a09d664ddd..d5f1ee27a3d847dee1c860fe1c739ddb96175858 100644 (file)
@@ -19,7 +19,10 @@ Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
  org.simantics.scl.osgi;bundle-version="1.0.4",
  org.simantics.scl.compiler;bundle-version="0.4.0",
  org.simantics.platform.ui.ontology;bundle-version="1.0.0",
  org.simantics.scl.osgi;bundle-version="1.0.4",
  org.simantics.scl.compiler;bundle-version="0.4.0",
  org.simantics.platform.ui.ontology;bundle-version="1.0.0",
- org.simantics.db.procore;bundle-version="1.1.0"
+ org.simantics.db.procore;bundle-version="1.1.0",
+ org.slf4j.api,
+ ch.qos.logback.classic,
+ ch.qos.logback.core
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ActivationPolicy: lazy
 Export-Package: org.simantics,
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ActivationPolicy: lazy
 Export-Package: org.simantics,
index 1754b00715bd2b6a6669479174845ee4ccb1d1cb..d59fff9c2fa85de2ef1afb2eab3e18bbd8a16f12 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics;\r
-\r
-import static org.simantics.db.common.utils.Transaction.commit;\r
-import static org.simantics.db.common.utils.Transaction.endTransaction;\r
-import static org.simantics.db.common.utils.Transaction.readGraph;\r
-import static org.simantics.db.common.utils.Transaction.startTransaction;\r
-import static org.simantics.db.common.utils.Transaction.writeGraph;\r
-\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Map.Entry;\r
-import java.util.Properties;\r
-import java.util.Set;\r
-import java.util.TreeMap;\r
-import java.util.UUID;\r
-\r
-import org.eclipse.core.runtime.ILog;\r
-import org.eclipse.core.runtime.IProduct;\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.core.runtime.IStatus;\r
-import org.eclipse.core.runtime.NullProgressMonitor;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.eclipse.core.runtime.Status;\r
-import org.eclipse.core.runtime.SubMonitor;\r
-import org.eclipse.osgi.service.resolver.BundleDescription;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.Databoard;\r
-import org.simantics.datatypes.literal.Font;\r
-import org.simantics.datatypes.literal.RGB;\r
-import org.simantics.db.Driver;\r
-import org.simantics.db.Driver.Management;\r
-import org.simantics.db.Manager;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.SessionModel;\r
-import org.simantics.db.UndoContext;\r
-import org.simantics.db.VirtualGraph;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.request.ObjectsWithType;\r
-import org.simantics.db.common.request.Queries;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.common.request.WriteResultRequest;\r
-import org.simantics.db.common.utils.Transaction;\r
-import org.simantics.db.exception.ClusterSetExistException;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ResourceNotFoundException;\r
-import org.simantics.db.indexing.DatabaseIndexing;\r
-import org.simantics.db.layer0.genericrelation.DependenciesRelation;\r
-import org.simantics.db.layer0.util.SimanticsClipboardImpl;\r
-import org.simantics.db.layer0.util.SimanticsKeys;\r
-import org.simantics.db.layer0.util.TGTransferableGraphSource;\r
-import org.simantics.db.layer0.variable.VariableRepository;\r
-import org.simantics.db.management.SessionContext;\r
-import org.simantics.db.request.Read;\r
-import org.simantics.db.service.LifecycleSupport.LifecycleListener;\r
-import org.simantics.db.service.LifecycleSupport.LifecycleState;\r
-import org.simantics.db.service.QueryControl;\r
-import org.simantics.db.service.UndoRedoSupport;\r
-import org.simantics.db.service.VirtualGraphSupport;\r
-import org.simantics.db.service.XSupport;\r
-import org.simantics.graph.db.GraphDependencyAnalyzer;\r
-import org.simantics.graph.db.GraphDependencyAnalyzer.IU;\r
-import org.simantics.graph.db.GraphDependencyAnalyzer.IdentityNode;\r
-import org.simantics.graph.db.IImportAdvisor;\r
-import org.simantics.graph.db.TransferableGraphs;\r
-import org.simantics.graph.diff.Diff;\r
-import org.simantics.graph.diff.TransferableGraphDelta1;\r
-import org.simantics.internal.Activator;\r
-import org.simantics.internal.startup.StartupExtensions;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.operation.Layer0X;\r
-import org.simantics.project.IProject;\r
-import org.simantics.project.ProjectFeatures;\r
-import org.simantics.project.ProjectKeys;\r
-import org.simantics.project.Projects;\r
-import org.simantics.project.exception.ProjectException;\r
-import org.simantics.project.features.registry.GroupReference;\r
-import org.simantics.project.management.DatabaseManagement;\r
-import org.simantics.project.management.GraphBundle;\r
-import org.simantics.project.management.GraphBundleEx;\r
-import org.simantics.project.management.GraphBundleRef;\r
-import org.simantics.project.management.PlatformUtil;\r
-import org.simantics.project.management.ServerManager;\r
-import org.simantics.project.management.ServerManagerFactory;\r
-import org.simantics.project.management.WorkspaceUtil;\r
-import org.simantics.utils.FileUtils;\r
-import org.simantics.utils.datastructures.Pair;\r
-import org.simantics.utils.logging.TimeLogger;\r
-\r
-/**\r
- * SimanticsPlatform performs procedures required in order to get simantics\r
- * workbench into operational state. This consists of the following steps:\r
- * <ul>\r
- *     <li> Asserting there is Database\r
- *     </li>\r
- *     <li> Starting Database process\r
- *     </li>\r
- *     <li> Opening a session to Database process\r
- *     </li>\r
- *     <li> Asserting required ontologies or other transferable graphs are installed in the database\r
- *     </li>\r
- *     <li> Asserting required project is installed in the database\r
- *     </li>\r
- *     <li> Asserting Simantics Features are installed in the database\r
- *     </li>\r
- *     <li> Asserting Simantics Features are installed to the project\r
- *     </li>\r
- *     <li> Shutdown: Save Session, Close session, Kill Database process\r
- *     </li>\r
- * </ul>\r
- *\r
- * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
- */\r
-public class SimanticsPlatform implements LifecycleListener {\r
-\r
-    /**\r
-     * The policy is relevant when developing Simantics from Eclipse IDE.\r
-     * It is applied when the ontology in the database of a workspace doesn't match\r
-     * a newer ontology in the Eclipse workspace.\r
-     */\r
-    public static enum OntologyRecoveryPolicy { ThrowError, Merge, ReinstallDatabase }\r
-\r
-    /**\r
-     * This policy dictates how the Simantics platform startup should react if\r
-     * the started workspace is not set up properly. The alternatives are to\r
-     * just throw an error and fail or to attempt all possible measures to fix\r
-     * the encountered problems.\r
-     */\r
-    public static enum RecoveryPolicy { ThrowError, FixError }\r
-\r
-    /** Singleton instance, started in SimanticsWorkbenchAdvisor */\r
-    public static final SimanticsPlatform INSTANCE = new SimanticsPlatform();\r
-\r
-    /** Set to true when the Simantics Platform is in good-and-go condition */\r
-    public boolean running;\r
-\r
-    /** Database Session */\r
-    public Session session;\r
-    private Management databasebManagement;\r
-\r
-    /** Database session context */\r
-    public SessionContext sessionContext;\r
-\r
-    /** Project identifier in Database */\r
-    public String projectURI;\r
-\r
-    /** Project name */\r
-    public String projectName;\r
-\r
-    /** Project resource */\r
-    public Resource projectResource;\r
-\r
-    /** Session specific bindings */\r
-    public SimanticsBindings simanticsBindings;\r
-    public SimanticsBindings simanticsBindings2;\r
-\r
-    public Thread mainThread;\r
-\r
-    /**\r
-     * The {@link IProject} activated by\r
-     * {@link #startUp(IProgressMonitor, RecoveryPolicy, OntologyRecoveryPolicy, ServerAddress, PlatformUserAgent)}\r
-     */\r
-    private IProject project;\r
-\r
-    protected ILog log;\r
-\r
-    /**\r
-     * Create a new simantics plaform manager in uninitialized state and\r
-     * with default policies. <p>\r
-     */\r
-    public SimanticsPlatform() {\r
-        log = Platform.getLog(Activator.getBundleContext().getBundle());\r
-        mainThread = Thread.currentThread();\r
-    }\r
-\r
-    public String getApplicationClientId() {\r
-        IProduct product = Platform.getProduct();\r
-        if(product == null) return "noProduct";//UUID.randomUUID().toString();\r
-        String application = product.getApplication();\r
-        return application != null ? application : UUID.randomUUID().toString();\r
-    }\r
-\r
-    private Session setupDatabase(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, PlatformUserAgent userAgent) throws PlatformException {\r
-        if (progressMonitor == null)\r
-            progressMonitor = new NullProgressMonitor();\r
-        File dbLocation = Platform.getLocation().append("db").toFile();\r
-        ServerManager serverManager;\r
-        try {\r
-            serverManager = ServerManagerFactory.create(databaseDriverId, dbLocation.getAbsolutePath());\r
-        } catch (DatabaseException | IOException e) {\r
-            throw new PlatformException("Failed to initialize Server Manager", e);\r
-        }\r
-        progressMonitor.beginTask("Setting up Simantics Database", 100);\r
-        progressMonitor.setTaskName("Asserting Database is installed.");\r
-        String msg = "Failed to initialize Simantics database.";\r
-        try {\r
-            // Create database\r
-            log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Creating database at " + dbLocation));\r
-            progressMonitor.setTaskName("Creating database at " + dbLocation);\r
-            databasebManagement = serverManager.getManagement(dbLocation);\r
-            databasebManagement.create();\r
-            // Create layer0.\r
-            return serverManager.createDatabase(dbLocation);\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException(msg, e);\r
-        } catch (Throwable e) {\r
-            throw new PlatformException(msg, e);\r
-        } finally {\r
-            progressMonitor.worked(20);\r
-        }\r
-    }\r
-\r
-    public void synchronizeOntologies(IProgressMonitor progressMonitor, OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize) throws PlatformException {\r
-\r
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();\r
-\r
-        final DatabaseManagement mgmt = new DatabaseManagement();\r
-\r
-        PlatformUtil.compileAllDynamicOntologies();\r
-\r
-        progressMonitor.setTaskName("Asserting all ontologies are installed");\r
-        final Map<GraphBundleRef, GraphBundleEx> platformTGs = new HashMap<GraphBundleRef, GraphBundleEx>();\r
-        try {\r
-\r
-            // Get a list of bundles installed into the database\r
-            progressMonitor.subTask("find installed bundles from database");\r
-            Map<GraphBundleRef, GraphBundleEx> installedTGs = new HashMap<GraphBundleRef, GraphBundleEx>();\r
-            for (GraphBundle b : session.syncRequest( mgmt.GraphBundleQuery )) {\r
-                installedTGs.put(GraphBundleRef.of(b), GraphBundleEx.extend(b));\r
-            }\r
-\r
-            if(!requireSynchronize && installedTGs.size() > 1 && !Platform.inDevelopmentMode()) return;\r
-//            if(installedTGs.size() > 1) return;\r
-\r
-            // Get a list of all bundles in the platform (Bundle Context)\r
-            List<GraphBundle> tgs = new ArrayList<GraphBundle>();\r
-            progressMonitor.subTask("load all transferable graphs from platform");\r
-            PlatformUtil.getAllGraphs(tgs);\r
-            progressMonitor.subTask("extend bundles to compile versions");\r
-            for (GraphBundle b : tgs) {\r
-                GraphBundleEx gbe = GraphBundleEx.extend(b);\r
-                gbe.build();\r
-                platformTGs.put(GraphBundleRef.of(b), gbe);\r
-            }\r
-\r
-            // Compile a list of TGs that need to be installed or reinstalled in the database\r
-            progressMonitor.subTask("check bundle reinstallation demand");\r
-            List<GraphBundleEx> installTGs = new ArrayList<GraphBundleEx>();\r
-            // Create list of TGs to update, <newTg, oldTg>\r
-            Map<GraphBundleEx,GraphBundleEx> reinstallTGs = new TreeMap<GraphBundleEx,GraphBundleEx>();\r
-            for (Entry<GraphBundleRef, GraphBundleEx> e : platformTGs.entrySet()) {\r
-                GraphBundleRef key = e.getKey();\r
-                GraphBundleEx platformBundle = e.getValue();\r
-                GraphBundleEx existingBundle = installedTGs.get(key);\r
-                \r
-//                System.out.println("GraphBundleRef key=" + key.toString());\r
-                \r
-                if (existingBundle == null) {\r
-                    // Bundle did not exist in the database, put it into list of bundles to install\r
-                    installTGs.add(platformBundle);\r
-                }\r
-                else {\r
-                    // Bundle exists in the database\r
-                    boolean platformBundleIsNewer = existingBundle.getVersion().compareTo(platformBundle.getVersion())<0;\r
-                    if (!platformBundleIsNewer)\r
-                        continue;\r
-                    // Check hash of transferable graph to know whether to update or not.\r
-                    if (platformBundle.getHashcode() == existingBundle.getHashcode())\r
-                        continue;\r
-                    //System.out.println("Ontology hashcodes do not match: platform bundle="\r
-                    //        + platformBundle.getVersionedId() + ", hash=" + platformBundle.getHashcode()\r
-                    //        + "; existing bundle=" + existingBundle.getVersionedId() + ", hash=" + existingBundle.getHashcode());\r
-                    reinstallTGs.put(platformBundle, existingBundle);\r
-                }\r
-            }\r
-            // INSTALL\r
-            // Database is missing graphs\r
-            if (!installTGs.isEmpty() || !reinstallTGs.isEmpty()) {\r
-                session.getService(XSupport.class).setServiceMode(true, true);\r
-\r
-                // Throw error\r
-                if (ontologyPolicy == OntologyRecoveryPolicy.ThrowError) {\r
-                    StringBuilder sb = new StringBuilder("The following graphs are not installed in the database: ");\r
-                    if (!installTGs.isEmpty()) {\r
-                        int i = 0;\r
-                        for (GraphBundleEx e : installTGs) {\r
-                            if (i>0) sb.append(", ");\r
-                            i++;\r
-                            sb.append(e.toString());\r
-                        }\r
-                        sb.append(" is missing from the database.\n");\r
-                    }\r
-                    if (!reinstallTGs.isEmpty()) {\r
-                        int i = 0;\r
-                        for (Entry<GraphBundleEx, GraphBundleEx> e : reinstallTGs.entrySet()) {\r
-                            if (i>0) sb.append(", ");\r
-                            i++;\r
-                            sb.append(e.getKey().toString());\r
-                        }\r
-                        sb.append(" Database/Platform Bundle version mismatch.\n");\r
-                    }\r
-                    sb.append("Hint: Use -fixErrors to install the graphs.");\r
-                    throw new PlatformException(sb.toString());\r
-                }\r
-                // Reinstall database\r
-                if (ontologyPolicy == OntologyRecoveryPolicy.ReinstallDatabase) {\r
-                    log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Reinstalling the database."));\r
-                    // TODO Install DB\r
-                    // Stop Session\r
-                    // Kill Process\r
-                    // Delete Database\r
-                    // Create Database\r
-                    // Start Database\r
-                    // Open Session\r
-                    // Install TGs\r
-                    throw new PlatformException("Reinstalling Database, NOT IMPLEMENTED");\r
-                }\r
-\r
-                if (ontologyPolicy == OntologyRecoveryPolicy.Merge) {\r
-                    progressMonitor.subTask("Merging ontology changes");\r
-                    // Sort missing TGs into install order\r
-                    GraphDependencyAnalyzer<GraphBundle> analyzer = new GraphDependencyAnalyzer<GraphBundle>();\r
-                    for(GraphBundle tg : installTGs) analyzer.addGraph(tg, tg.getGraph());\r
-                    for(GraphBundle tg : reinstallTGs.keySet()) analyzer.addGraph(tg, tg.getGraph());\r
-                    if(!analyzer.analyzeDependency()) {\r
-                        Collection<Pair<GraphBundle, GraphBundle>> problems = analyzer.getConflicts();\r
-                        StringBuilder sb = new StringBuilder();\r
-                        for (Pair<GraphBundle, GraphBundle> problem : problems) {\r
-                            sb.append("Conflict with "+problem.first+" and "+problem.second+".\n");\r
-                        }\r
-                        throw new PlatformException(sb.toString());\r
-                    }\r
-                    else if(!session.syncRequest( analyzer.queryExternalDependenciesSatisfied )) {\r
-                        Collection<IdentityNode> unsatisfiedDependencies = analyzer.getUnsatisfiedDependencies();\r
-                        StringBuilder sb = new StringBuilder();\r
-                        for (IdentityNode dep: unsatisfiedDependencies) {\r
-                            sb.append("Unsatisfied Dependency "+dep+". Required by\n");\r
-                            for(IU iu : GraphDependencyAnalyzer.toCollection(dep.getRequires())) {\r
-                                sb.append("    " + ((GraphBundle)iu.getId()).getId() + "\n");\r
-                            }\r
-                        }\r
-                        throw new PlatformException(sb.toString());\r
-                    }\r
-                    \r
-                    List<GraphBundle> sortedBundles = analyzer.getSortedGraphs();\r
-                    if(!sortedBundles.isEmpty()) {\r
-                       \r
-                        session.syncRequest(new WriteRequest() {\r
-                            @Override\r
-                            public void perform(WriteGraph graph) throws DatabaseException {\r
-                                try {\r
-                                    graph.newClusterSet(graph.getRootLibrary());\r
-                                } catch (ClusterSetExistException e) {\r
-                                    // Cluster set exist already, no problem.\r
-                                }\r
-                                graph.setClusterSet4NewResource(graph.getRootLibrary());\r
-                                graph.flushCluster();\r
-                            }\r
-                        });\r
-\r
-                        boolean mergedOntologies = false;\r
-\r
-                        // Install TGs\r
-                        for(final GraphBundle tg : sortedBundles) {\r
-\r
-                               final IImportAdvisor advisor = new OntologyImportAdvisor(tg, mgmt);\r
-                               final GraphBundle oldTG = reinstallTGs.get(tg);\r
-\r
-                               if (oldTG==null) {\r
-                                       \r
-                                       boolean createImmutable = tg.getImmutable();\r
-                                session.getService(XSupport.class).setServiceMode(true, createImmutable);\r
-\r
-                                       // Install TG\r
-                                       log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Installing "+tg.toString()+" - "+tg.getName()));\r
-                                       TransferableGraphs.importGraph1(session, new TGTransferableGraphSource(tg.getGraph()), advisor, null);\r
-                               } else {\r
-                                       // Merge TG\r
-                                       startTransaction(session, false);\r
-                                       TransferableGraphDelta1 delta = new Diff(oldTG.getGraph(), tg.getGraph()).diff();\r
-                                       final long[] oldResources = oldTG.getResourceArray();\r
-                                       boolean changes = TransferableGraphs.hasChanges(readGraph(), oldResources, delta);\r
-                                       endTransaction();\r
-                                       if (!changes) {\r
-                                           //log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Nothing to merge for "+tg.toString()));\r
-                                           continue;\r
-                                       }\r
-\r
-                                log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Merging new version of "+tg.toString()));\r
-\r
-                                       startTransaction(session, true);\r
-                                       \r
-                                       //delta.print();\r
-                                       try {\r
-                                               \r
-                                               \r
-                                               long[] resourceArray = TransferableGraphs.applyDelta(writeGraph(), oldResources, delta);\r
-                                               tg.setResourceArray(resourceArray);\r
-                                               mgmt.setGraphBundleEntry(tg);\r
-                                               commit();\r
-                                               mergedOntologies = true;\r
-                                       } catch (Throwable t) {\r
-                                               throw new PlatformException(t);\r
-                                       } finally {\r
-                                               endTransaction();\r
-                                       }\r
-                               }\r
-                        }\r
-                        \r
-                        session.syncRequest(new WriteRequest() {\r
-                            @Override\r
-                            public void perform(WriteGraph graph) throws DatabaseException {\r
-                                graph.setClusterSet4NewResource(graph.getRootLibrary());\r
-                                graph.flushCluster();\r
-                            }\r
-                        });\r
-\r
-                        if (mergedOntologies)\r
-                            DatabaseIndexing.deleteAllIndexes();\r
-                    }\r
-\r
-                    TimeLogger.log("Ontologies synchronized.");\r
-                    \r
-                }\r
-                session.getService(XSupport.class).setServiceMode(false, false);\r
-            }\r
-            progressMonitor.worked(20);\r
-        } catch (IOException e) {\r
-            throw new PlatformException(e);\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException(e);\r
-        }\r
-\r
-    }\r
-\r
-    public boolean assertConfiguration(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy) throws PlatformException {\r
-\r
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();\r
-\r
-        File workspaceLocation = Platform.getLocation().toFile();\r
-\r
-        boolean installProject = false;\r
-        progressMonitor.setTaskName("Asserting simantics.cfg is installed");\r
-        try {\r
-            File propertyFile = new File(workspaceLocation, "simantics.cfg");\r
-            Properties properties;\r
-            try {\r
-                properties = WorkspaceUtil.readProperties(propertyFile);\r
-            } catch (IOException e) {\r
-                if (workspacePolicy == RecoveryPolicy.ThrowError) throw new PlatformException("Could not load "+propertyFile);\r
-\r
-                // Create a project and write Property file\r
-                properties = new Properties();\r
-                properties.setProperty("project_uri", "http://Projects/Development%20Project");\r
-                properties.setProperty("project_name", "Development Project");\r
-                WorkspaceUtil.writeProperties(propertyFile, properties);\r
-                installProject |= true;\r
-            }\r
-            projectURI = properties.getProperty("project_uri");\r
-            projectName = properties.getProperty("project_name");\r
-            progressMonitor.worked(10);\r
-        } catch (IOException e) {\r
-            throw new PlatformException(e);\r
-        }\r
-\r
-        return installProject;\r
-\r
-    }\r
-\r
-    public boolean assertProject(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, boolean installProject) throws PlatformException {\r
-\r
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();\r
-\r
-        final DatabaseManagement mgmt = new DatabaseManagement();\r
-\r
-        progressMonitor.setTaskName("Asserting project resource exists in the database");\r
-        try {\r
-            projectResource = session.syncRequest( Queries.resource( projectURI ) );\r
-        } catch (ResourceNotFoundException nfe) {\r
-            // Project was not found\r
-            if (workspacePolicy == RecoveryPolicy.ThrowError)\r
-                throw new PlatformException("Project Resource "+projectURI+" is not found in the database.");\r
-            // Create empty project with no features\r
-            try {\r
-                Transaction.startTransaction(session, true);\r
-                try {\r
-                    // The project needs to be created mutable.\r
-                    session.getService(XSupport.class).setServiceMode(true, false);\r
-\r
-                    ArrayList<String> empty = new ArrayList<String>();\r
-                    projectResource = mgmt.createProject(projectName, empty);\r
-                    installProject |= true;\r
-\r
-                    session.getService(XSupport.class).setServiceMode(false, false);\r
-                    Transaction.commit();\r
-                } finally {\r
-                    Transaction.endTransaction();\r
-                }\r
-                //session.getService( LifecycleSupport.class ).save();\r
-            } catch (DatabaseException e) {\r
-                throw new PlatformException("Failed to create "+projectURI, e);\r
-            }\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException("Failed to create "+projectURI, e);\r
-        }\r
-        progressMonitor.worked(10);\r
-\r
-        return installProject;\r
-\r
-    }\r
-\r
-    public void updateInstalledGroups(IProgressMonitor progressMonitor, boolean installProject) throws PlatformException {\r
-\r
-        if (installProject)\r
-        {\r
-            // Attach all feature groups available in platform to created project\r
-            progressMonitor.setTaskName("Install all features");\r
-            Set<GroupReference> publishedFeatureGroups = ProjectFeatures.getInstallGroupsOfPublishedFeatures();\r
-            Collection<GroupReference> groupsWithoutVersion = GroupReference.stripVersions(publishedFeatureGroups);\r
-\r
-    //        final List<String> Platform_Features = new ArrayList<String>();\r
-    //\r
-    //        // Convert graph instances\r
-    //        Collection<TransferableGraph1> platformGraphs = new ArrayList<TransferableGraph1>();\r
-    //        for (GraphBundleEx e : platformTGs.values()) platformGraphs.add( e.getGraph() );\r
-    //        IGraph graph = Graphs.createGraph(platformGraphs);\r
-    //\r
-    //        Res    PublishedProjectFeatures = UriUtils.uriToPath( ProjectResource.URIs.PublishedProjectFeatures );\r
-    //        Path   HasFeature = UriUtils.uriToPath( ProjectResource.URIs.HasFeature );\r
-    //        for(Res feature : graph.getObjects(PublishedProjectFeatures, HasFeature)) {\r
-    //            System.out.println("Installing Project Feature: "+feature.toString());\r
-    //            Platform_Features.add( feature.toString() );\r
-    //        }\r
-\r
-            try {\r
-                Transaction.startTransaction(session, true);\r
-                try {\r
-    //                for (String feature : Platform_Features) {\r
-    //                    try {\r
-    //                        getResource(feature);\r
-    //                    } catch(ResourceNotFoundException e) {\r
-    //                        System.out.println(feature+" not found");\r
-    //                    }\r
-    //                    mgmt.installFeature(projectResource, feature);\r
-    //                }\r
-                    Projects.setProjectInstalledGroups(writeGraph(), projectResource, groupsWithoutVersion);\r
-                    Transaction.commit();\r
-                } finally {\r
-                    Transaction.endTransaction();\r
-                }\r
-                //session.getService( LifecycleSupport.class ).save();\r
-            } catch(DatabaseException ae) {\r
-                throw new PlatformException("Failed to install features", ae);\r
-            }\r
-            progressMonitor.worked(10);\r
-        }\r
-\r
-    }\r
-\r
-    public void assertSessionModel(IProgressMonitor progressMonitor) throws PlatformException {\r
-\r
-        Properties properties = session.getService(Properties.class);\r
-        final String clientId = properties.getProperty("clientId");\r
-\r
-        try {\r
-\r
-            // Currently this needs to be done before data becomes available\r
-            VirtualGraphSupport support = session.getService(VirtualGraphSupport.class);\r
-            VirtualGraph activations = support.getWorkspacePersistent("activations");\r
-\r
-            Resource sessionModel = session.syncRequest(new Read<Resource>() {\r
-\r
-                @Override\r
-                public Resource perform(ReadGraph graph) throws DatabaseException {\r
-\r
-                    Layer0X L0X = Layer0X.getInstance(graph);\r
-                    for(Resource sessionModel : graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0X.HasSession, L0X.Session))) {\r
-                        String id = graph.getPossibleRelatedValue(sessionModel, L0X.Session_HasClientId);\r
-                        if(id != null && id.equals(clientId)) return sessionModel;\r
-                    }\r
-                    return null;\r
-\r
-                }\r
-\r
-            });\r
-\r
-            if(sessionModel == null) {\r
-\r
-                sessionModel = session.syncRequest(new WriteResultRequest<Resource>(activations) {\r
-\r
-                    @Override\r
-                    public Resource perform(WriteGraph graph) throws DatabaseException {\r
-                        Layer0 L0 = Layer0.getInstance(graph);\r
-                        Layer0X L0X = Layer0X.getInstance(graph);\r
-                        Resource session = graph.newResource();\r
-                        graph.claim(session, L0.InstanceOf, null, L0X.Session);\r
-                        graph.claim(session, L0X.Session_HasUser, null, graph.getResource("http://Users/AdminUser"));\r
-                        graph.addLiteral(session, L0X.Session_HasClientId, L0X.Session_HasClientId_Inverse, clientId, Bindings.STRING);\r
-                        graph.claim(graph.getRootLibrary(), L0X.HasSession, session);\r
-                        return session;\r
-                    }\r
-                });\r
-\r
-            }\r
-\r
-            session.registerService(SessionModel.class, new PlatformSessionModel(sessionModel));\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException(e);\r
-        }\r
-\r
-    }\r
-\r
-    static class PlatformSessionModel implements SessionModel {\r
-        private final Resource sessionModel;\r
-\r
-        public PlatformSessionModel(Resource model) {\r
-            this.sessionModel = model;\r
-        }\r
-\r
-        @Override\r
-        public Resource getResource() {\r
-            return sessionModel;\r
-        }\r
-    }\r
-\r
-    public void resetDatabase(IProgressMonitor monitor) throws PlatformException {\r
-        File dbLocation = Platform.getLocation().append("db").toFile();\r
-        if(!dbLocation.exists()) return;\r
-        try { // Load driver\r
-            Driver driver = Manager.getDriver("procore");\r
-            Management management = driver.getManagement(dbLocation.getAbsolutePath(), null);\r
-            management.delete();\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException("Failed to remove database at " + dbLocation.getAbsolutePath(), e);\r
-        }\r
-        // We have created extra files to database folder which have to be deleted also.\r
-        // This is an awful idea! Do not create extra files to database folder!\r
-        Throwable t = null;\r
-        for (int i=0; i<10; ++i) {\r
-            try {\r
-                FileUtils.deleteAll(dbLocation);\r
-                t = null;\r
-                break;\r
-            } catch (IOException e) {\r
-                // Assuming this has been thrown because delete file/folder failed.\r
-                t = e;\r
-            }\r
-            try {\r
-                Thread.sleep(200);\r
-            } catch (InterruptedException e) {\r
-                // Ignoring interrupted exception.\r
-            }\r
-        }\r
-        if (null != t)\r
-            throw new PlatformException("Failed to remove database folder at " + dbLocation.getAbsolutePath(), t);\r
-    }\r
-    public void resetWorkspace(IProgressMonitor monitor, ArrayList<String> fileFilter) throws PlatformException, IllegalStateException, IOException {\r
-        File file = Platform.getLocation().toFile();\r
-        if (null != fileFilter)\r
-            FileUtils.deleteAllWithFilter(file , fileFilter);\r
-        resetDatabase(monitor);\r
-    }\r
-\r
-    /**\r
-     * Start-up the platform. The procedure consists of 8 steps. Once everything\r
-     * is up and running, all fields are set property.\r
-     * <p>\r
-     *\r
-     * If workspacePolicy is FixErrors, there is an attempt to fix unexpected\r
-     * errors. It includes installing database files, installing ontologies, and\r
-     * installing project features.\r
-     * <p>\r
-     *\r
-     * In SWB this is handled in SimanticsWorkbenchAdvisor#openWindows().\r
-     * <p>\r
-     *\r
-     * If remote server is given, simantics plaform takes connection there\r
-     * instead of local server at "db/".\r
-     *\r
-     * @param workspacePolicy action to take on workspace/database related\r
-     *        errors\r
-     * @param ontologyPolicy action to take on ontology mismatch\r
-     * @param progressMonitor optional progress monitor\r
-     * @param userAgent interface for resorting to user feedback during platform\r
-     *        startup or <code>null</code> to resort to default measures\r
-     * @throws PlatformException\r
-     */\r
-    public SessionContext startUp(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy,\r
-            OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize, PlatformUserAgent userAgent)\r
-    throws PlatformException\r
-    {\r
-\r
-        assert(!running);\r
-        TimeLogger.log("Beginning of SimanticsPlatform.startUp");\r
-\r
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();\r
-\r
-        // For debugging on what kind of platform automatic tests are running in\r
-        // case there are problems.\r
-        if ("true".equals(System.getProperty("org.simantics.dumpBundleState")))\r
-            dumpPlatformBundleState();\r
-\r
-        // 0. Consult all startup extensions before doing anything with the workspace.\r
-        StartupExtensions.consultStartupExtensions();\r
-        TimeLogger.log("Consulted platform pre-startup extensions");\r
-\r
-        // 0.1. Clear all temporary files\r
-        Simantics.clearTemporaryDirectory();\r
-        TimeLogger.log("Cleared temporary directory");\r
-\r
-        // 0.2 Clear VariableRepository.repository static map which holds references to SessionImplDb\r
-        VariableRepository.clear();\r
-        \r
-        // 1. Assert there is a database at <workspace>/db\r
-        session = setupDatabase(databaseDriverId, progressMonitor, workspacePolicy, userAgent);\r
-        TimeLogger.log("Database setup complete");\r
-\r
-        // 2. Assert all graphs, and correct versions, are installed to the database\r
-        synchronizeOntologies(progressMonitor, ontologyPolicy, requireSynchronize);\r
-        TimeLogger.log("Synchronized ontologies");\r
-\r
-        // 4. Assert simantics.cfg exists\r
-        boolean installProject = assertConfiguration(progressMonitor,workspacePolicy);\r
-\r
-        // 5. Assert Project Resource is installed in the database\r
-        installProject = assertProject(progressMonitor, workspacePolicy, installProject);\r
-\r
-        // 6. Install all features into project, if in debug mode\r
-        updateInstalledGroups(progressMonitor, installProject);\r
-        TimeLogger.log("Installed all features into project");\r
-\r
-        // 7. Assert L0.Session in database for this session\r
-        assertSessionModel(progressMonitor);\r
-\r
-        session.getService(XSupport.class).setServiceMode(false, false);\r
-\r
-        try {\r
-            session.sync(new WriteRequest() {\r
-\r
-                @Override\r
-                public void perform(WriteGraph graph) throws DatabaseException {\r
-                    QueryControl qc = graph.getService(QueryControl.class);\r
-                    qc.flush(graph);\r
-                }\r
-\r
-            });\r
-            TimeLogger.log("Flushed queries");\r
-        } catch (DatabaseException e) {\r
-            Logger.defaultLogError(e);\r
-        }\r
-        boolean loadProject = true;\r
-        try {\r
-\r
-               sessionContext = SimanticsPlatform.INSTANCE.createSessionContext(true);\r
-               // This must be before setSessionContext since some listeners might query this\r
-            sessionContext.setHint(SimanticsKeys.KEY_PROJECT, SimanticsPlatform.INSTANCE.projectResource);\r
-\r
-            Simantics.setSessionContext(sessionContext);\r
-\r
-            // 1. Put ResourceBinding that throws an exception to General Bindings\r
-            simanticsBindings = new SimanticsBindings( null );\r
-            Bindings.classBindingFactory.addFactory( simanticsBindings );\r
-\r
-\r
-            // 2. Create session-specific second Binding context (Databoard) and\r
-            //    put that to Session as a service\r
-            Session session = sessionContext.getSession();\r
-            Databoard sessionDataboard = new Databoard();\r
-            session.registerService(Databoard.class, sessionDataboard);\r
-            simanticsBindings2 = new SimanticsBindings( session );\r
-            sessionDataboard.classBindingFactory.addFactory( simanticsBindings2 );\r
-\r
-            // Register datatype bindings\r
-            Bindings.defaultBindingFactory.getRepository().put(RGB.Integer.BINDING.type(), RGB.Integer.BINDING);\r
-            Bindings.defaultBindingFactory.getRepository().put(Font.BINDING.type(), Font.BINDING);\r
-\r
-            if(loadProject) {\r
-\r
-                TimeLogger.log("Load projects");\r
-                project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource);\r
-\r
-                sessionContext.setHint(ProjectKeys.KEY_PROJECT, project);\r
-                TimeLogger.log("Loading projects complete");\r
-\r
-                project.activate();\r
-                TimeLogger.log("Project activated");\r
-            }\r
-\r
-        } catch (DatabaseException e) {\r
-            Logger.defaultLogError(e);\r
-            throw new PlatformException(e);\r
-        } catch (ProjectException e) {\r
-            boolean hasStackTrace = e.getStackTrace().length > 0;\r
-            if (!hasStackTrace)\r
-                throw new PlatformException(e.getMessage(), hasStackTrace);\r
-            throw new PlatformException(e, hasStackTrace);\r
-        }\r
-\r
-        running = true;\r
-\r
-        return sessionContext;\r
-\r
-    }\r
-\r
-    public SessionContext createSessionContext(boolean init) throws PlatformException {\r
-        try {\r
-            // Construct and initialize SessionContext from Session.\r
-            SessionContext sessionContext = SessionContext.create(session, init);\r
-            if (init)\r
-                sessionContext.registerServices();\r
-            return sessionContext;\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException(e);\r
-        }\r
-    }\r
-\r
-//    private static File getIgnorePrerequisitesFile(URL workspaceUrl) {\r
-//        if (workspaceUrl == null)\r
-//            return null;\r
-//        return new File(workspaceUrl.getPath(), ".ignorePrerequisites");\r
-//    }\r
-//\r
-//    private void ensurePrerequisites(IProgressMonitor progressMonitor, PlatformUserAgent userAgent) throws PlatformException {\r
-//        Location loc = Platform.getInstanceLocation();\r
-//        File ignorePrerequisites = getIgnorePrerequisitesFile(loc.getURL());\r
-//        if (loc.isSet() && ignorePrerequisites != null) {\r
-//            if (ignorePrerequisites.exists() || ignorePrerequisites.isFile())\r
-//                return;\r
-//        }\r
-//\r
-//        try {\r
-//            ServerEnvironment.ensureServerDependenciesMet();\r
-//        } catch (ExecutionEnvironmentException e) {\r
-//            // Not installed properly, ask user whether to try installation.\r
-//            try {\r
-//                StringBuilder msg = new StringBuilder();\r
-//                msg.append("Your system seems to be missing the following prerequisites for running this application:\n\n");\r
-//                for (Product product : e.requiredProducts)\r
-//                    msg.append("\t" + product.getDescription() + "\n");\r
-//                msg.append("\nYou can either install the missing components now or ignore and attempt to start the application without them. Ignore Always will ignore this question for this workspace.");\r
-//                msg.append("\n\nSelecting Cancel will close the application.");\r
-//\r
-//                int selection = 0;\r
-//                if (userAgent != null) {\r
-//                    selection = userAgent.showPrompt("Missing Prerequisites", msg.toString(), new String[] {\r
-//                        "Install Pre-requisites",\r
-//                        "Ignore Now",\r
-//                        "Ignore Always",\r
-//                        "Cancel"\r
-//                    }, selection);\r
-//                }\r
-//                boolean tryInstall = false;\r
-//                switch (selection) {\r
-//                    case 0:\r
-//                        tryInstall = true;\r
-//                        break;\r
-//                    case 2:\r
-//                        ignorePrerequisites.createNewFile();\r
-//                    case 1:\r
-//                        break;\r
-//                    case 3:\r
-//                    case -1:\r
-//                        throw new CancelStartupException();\r
-//                }\r
-//\r
-//                if (tryInstall) {\r
-//                    // Try to install it and check for success afterwards.\r
-//                    ServerEnvironment.tryInstallDependencies(progressMonitor);\r
-//                    ServerEnvironment.ensureServerDependenciesMet();\r
-//                }\r
-//            } catch (InstallException ie) {\r
-//                throw new PlatformException(ie);\r
-//            } catch (ExecutionEnvironmentException eee) {\r
-//                throw new PlatformException(eee);\r
-//            } catch (IOException ie) {\r
-//                throw new PlatformException(ie);\r
-//            }\r
-//        }\r
-//    }\r
-\r
-    /**\r
-     * Shutdown Simantics Platform.\r
-     *\r
-     * In SWB this is handled in SimanticsWorkbenchAdvisor#disconnectFromWorkspace.\r
-     *\r
-     * @param progressMonitor optional progress monitor\r
-     * @throws PlatformException\r
-     */\r
-    public void shutdown(IProgressMonitor progressMonitor) throws PlatformException\r
-    {\r
-        SubMonitor progress = SubMonitor.convert(progressMonitor, 100);\r
-        PlatformException platformException = null;\r
-        try {\r
-            progress.subTask("Close Project");\r
-            if (project != null) {\r
-                project.safeDispose();\r
-            }\r
-            progress.worked(10);\r
-\r
-            running = false;\r
-            progress.subTask("Close Database Session");\r
-            Databoard databoard = null;\r
-            if (sessionContext != null) {\r
-                Session s = sessionContext.peekSession();\r
-                if (s != null) {\r
-                    databoard = s.peekService(Databoard.class);\r
-\r
-                    progress.subTask("Flushing Index Caches");\r
-                    try {\r
-                        Simantics.flushIndexCaches(progress.newChild(20), s);\r
-                    } catch (Throwable t) {\r
-                        Logger.defaultLogError(t);\r
-                    }\r
-                }\r
-\r
-                progress.subTask("Close Database Session");\r
-                sessionContext.safeDispose();\r
-                sessionContext = null;\r
-                Simantics.setSessionContext(null);\r
-            }\r
-            if (simanticsBindings != null) {\r
-                Bindings.classBindingFactory.removeFactory( simanticsBindings );\r
-                simanticsBindings = null;\r
-            }\r
-            if (databoard != null) {\r
-               if (simanticsBindings2 != null) {\r
-                       databoard.classBindingFactory.removeFactory( simanticsBindings2 );\r
-                       simanticsBindings2 = null;\r
-               }\r
-               databoard.clear();\r
-            }\r
-\r
-            // Make sure Simantics clipboard doesn't store unwanted session data references.\r
-            Simantics.setClipboard(new SimanticsClipboardImpl());\r
-\r
-            progress.worked(30);\r
-\r
-            session = null;\r
-            projectResource = null;\r
-\r
-            DependenciesRelation.assertFinishedTracking();\r
-\r
-        } catch (Exception e) {\r
-            platformException = new PlatformException("Failed to shutdown Simantics Platform", e);\r
-        }\r
-\r
-        progress.worked(10);\r
-        progress.subTask("Shutting down database");\r
-        try {\r
-            if (null != databasebManagement)\r
-                databasebManagement.shutdown();\r
-        } catch (Throwable t) {\r
-            Logger.defaultLogError(t);\r
-        }\r
-        progress.worked(10);\r
-\r
-        progress.subTask("Clearing Workspace Temporary Directory");\r
-        try {\r
-            Simantics.clearTemporaryDirectory();\r
-        } catch (Throwable t) {\r
-            Logger.defaultLogError(t);\r
-        }\r
-        progress.worked(10);\r
-        if (null != platformException)\r
-            throw platformException;\r
-    }\r
-\r
-    // TODO: consider removing this in the future ??\r
-    @Override\r
-    public void stateChanged(LifecycleState newState) {\r
-        if(newState == LifecycleState.CLOSED) {\r
-            if(running) {\r
-                if(Platform.isRunning()) {\r
-                    mainThread.interrupt();\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * @return <code>true</code> if discard was successful, <code>false</code>\r
-     *         if there was no session, {@link UndoRedoSupport} or\r
-     *         {@link UndoContext} to discard through\r
-     */\r
-    public boolean discardSessionUndoHistory() {\r
-        Session s = session;\r
-        if (s != null) {\r
-            UndoRedoSupport urs = s.peekService(UndoRedoSupport.class);\r
-            if (urs != null) {\r
-                UndoContext uc = urs.getUndoContext(s);\r
-                if (uc != null) {\r
-                    uc.clear();\r
-                    return true;\r
-                }\r
-            }\r
-        }\r
-        return false;\r
-    }\r
-\r
-    public void reconnect(String databaseDriverId) throws Exception {\r
-        // Starts database server.\r
-        SimanticsPlatform.INSTANCE.startUp(databaseDriverId, null, RecoveryPolicy.ThrowError, OntologyRecoveryPolicy.ThrowError, true, null);\r
-    }\r
-\r
-    private void dumpPlatformBundleState() {\r
-        BundleDescription[] bs = Platform.getPlatformAdmin().getState().getBundles();\r
-        System.out.println("Total bundles: " + bs.length);\r
-        for (BundleDescription b : bs) {\r
-            System.out.format("%-80s @ %s\n", b.toString(), b.getLocation());\r
-        }\r
-    }\r
-\r
-}\r
-\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * 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:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics;
+
+import static org.simantics.db.common.utils.Transaction.commit;
+import static org.simantics.db.common.utils.Transaction.endTransaction;
+import static org.simantics.db.common.utils.Transaction.readGraph;
+import static org.simantics.db.common.utils.Transaction.startTransaction;
+import static org.simantics.db.common.utils.Transaction.writeGraph;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.UUID;
+
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.Databoard;
+import org.simantics.datatypes.literal.Font;
+import org.simantics.datatypes.literal.RGB;
+import org.simantics.db.Driver;
+import org.simantics.db.Driver.Management;
+import org.simantics.db.Manager;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.SessionModel;
+import org.simantics.db.UndoContext;
+import org.simantics.db.VirtualGraph;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.ObjectsWithType;
+import org.simantics.db.common.request.Queries;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.request.WriteResultRequest;
+import org.simantics.db.common.utils.Transaction;
+import org.simantics.db.exception.ClusterSetExistException;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ResourceNotFoundException;
+import org.simantics.db.indexing.DatabaseIndexing;
+import org.simantics.db.layer0.genericrelation.DependenciesRelation;
+import org.simantics.db.layer0.util.SimanticsClipboardImpl;
+import org.simantics.db.layer0.util.SimanticsKeys;
+import org.simantics.db.layer0.util.TGTransferableGraphSource;
+import org.simantics.db.layer0.variable.VariableRepository;
+import org.simantics.db.management.SessionContext;
+import org.simantics.db.request.Read;
+import org.simantics.db.service.LifecycleSupport.LifecycleListener;
+import org.simantics.db.service.LifecycleSupport.LifecycleState;
+import org.simantics.db.service.QueryControl;
+import org.simantics.db.service.UndoRedoSupport;
+import org.simantics.db.service.VirtualGraphSupport;
+import org.simantics.db.service.XSupport;
+import org.simantics.graph.db.GraphDependencyAnalyzer;
+import org.simantics.graph.db.GraphDependencyAnalyzer.IU;
+import org.simantics.graph.db.GraphDependencyAnalyzer.IdentityNode;
+import org.simantics.graph.db.IImportAdvisor;
+import org.simantics.graph.db.TransferableGraphs;
+import org.simantics.graph.diff.Diff;
+import org.simantics.graph.diff.TransferableGraphDelta1;
+import org.simantics.internal.Activator;
+import org.simantics.internal.startup.StartupExtensions;
+import org.simantics.layer0.Layer0;
+import org.simantics.operation.Layer0X;
+import org.simantics.project.IProject;
+import org.simantics.project.ProjectFeatures;
+import org.simantics.project.ProjectKeys;
+import org.simantics.project.Projects;
+import org.simantics.project.exception.ProjectException;
+import org.simantics.project.features.registry.GroupReference;
+import org.simantics.project.management.DatabaseManagement;
+import org.simantics.project.management.GraphBundle;
+import org.simantics.project.management.GraphBundleEx;
+import org.simantics.project.management.GraphBundleRef;
+import org.simantics.project.management.PlatformUtil;
+import org.simantics.project.management.ServerManager;
+import org.simantics.project.management.ServerManagerFactory;
+import org.simantics.project.management.WorkspaceUtil;
+import org.simantics.utils.FileUtils;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.logging.TimeLogger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * SimanticsPlatform performs procedures required in order to get simantics
+ * workbench into operational state. This consists of the following steps:
+ * <ul>
+ *     <li> Asserting there is Database
+ *     </li>
+ *     <li> Starting Database process
+ *     </li>
+ *     <li> Opening a session to Database process
+ *     </li>
+ *     <li> Asserting required ontologies or other transferable graphs are installed in the database
+ *     </li>
+ *     <li> Asserting required project is installed in the database
+ *     </li>
+ *     <li> Asserting Simantics Features are installed in the database
+ *     </li>
+ *     <li> Asserting Simantics Features are installed to the project
+ *     </li>
+ *     <li> Shutdown: Save Session, Close session, Kill Database process
+ *     </li>
+ * </ul>
+ *
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+public class SimanticsPlatform implements LifecycleListener {
+
+    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SimanticsPlatform.class);
+    
+    /**
+     * The policy is relevant when developing Simantics from Eclipse IDE.
+     * It is applied when the ontology in the database of a workspace doesn't match
+     * a newer ontology in the Eclipse workspace.
+     */
+    public static enum OntologyRecoveryPolicy { ThrowError, Merge, ReinstallDatabase }
+
+    /**
+     * This policy dictates how the Simantics platform startup should react if
+     * the started workspace is not set up properly. The alternatives are to
+     * just throw an error and fail or to attempt all possible measures to fix
+     * the encountered problems.
+     */
+    public static enum RecoveryPolicy { ThrowError, FixError }
+
+    /** Singleton instance, started in SimanticsWorkbenchAdvisor */
+    public static final SimanticsPlatform INSTANCE = new SimanticsPlatform();
+
+    /** Set to true when the Simantics Platform is in good-and-go condition */
+    public boolean running;
+
+    /** Database Session */
+    public Session session;
+    private Management databasebManagement;
+
+    /** Database session context */
+    public SessionContext sessionContext;
+
+    /** Project identifier in Database */
+    public String projectURI;
+
+    /** Project name */
+    public String projectName;
+
+    /** Project resource */
+    public Resource projectResource;
+
+    /** Session specific bindings */
+    public SimanticsBindings simanticsBindings;
+    public SimanticsBindings simanticsBindings2;
+
+    public Thread mainThread;
+
+    /**
+     * The {@link IProject} activated by
+     * {@link #startUp(IProgressMonitor, RecoveryPolicy, OntologyRecoveryPolicy, ServerAddress, PlatformUserAgent)}
+     */
+    private IProject project;
+
+    protected ILog log;
+
+    /**
+     * Create a new simantics plaform manager in uninitialized state and
+     * with default policies. <p>
+     */
+    public SimanticsPlatform() {
+        log = Platform.getLog(Activator.getBundleContext().getBundle());
+        mainThread = Thread.currentThread();
+    }
+
+    public String getApplicationClientId() {
+        IProduct product = Platform.getProduct();
+        if(product == null) return "noProduct";//UUID.randomUUID().toString();
+        String application = product.getApplication();
+        return application != null ? application : UUID.randomUUID().toString();
+    }
+
+    private Session setupDatabase(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, PlatformUserAgent userAgent) throws PlatformException {
+        if (progressMonitor == null)
+            progressMonitor = new NullProgressMonitor();
+        File dbLocation = Platform.getLocation().append("db").toFile();
+        ServerManager serverManager;
+        try {
+            serverManager = ServerManagerFactory.create(databaseDriverId, dbLocation.getAbsolutePath());
+        } catch (DatabaseException | IOException e) {
+            throw new PlatformException("Failed to initialize Server Manager", e);
+        }
+        progressMonitor.beginTask("Setting up Simantics Database", 100);
+        progressMonitor.setTaskName("Asserting Database is installed.");
+        String msg = "Failed to initialize Simantics database.";
+        try {
+            // Create database
+            log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Creating database at " + dbLocation));
+            progressMonitor.setTaskName("Creating database at " + dbLocation);
+            databasebManagement = serverManager.getManagement(dbLocation);
+            databasebManagement.create();
+            // Create layer0.
+            return serverManager.createDatabase(dbLocation);
+        } catch (DatabaseException e) {
+            throw new PlatformException(msg, e);
+        } catch (Throwable e) {
+            throw new PlatformException(msg, e);
+        } finally {
+            progressMonitor.worked(20);
+        }
+    }
+
+    public void synchronizeOntologies(IProgressMonitor progressMonitor, OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize) throws PlatformException {
+
+        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
+
+        final DatabaseManagement mgmt = new DatabaseManagement();
+
+        PlatformUtil.compileAllDynamicOntologies();
+
+        progressMonitor.setTaskName("Asserting all ontologies are installed");
+        final Map<GraphBundleRef, GraphBundleEx> platformTGs = new HashMap<GraphBundleRef, GraphBundleEx>();
+        try {
+
+            // Get a list of bundles installed into the database
+            progressMonitor.subTask("find installed bundles from database");
+            Map<GraphBundleRef, GraphBundleEx> installedTGs = new HashMap<GraphBundleRef, GraphBundleEx>();
+            for (GraphBundle b : session.syncRequest( mgmt.GraphBundleQuery )) {
+                installedTGs.put(GraphBundleRef.of(b), GraphBundleEx.extend(b));
+            }
+
+            if(!requireSynchronize && installedTGs.size() > 1 && !Platform.inDevelopmentMode()) return;
+//            if(installedTGs.size() > 1) return;
+
+            // Get a list of all bundles in the platform (Bundle Context)
+            List<GraphBundle> tgs = new ArrayList<GraphBundle>();
+            progressMonitor.subTask("load all transferable graphs from platform");
+            PlatformUtil.getAllGraphs(tgs);
+            progressMonitor.subTask("extend bundles to compile versions");
+            for (GraphBundle b : tgs) {
+                GraphBundleEx gbe = GraphBundleEx.extend(b);
+                gbe.build();
+                platformTGs.put(GraphBundleRef.of(b), gbe);
+            }
+
+            // Compile a list of TGs that need to be installed or reinstalled in the database
+            progressMonitor.subTask("check bundle reinstallation demand");
+            List<GraphBundleEx> installTGs = new ArrayList<GraphBundleEx>();
+            // Create list of TGs to update, <newTg, oldTg>
+            Map<GraphBundleEx,GraphBundleEx> reinstallTGs = new TreeMap<GraphBundleEx,GraphBundleEx>();
+            for (Entry<GraphBundleRef, GraphBundleEx> e : platformTGs.entrySet()) {
+                GraphBundleRef key = e.getKey();
+                GraphBundleEx platformBundle = e.getValue();
+                GraphBundleEx existingBundle = installedTGs.get(key);
+                
+//                System.out.println("GraphBundleRef key=" + key.toString());
+                
+                if (existingBundle == null) {
+                    // Bundle did not exist in the database, put it into list of bundles to install
+                    installTGs.add(platformBundle);
+                }
+                else {
+                    // Bundle exists in the database
+                    boolean platformBundleIsNewer = existingBundle.getVersion().compareTo(platformBundle.getVersion())<0;
+                    if (!platformBundleIsNewer)
+                        continue;
+                    // Check hash of transferable graph to know whether to update or not.
+                    if (platformBundle.getHashcode() == existingBundle.getHashcode())
+                        continue;
+                    //System.out.println("Ontology hashcodes do not match: platform bundle="
+                    //        + platformBundle.getVersionedId() + ", hash=" + platformBundle.getHashcode()
+                    //        + "; existing bundle=" + existingBundle.getVersionedId() + ", hash=" + existingBundle.getHashcode());
+                    reinstallTGs.put(platformBundle, existingBundle);
+                }
+            }
+            // INSTALL
+            // Database is missing graphs
+            if (!installTGs.isEmpty() || !reinstallTGs.isEmpty()) {
+                session.getService(XSupport.class).setServiceMode(true, true);
+
+                // Throw error
+                if (ontologyPolicy == OntologyRecoveryPolicy.ThrowError) {
+                    StringBuilder sb = new StringBuilder("The following graphs are not installed in the database: ");
+                    if (!installTGs.isEmpty()) {
+                        int i = 0;
+                        for (GraphBundleEx e : installTGs) {
+                            if (i>0) sb.append(", ");
+                            i++;
+                            sb.append(e.toString());
+                        }
+                        sb.append(" is missing from the database.\n");
+                    }
+                    if (!reinstallTGs.isEmpty()) {
+                        int i = 0;
+                        for (Entry<GraphBundleEx, GraphBundleEx> e : reinstallTGs.entrySet()) {
+                            if (i>0) sb.append(", ");
+                            i++;
+                            sb.append(e.getKey().toString());
+                        }
+                        sb.append(" Database/Platform Bundle version mismatch.\n");
+                    }
+                    sb.append("Hint: Use -fixErrors to install the graphs.");
+                    throw new PlatformException(sb.toString());
+                }
+                // Reinstall database
+                if (ontologyPolicy == OntologyRecoveryPolicy.ReinstallDatabase) {
+                    log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Reinstalling the database."));
+                    // TODO Install DB
+                    // Stop Session
+                    // Kill Process
+                    // Delete Database
+                    // Create Database
+                    // Start Database
+                    // Open Session
+                    // Install TGs
+                    throw new PlatformException("Reinstalling Database, NOT IMPLEMENTED");
+                }
+
+                if (ontologyPolicy == OntologyRecoveryPolicy.Merge) {
+                    progressMonitor.subTask("Merging ontology changes");
+                    // Sort missing TGs into install order
+                    GraphDependencyAnalyzer<GraphBundle> analyzer = new GraphDependencyAnalyzer<GraphBundle>();
+                    for(GraphBundle tg : installTGs) analyzer.addGraph(tg, tg.getGraph());
+                    for(GraphBundle tg : reinstallTGs.keySet()) analyzer.addGraph(tg, tg.getGraph());
+                    if(!analyzer.analyzeDependency()) {
+                        Collection<Pair<GraphBundle, GraphBundle>> problems = analyzer.getConflicts();
+                        StringBuilder sb = new StringBuilder();
+                        for (Pair<GraphBundle, GraphBundle> problem : problems) {
+                            sb.append("Conflict with "+problem.first+" and "+problem.second+".\n");
+                        }
+                        throw new PlatformException(sb.toString());
+                    }
+                    else if(!session.syncRequest( analyzer.queryExternalDependenciesSatisfied )) {
+                        Collection<IdentityNode> unsatisfiedDependencies = analyzer.getUnsatisfiedDependencies();
+                        StringBuilder sb = new StringBuilder();
+                        for (IdentityNode dep: unsatisfiedDependencies) {
+                            sb.append("Unsatisfied Dependency "+dep+". Required by\n");
+                            for(IU iu : GraphDependencyAnalyzer.toCollection(dep.getRequires())) {
+                                sb.append("    " + ((GraphBundle)iu.getId()).getId() + "\n");
+                            }
+                        }
+                        throw new PlatformException(sb.toString());
+                    }
+                    
+                    List<GraphBundle> sortedBundles = analyzer.getSortedGraphs();
+                    if(!sortedBundles.isEmpty()) {
+                       
+                        session.syncRequest(new WriteRequest() {
+                            @Override
+                            public void perform(WriteGraph graph) throws DatabaseException {
+                                try {
+                                    graph.newClusterSet(graph.getRootLibrary());
+                                } catch (ClusterSetExistException e) {
+                                    // Cluster set exist already, no problem.
+                                }
+                                graph.setClusterSet4NewResource(graph.getRootLibrary());
+                                graph.flushCluster();
+                            }
+                        });
+
+                        boolean mergedOntologies = false;
+
+                        // Install TGs
+                        for(final GraphBundle tg : sortedBundles) {
+
+                               final IImportAdvisor advisor = new OntologyImportAdvisor(tg, mgmt);
+                               final GraphBundle oldTG = reinstallTGs.get(tg);
+
+                               if (oldTG==null) {
+                                       
+                                       boolean createImmutable = tg.getImmutable();
+                                session.getService(XSupport.class).setServiceMode(true, createImmutable);
+
+                                       // Install TG
+                                       log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Installing "+tg.toString()+" - "+tg.getName()));
+                                       TransferableGraphs.importGraph1(session, new TGTransferableGraphSource(tg.getGraph()), advisor, null);
+                               } else {
+                                       // Merge TG
+                                       startTransaction(session, false);
+                                       TransferableGraphDelta1 delta = new Diff(oldTG.getGraph(), tg.getGraph()).diff();
+                                       final long[] oldResources = oldTG.getResourceArray();
+                                       boolean changes = TransferableGraphs.hasChanges(readGraph(), oldResources, delta);
+                                       endTransaction();
+                                       if (!changes) {
+                                           //log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Nothing to merge for "+tg.toString()));
+                                           continue;
+                                       }
+
+                                log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Merging new version of "+tg.toString()));
+
+                                       startTransaction(session, true);
+                                       
+                                       //delta.print();
+                                       try {
+                                               
+                                               
+                                               long[] resourceArray = TransferableGraphs.applyDelta(writeGraph(), oldResources, delta);
+                                               tg.setResourceArray(resourceArray);
+                                               mgmt.setGraphBundleEntry(tg);
+                                               commit();
+                                               mergedOntologies = true;
+                                       } catch (Throwable t) {
+                                               throw new PlatformException(t);
+                                       } finally {
+                                               endTransaction();
+                                       }
+                               }
+                        }
+                        
+                        session.syncRequest(new WriteRequest() {
+                            @Override
+                            public void perform(WriteGraph graph) throws DatabaseException {
+                                graph.setClusterSet4NewResource(graph.getRootLibrary());
+                                graph.flushCluster();
+                            }
+                        });
+
+                        if (mergedOntologies)
+                            DatabaseIndexing.deleteAllIndexes();
+                    }
+
+                    TimeLogger.log("Ontologies synchronized.");
+                    
+                }
+                session.getService(XSupport.class).setServiceMode(false, false);
+            }
+            progressMonitor.worked(20);
+        } catch (IOException e) {
+            throw new PlatformException(e);
+        } catch (DatabaseException e) {
+            throw new PlatformException(e);
+        }
+
+    }
+
+    public boolean assertConfiguration(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy) throws PlatformException {
+
+        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
+
+        File workspaceLocation = Platform.getLocation().toFile();
+
+        boolean installProject = false;
+        progressMonitor.setTaskName("Asserting simantics.cfg is installed");
+        try {
+            File propertyFile = new File(workspaceLocation, "simantics.cfg");
+            Properties properties;
+            try {
+                properties = WorkspaceUtil.readProperties(propertyFile);
+            } catch (IOException e) {
+                if (workspacePolicy == RecoveryPolicy.ThrowError) throw new PlatformException("Could not load "+propertyFile);
+
+                // Create a project and write Property file
+                properties = new Properties();
+                properties.setProperty("project_uri", "http://Projects/Development%20Project");
+                properties.setProperty("project_name", "Development Project");
+                WorkspaceUtil.writeProperties(propertyFile, properties);
+                installProject |= true;
+            }
+            projectURI = properties.getProperty("project_uri");
+            projectName = properties.getProperty("project_name");
+            progressMonitor.worked(10);
+        } catch (IOException e) {
+            throw new PlatformException(e);
+        }
+
+        return installProject;
+
+    }
+
+    public boolean assertProject(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, boolean installProject) throws PlatformException {
+
+        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
+
+        final DatabaseManagement mgmt = new DatabaseManagement();
+
+        progressMonitor.setTaskName("Asserting project resource exists in the database");
+        try {
+            projectResource = session.syncRequest( Queries.resource( projectURI ) );
+        } catch (ResourceNotFoundException nfe) {
+            // Project was not found
+            if (workspacePolicy == RecoveryPolicy.ThrowError)
+                throw new PlatformException("Project Resource "+projectURI+" is not found in the database.");
+            // Create empty project with no features
+            try {
+                Transaction.startTransaction(session, true);
+                try {
+                    // The project needs to be created mutable.
+                    session.getService(XSupport.class).setServiceMode(true, false);
+
+                    ArrayList<String> empty = new ArrayList<String>();
+                    projectResource = mgmt.createProject(projectName, empty);
+                    installProject |= true;
+
+                    session.getService(XSupport.class).setServiceMode(false, false);
+                    Transaction.commit();
+                } finally {
+                    Transaction.endTransaction();
+                }
+                //session.getService( LifecycleSupport.class ).save();
+            } catch (DatabaseException e) {
+                throw new PlatformException("Failed to create "+projectURI, e);
+            }
+        } catch (DatabaseException e) {
+            throw new PlatformException("Failed to create "+projectURI, e);
+        }
+        progressMonitor.worked(10);
+
+        return installProject;
+
+    }
+
+    public void updateInstalledGroups(IProgressMonitor progressMonitor, boolean installProject) throws PlatformException {
+
+        if (installProject)
+        {
+            // Attach all feature groups available in platform to created project
+            progressMonitor.setTaskName("Install all features");
+            Set<GroupReference> publishedFeatureGroups = ProjectFeatures.getInstallGroupsOfPublishedFeatures();
+            Collection<GroupReference> groupsWithoutVersion = GroupReference.stripVersions(publishedFeatureGroups);
+
+    //        final List<String> Platform_Features = new ArrayList<String>();
+    //
+    //        // Convert graph instances
+    //        Collection<TransferableGraph1> platformGraphs = new ArrayList<TransferableGraph1>();
+    //        for (GraphBundleEx e : platformTGs.values()) platformGraphs.add( e.getGraph() );
+    //        IGraph graph = Graphs.createGraph(platformGraphs);
+    //
+    //        Res    PublishedProjectFeatures = UriUtils.uriToPath( ProjectResource.URIs.PublishedProjectFeatures );
+    //        Path   HasFeature = UriUtils.uriToPath( ProjectResource.URIs.HasFeature );
+    //        for(Res feature : graph.getObjects(PublishedProjectFeatures, HasFeature)) {
+    //            System.out.println("Installing Project Feature: "+feature.toString());
+    //            Platform_Features.add( feature.toString() );
+    //        }
+
+            try {
+                Transaction.startTransaction(session, true);
+                try {
+    //                for (String feature : Platform_Features) {
+    //                    try {
+    //                        getResource(feature);
+    //                    } catch(ResourceNotFoundException e) {
+    //                        System.out.println(feature+" not found");
+    //                    }
+    //                    mgmt.installFeature(projectResource, feature);
+    //                }
+                    Projects.setProjectInstalledGroups(writeGraph(), projectResource, groupsWithoutVersion);
+                    Transaction.commit();
+                } finally {
+                    Transaction.endTransaction();
+                }
+                //session.getService( LifecycleSupport.class ).save();
+            } catch(DatabaseException ae) {
+                throw new PlatformException("Failed to install features", ae);
+            }
+            progressMonitor.worked(10);
+        }
+
+    }
+
+    public void assertSessionModel(IProgressMonitor progressMonitor) throws PlatformException {
+
+        Properties properties = session.getService(Properties.class);
+        final String clientId = properties.getProperty("clientId");
+
+        try {
+
+            // Currently this needs to be done before data becomes available
+            VirtualGraphSupport support = session.getService(VirtualGraphSupport.class);
+            VirtualGraph activations = support.getWorkspacePersistent("activations");
+
+            Resource sessionModel = session.syncRequest(new Read<Resource>() {
+
+                @Override
+                public Resource perform(ReadGraph graph) throws DatabaseException {
+
+                    Layer0X L0X = Layer0X.getInstance(graph);
+                    for(Resource sessionModel : graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0X.HasSession, L0X.Session))) {
+                        String id = graph.getPossibleRelatedValue(sessionModel, L0X.Session_HasClientId);
+                        if(id != null && id.equals(clientId)) return sessionModel;
+                    }
+                    return null;
+
+                }
+
+            });
+
+            if(sessionModel == null) {
+
+                sessionModel = session.syncRequest(new WriteResultRequest<Resource>(activations) {
+
+                    @Override
+                    public Resource perform(WriteGraph graph) throws DatabaseException {
+                        Layer0 L0 = Layer0.getInstance(graph);
+                        Layer0X L0X = Layer0X.getInstance(graph);
+                        Resource session = graph.newResource();
+                        graph.claim(session, L0.InstanceOf, null, L0X.Session);
+                        graph.claim(session, L0X.Session_HasUser, null, graph.getResource("http://Users/AdminUser"));
+                        graph.addLiteral(session, L0X.Session_HasClientId, L0X.Session_HasClientId_Inverse, clientId, Bindings.STRING);
+                        graph.claim(graph.getRootLibrary(), L0X.HasSession, session);
+                        return session;
+                    }
+                });
+
+            }
+
+            session.registerService(SessionModel.class, new PlatformSessionModel(sessionModel));
+        } catch (DatabaseException e) {
+            throw new PlatformException(e);
+        }
+
+    }
+
+    static class PlatformSessionModel implements SessionModel {
+        private final Resource sessionModel;
+
+        public PlatformSessionModel(Resource model) {
+            this.sessionModel = model;
+        }
+
+        @Override
+        public Resource getResource() {
+            return sessionModel;
+        }
+    }
+
+    public void resetDatabase(IProgressMonitor monitor) throws PlatformException {
+        File dbLocation = Platform.getLocation().append("db").toFile();
+        if(!dbLocation.exists()) return;
+        try { // Load driver
+            Driver driver = Manager.getDriver("procore");
+            Management management = driver.getManagement(dbLocation.getAbsolutePath(), null);
+            management.delete();
+        } catch (DatabaseException e) {
+            throw new PlatformException("Failed to remove database at " + dbLocation.getAbsolutePath(), e);
+        }
+        // We have created extra files to database folder which have to be deleted also.
+        // This is an awful idea! Do not create extra files to database folder!
+        Throwable t = null;
+        for (int i=0; i<10; ++i) {
+            try {
+                FileUtils.deleteAll(dbLocation);
+                t = null;
+                break;
+            } catch (IOException e) {
+                // Assuming this has been thrown because delete file/folder failed.
+                t = e;
+            }
+            try {
+                Thread.sleep(200);
+            } catch (InterruptedException e) {
+                // Ignoring interrupted exception.
+            }
+        }
+        if (null != t)
+            throw new PlatformException("Failed to remove database folder at " + dbLocation.getAbsolutePath(), t);
+    }
+    public void resetWorkspace(IProgressMonitor monitor, ArrayList<String> fileFilter) throws PlatformException, IllegalStateException, IOException {
+        File file = Platform.getLocation().toFile();
+        if (null != fileFilter)
+            FileUtils.deleteAllWithFilter(file , fileFilter);
+        resetDatabase(monitor);
+    }
+
+    /**
+     * Start-up the platform. The procedure consists of 8 steps. Once everything
+     * is up and running, all fields are set property.
+     * <p>
+     *
+     * If workspacePolicy is FixErrors, there is an attempt to fix unexpected
+     * errors. It includes installing database files, installing ontologies, and
+     * installing project features.
+     * <p>
+     *
+     * In SWB this is handled in SimanticsWorkbenchAdvisor#openWindows().
+     * <p>
+     *
+     * If remote server is given, simantics plaform takes connection there
+     * instead of local server at "db/".
+     *
+     * @param workspacePolicy action to take on workspace/database related
+     *        errors
+     * @param ontologyPolicy action to take on ontology mismatch
+     * @param progressMonitor optional progress monitor
+     * @param userAgent interface for resorting to user feedback during platform
+     *        startup or <code>null</code> to resort to default measures
+     * @throws PlatformException
+     */
+    public SessionContext startUp(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy,
+            OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize, PlatformUserAgent userAgent)
+    throws PlatformException
+    {
+
+        assert(!running);
+        TimeLogger.log("Beginning of SimanticsPlatform.startUp");
+
+        LOGGER.info("Beginning of SimanticsPlatform.startUp");
+        
+        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
+
+        // For debugging on what kind of platform automatic tests are running in
+        // case there are problems.
+        if ("true".equals(System.getProperty("org.simantics.dumpBundleState")))
+            dumpPlatformBundleState();
+
+        // 0. Consult all startup extensions before doing anything with the workspace.
+        StartupExtensions.consultStartupExtensions();
+        TimeLogger.log("Consulted platform pre-startup extensions");
+
+        // 0.1. Clear all temporary files
+        Simantics.clearTemporaryDirectory();
+        TimeLogger.log("Cleared temporary directory");
+
+        // 0.2 Clear VariableRepository.repository static map which holds references to SessionImplDb
+        VariableRepository.clear();
+        
+        // 1. Assert there is a database at <workspace>/db
+        session = setupDatabase(databaseDriverId, progressMonitor, workspacePolicy, userAgent);
+        TimeLogger.log("Database setup complete");
+
+        // 2. Assert all graphs, and correct versions, are installed to the database
+        synchronizeOntologies(progressMonitor, ontologyPolicy, requireSynchronize);
+        TimeLogger.log("Synchronized ontologies");
+
+        // 4. Assert simantics.cfg exists
+        boolean installProject = assertConfiguration(progressMonitor,workspacePolicy);
+
+        // 5. Assert Project Resource is installed in the database
+        installProject = assertProject(progressMonitor, workspacePolicy, installProject);
+
+        // 6. Install all features into project, if in debug mode
+        updateInstalledGroups(progressMonitor, installProject);
+        TimeLogger.log("Installed all features into project");
+
+        // 7. Assert L0.Session in database for this session
+        assertSessionModel(progressMonitor);
+
+        session.getService(XSupport.class).setServiceMode(false, false);
+
+        try {
+            session.sync(new WriteRequest() {
+
+                @Override
+                public void perform(WriteGraph graph) throws DatabaseException {
+                    QueryControl qc = graph.getService(QueryControl.class);
+                    qc.flush(graph);
+                }
+
+            });
+            TimeLogger.log("Flushed queries");
+        } catch (DatabaseException e) {
+            Logger.defaultLogError(e);
+        }
+        boolean loadProject = true;
+        try {
+
+               sessionContext = SimanticsPlatform.INSTANCE.createSessionContext(true);
+               // This must be before setSessionContext since some listeners might query this
+            sessionContext.setHint(SimanticsKeys.KEY_PROJECT, SimanticsPlatform.INSTANCE.projectResource);
+
+            Simantics.setSessionContext(sessionContext);
+
+            // 1. Put ResourceBinding that throws an exception to General Bindings
+            simanticsBindings = new SimanticsBindings( null );
+            Bindings.classBindingFactory.addFactory( simanticsBindings );
+
+
+            // 2. Create session-specific second Binding context (Databoard) and
+            //    put that to Session as a service
+            Session session = sessionContext.getSession();
+            Databoard sessionDataboard = new Databoard();
+            session.registerService(Databoard.class, sessionDataboard);
+            simanticsBindings2 = new SimanticsBindings( session );
+            sessionDataboard.classBindingFactory.addFactory( simanticsBindings2 );
+
+            // Register datatype bindings
+            Bindings.defaultBindingFactory.getRepository().put(RGB.Integer.BINDING.type(), RGB.Integer.BINDING);
+            Bindings.defaultBindingFactory.getRepository().put(Font.BINDING.type(), Font.BINDING);
+
+            if(loadProject) {
+
+                TimeLogger.log("Load projects");
+                project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource);
+
+                sessionContext.setHint(ProjectKeys.KEY_PROJECT, project);
+                TimeLogger.log("Loading projects complete");
+
+                project.activate();
+                TimeLogger.log("Project activated");
+            }
+
+        } catch (DatabaseException e) {
+            Logger.defaultLogError(e);
+            throw new PlatformException(e);
+        } catch (ProjectException e) {
+            boolean hasStackTrace = e.getStackTrace().length > 0;
+            if (!hasStackTrace)
+                throw new PlatformException(e.getMessage(), hasStackTrace);
+            throw new PlatformException(e, hasStackTrace);
+        }
+
+        running = true;
+
+        return sessionContext;
+
+    }
+
+    public SessionContext createSessionContext(boolean init) throws PlatformException {
+        try {
+            // Construct and initialize SessionContext from Session.
+            SessionContext sessionContext = SessionContext.create(session, init);
+            if (init)
+                sessionContext.registerServices();
+            return sessionContext;
+        } catch (DatabaseException e) {
+            throw new PlatformException(e);
+        }
+    }
+
+//    private static File getIgnorePrerequisitesFile(URL workspaceUrl) {
+//        if (workspaceUrl == null)
+//            return null;
+//        return new File(workspaceUrl.getPath(), ".ignorePrerequisites");
+//    }
+//
+//    private void ensurePrerequisites(IProgressMonitor progressMonitor, PlatformUserAgent userAgent) throws PlatformException {
+//        Location loc = Platform.getInstanceLocation();
+//        File ignorePrerequisites = getIgnorePrerequisitesFile(loc.getURL());
+//        if (loc.isSet() && ignorePrerequisites != null) {
+//            if (ignorePrerequisites.exists() || ignorePrerequisites.isFile())
+//                return;
+//        }
+//
+//        try {
+//            ServerEnvironment.ensureServerDependenciesMet();
+//        } catch (ExecutionEnvironmentException e) {
+//            // Not installed properly, ask user whether to try installation.
+//            try {
+//                StringBuilder msg = new StringBuilder();
+//                msg.append("Your system seems to be missing the following prerequisites for running this application:\n\n");
+//                for (Product product : e.requiredProducts)
+//                    msg.append("\t" + product.getDescription() + "\n");
+//                msg.append("\nYou can either install the missing components now or ignore and attempt to start the application without them. Ignore Always will ignore this question for this workspace.");
+//                msg.append("\n\nSelecting Cancel will close the application.");
+//
+//                int selection = 0;
+//                if (userAgent != null) {
+//                    selection = userAgent.showPrompt("Missing Prerequisites", msg.toString(), new String[] {
+//                        "Install Pre-requisites",
+//                        "Ignore Now",
+//                        "Ignore Always",
+//                        "Cancel"
+//                    }, selection);
+//                }
+//                boolean tryInstall = false;
+//                switch (selection) {
+//                    case 0:
+//                        tryInstall = true;
+//                        break;
+//                    case 2:
+//                        ignorePrerequisites.createNewFile();
+//                    case 1:
+//                        break;
+//                    case 3:
+//                    case -1:
+//                        throw new CancelStartupException();
+//                }
+//
+//                if (tryInstall) {
+//                    // Try to install it and check for success afterwards.
+//                    ServerEnvironment.tryInstallDependencies(progressMonitor);
+//                    ServerEnvironment.ensureServerDependenciesMet();
+//                }
+//            } catch (InstallException ie) {
+//                throw new PlatformException(ie);
+//            } catch (ExecutionEnvironmentException eee) {
+//                throw new PlatformException(eee);
+//            } catch (IOException ie) {
+//                throw new PlatformException(ie);
+//            }
+//        }
+//    }
+
+    /**
+     * Shutdown Simantics Platform.
+     *
+     * In SWB this is handled in SimanticsWorkbenchAdvisor#disconnectFromWorkspace.
+     *
+     * @param progressMonitor optional progress monitor
+     * @throws PlatformException
+     */
+    public void shutdown(IProgressMonitor progressMonitor) throws PlatformException
+    {
+        SubMonitor progress = SubMonitor.convert(progressMonitor, 100);
+        PlatformException platformException = null;
+        try {
+            progress.subTask("Close Project");
+            if (project != null) {
+                project.safeDispose();
+            }
+            progress.worked(10);
+
+            running = false;
+            progress.subTask("Close Database Session");
+            Databoard databoard = null;
+            if (sessionContext != null) {
+                Session s = sessionContext.peekSession();
+                if (s != null) {
+                    databoard = s.peekService(Databoard.class);
+
+                    progress.subTask("Flushing Index Caches");
+                    try {
+                        Simantics.flushIndexCaches(progress.newChild(20), s);
+                    } catch (Throwable t) {
+                        Logger.defaultLogError(t);
+                    }
+                }
+
+                progress.subTask("Close Database Session");
+                sessionContext.safeDispose();
+                sessionContext = null;
+                Simantics.setSessionContext(null);
+            }
+            if (simanticsBindings != null) {
+                Bindings.classBindingFactory.removeFactory( simanticsBindings );
+                simanticsBindings = null;
+            }
+            if (databoard != null) {
+               if (simanticsBindings2 != null) {
+                       databoard.classBindingFactory.removeFactory( simanticsBindings2 );
+                       simanticsBindings2 = null;
+               }
+               databoard.clear();
+            }
+
+            // Make sure Simantics clipboard doesn't store unwanted session data references.
+            Simantics.setClipboard(new SimanticsClipboardImpl());
+
+            progress.worked(30);
+
+            session = null;
+            projectResource = null;
+
+            DependenciesRelation.assertFinishedTracking();
+
+        } catch (Exception e) {
+            platformException = new PlatformException("Failed to shutdown Simantics Platform", e);
+        }
+
+        progress.worked(10);
+        progress.subTask("Shutting down database");
+        try {
+            if (null != databasebManagement)
+                databasebManagement.shutdown();
+        } catch (Throwable t) {
+            Logger.defaultLogError(t);
+        }
+        progress.worked(10);
+
+        progress.subTask("Clearing Workspace Temporary Directory");
+        try {
+            Simantics.clearTemporaryDirectory();
+        } catch (Throwable t) {
+            Logger.defaultLogError(t);
+        }
+        progress.worked(10);
+        if (null != platformException)
+            throw platformException;
+    }
+
+    // TODO: consider removing this in the future ??
+    @Override
+    public void stateChanged(LifecycleState newState) {
+        if(newState == LifecycleState.CLOSED) {
+            if(running) {
+                if(Platform.isRunning()) {
+                    mainThread.interrupt();
+                }
+            }
+        }
+    }
+
+    /**
+     * @return <code>true</code> if discard was successful, <code>false</code>
+     *         if there was no session, {@link UndoRedoSupport} or
+     *         {@link UndoContext} to discard through
+     */
+    public boolean discardSessionUndoHistory() {
+        Session s = session;
+        if (s != null) {
+            UndoRedoSupport urs = s.peekService(UndoRedoSupport.class);
+            if (urs != null) {
+                UndoContext uc = urs.getUndoContext(s);
+                if (uc != null) {
+                    uc.clear();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void reconnect(String databaseDriverId) throws Exception {
+        // Starts database server.
+        SimanticsPlatform.INSTANCE.startUp(databaseDriverId, null, RecoveryPolicy.ThrowError, OntologyRecoveryPolicy.ThrowError, true, null);
+    }
+
+    private void dumpPlatformBundleState() {
+        BundleDescription[] bs = Platform.getPlatformAdmin().getState().getBundles();
+        System.out.println("Total bundles: " + bs.length);
+        for (BundleDescription b : bs) {
+            System.out.format("%-80s @ %s\n", b.toString(), b.getLocation());
+        }
+    }
+
+}
+
index 54ab690db0c2627a056ef9c6d2c03a78810608cf..0b2a85da4e23bbc2ca65c163faf8c18c60f94dc7 100644 (file)
-<?xml version="1.0" encoding="UTF-8"?>\r
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
-    <groupId>org.simantics</groupId>\r
-    <artifactId>org.simantics.root.bundles</artifactId>\r
-    <version>1.0.0-SNAPSHOT</version>\r
-    <packaging>pom</packaging>\r
-\r
-    <parent>\r
-        <groupId>org.simantics</groupId>\r
-        <artifactId>org.simantics.root</artifactId>\r
-        <version>1.0.0-SNAPSHOT</version>\r
-    </parent>\r
-\r
-    <build>\r
-        <plugins>\r
-            <plugin>\r
-                <groupId>org.eclipse.tycho</groupId>\r
-                <artifactId>tycho-compiler-plugin</artifactId>\r
-                <version>${tycho.version}</version>\r
-                <configuration>\r
-                    <compilerArgument>-err:-forbidden</compilerArgument>\r
-                </configuration>\r
-            </plugin>\r
-            <plugin>\r
-                <groupId>org.eclipse.tycho</groupId>\r
-                <artifactId>tycho-source-plugin</artifactId>\r
-                <version>${tycho.version}</version>\r
-                <executions>\r
-                    <execution>\r
-                        <id>plugin-source</id>\r
-                        <goals>\r
-                            <goal>plugin-source</goal>\r
-                        </goals>\r
-                    </execution>\r
-                </executions>\r
-            </plugin>\r
-        </plugins>\r
-    </build>\r
-\r
-    <modules>\r
-        <module>com.famfamfam.silk</module>\r
-        <module>org.simantics</module>\r
-        <module>org.simantics.action.ontology</module>\r
-        <module>org.simantics.acorn</module>\r
-        <module>org.simantics.annotation.ontology</module>\r
-        <module>org.simantics.annotation.ui</module>\r
-        <module>org.simantics.application</module>\r
-        <module>org.simantics.backup</module>\r
-        <module>org.simantics.backup.db</module>\r
-        <module>org.simantics.backup.ontology</module>\r
-        <module>org.simantics.basicexpression</module>\r
-        <module>org.simantics.browsing.ui</module>\r
-        <module>org.simantics.browsing.ui.common</module>\r
-        <module>org.simantics.browsing.ui.graph</module>\r
-        <module>org.simantics.browsing.ui.graph.impl</module>\r
-        <module>org.simantics.browsing.ui.model</module>\r
-        <module>org.simantics.browsing.ui.ontology</module>\r
-        <module>org.simantics.browsing.ui.platform</module>\r
-        <module>org.simantics.browsing.ui.swt</module>\r
-        <module>org.simantics.charts</module>\r
-        <module>org.simantics.charts.ontology</module>\r
-        <module>org.simantics.color.ontology</module>\r
-        <module>org.simantics.common</module>\r
-        <module>org.simantics.compressions</module>\r
-        <module>org.simantics.databoard</module>\r
-        <module>org.simantics.datatypes</module>\r
-        <module>org.simantics.datatypes.ontology</module>\r
-        <module>org.simantics.db</module>\r
-        <module>org.simantics.db.common</module>\r
-        <module>org.simantics.db.impl</module>\r
-        <module>org.simantics.db.indexing</module>\r
-        <module>org.simantics.db.layer0</module>\r
-        <module>org.simantics.db.management</module>\r
-        <module>org.simantics.db.procore</module>\r
-        <module>org.simantics.db.procore.server.environment</module>\r
-        <module>org.simantics.db.procore.ui</module>\r
-        <module>org.simantics.db.server</module>\r
-        <module>org.simantics.db.services</module>\r
-        <module>org.simantics.debug.browser</module>\r
-        <module>org.simantics.debug.browser.ui</module>\r
-        <module>org.simantics.debug.graphical</module>\r
-        <module>org.simantics.debug.ui</module>\r
-        <module>org.simantics.diagram</module>\r
-        <module>org.simantics.diagram.connection</module>\r
-        <module>org.simantics.diagram.ontology</module>\r
-        <module>org.simantics.diagram.profile</module>\r
-        <module>org.simantics.document</module>\r
-        <module>org.simantics.document.base.ontology</module>\r
-        <module>org.simantics.document.linking.ontology</module>\r
-        <module>org.simantics.document.linking.ui</module>\r
-        <module>org.simantics.document.ontology</module>\r
-        <module>org.simantics.document.server</module>\r
-        <module>org.simantics.document.server.io</module>\r
-        <module>org.simantics.document.swt.core</module>\r
-        <module>org.simantics.document.swt.ontology</module>\r
-        <module>org.simantics.document.ui</module>\r
-        <module>org.simantics.document.ui.ontology</module>\r
-        <module>org.simantics.dublincore.ontology</module>\r
-        <module>org.simantics.editors</module>\r
-        <module>org.simantics.editors.win32</module>\r
-        <module>org.simantics.equation</module>\r
-        <module>org.simantics.event</module>\r
-        <module>org.simantics.event.ontology</module>\r
-        <module>org.simantics.excel</module>\r
-        <module>org.simantics.export.core</module>\r
-        <module>org.simantics.export.ui</module>\r
-        <module>org.simantics.fastlz</module>\r
-        <module>org.simantics.fileimport</module>\r
-        <module>org.simantics.fileimport.ui</module>\r
-        <module>org.simantics.g2d</module>\r
-        <module>org.simantics.g2d.ontology</module>\r
-        <module>org.simantics.graph</module>\r
-        <module>org.simantics.graph.compiler</module>\r
-        <module>org.simantics.graph.db</module>\r
-        <module>org.simantics.graphfile</module>\r
-        <module>org.simantics.graphfile.ontology</module>\r
-        <module>org.simantics.graphviz</module>\r
-        <module>org.simantics.graphviz.ui</module>\r
-        <module>org.simantics.history</module>\r
-        <module>org.simantics.image.ontology</module>\r
-        <module>org.simantics.image.ui</module>\r
-        <module>org.simantics.image2.ontology</module>\r
-        <module>org.simantics.issues</module>\r
-        <module>org.simantics.issues.common</module>\r
-        <module>org.simantics.issues.ontology</module>\r
-        <module>org.simantics.issues.ui</module>\r
-        <module>org.simantics.issues.ui.ontology</module>\r
-        <module>org.simantics.layer0</module>\r
-        <module>org.simantics.layer0.utils</module>\r
-        <module>org.simantics.layer0x.ontology</module>\r
-        <module>org.simantics.ltk</module>\r
-        <module>org.simantics.ltk.antlr</module>\r
-        <module>org.simantics.lz4</module>\r
-        <module>org.simantics.mapping</module>\r
-        <module>org.simantics.message</module>\r
-        <module>org.simantics.message.ui</module>\r
-        <module>org.simantics.migration.ui</module>\r
-        <module>org.simantics.modeling</module>\r
-        <module>org.simantics.modeling.ontology</module>\r
-        <module>org.simantics.modeling.template2d.ontology</module>\r
-        <module>org.simantics.modeling.template2d.ui</module>\r
-        <module>org.simantics.modeling.ui</module>\r
-        <module>org.simantics.nativemem</module>\r
-        <module>org.simantics.objmap2</module>\r
-        <module>org.simantics.platform.ui.ontology</module>\r
-        <module>org.simantics.project</module>\r
-        <module>org.simantics.project.ontology</module>\r
-        <module>org.simantics.scenegraph</module>\r
-        <module>org.simantics.scenegraph.loader</module>\r
-        <module>org.simantics.scenegraph.ontology</module>\r
-        <module>org.simantics.scenegraph.profile</module>\r
-        <module>org.simantics.scenegraph.swing</module>\r
-        <module>org.simantics.scenegraph.ui</module>\r
-        <module>org.simantics.scl.commands</module>\r
-        <module>org.simantics.scl.compiler</module>\r
-        <module>org.simantics.scl.compiler.dummy</module>\r
-        <module>org.simantics.scl.data</module>\r
-        <module>org.simantics.scl.db</module>\r
-        <module>org.simantics.scl.expressions</module>\r
-        <module>org.simantics.scl.osgi</module>\r
-        <module>org.simantics.scl.reflection</module>\r
-        <module>org.simantics.scl.runtime</module>\r
-        <module>org.simantics.scl.ui</module>\r
-        <module>org.simantics.scl.ui.editor</module>\r
-        <module>org.simantics.selectionview</module>\r
-        <module>org.simantics.selectionview.ontology</module>\r
-        <module>org.simantics.selectionview.ui.ontology</module>\r
-        <module>org.simantics.silk.ontology</module>\r
-        <module>org.simantics.simulation</module>\r
-        <module>org.simantics.simulation.ontology</module>\r
-        <module>org.simantics.simulation.sequences</module>\r
-        <module>org.simantics.simulation.ui</module>\r
-        <module>org.simantics.simulator.variable</module>\r
-        <module>org.simantics.softwareconfiguration.ontology</module>\r
-        <module>org.simantics.spreadsheet</module>\r
-        <module>org.simantics.spreadsheet.common</module>\r
-        <module>org.simantics.spreadsheet.graph</module>\r
-        <module>org.simantics.spreadsheet.ontology</module>\r
-        <module>org.simantics.spreadsheet.ui</module>\r
-        <module>org.simantics.structural.ontology</module>\r
-        <module>org.simantics.structural.synchronization</module>\r
-        <module>org.simantics.structural.synchronization.client</module>\r
-        <module>org.simantics.structural.ui</module>\r
-        <module>org.simantics.structural2</module>\r
-        <module>org.simantics.team.ui</module>\r
-        <module>org.simantics.threadlog</module>\r
-        <module>org.simantics.trend</module>\r
-        <module>org.simantics.ui</module>\r
-        <module>org.simantics.user.ontology</module>\r
-        <module>org.simantics.utils</module>\r
-        <module>org.simantics.utils.datastructures</module>\r
-        <module>org.simantics.utils.thread</module>\r
-        <module>org.simantics.utils.thread.swt</module>\r
-        <module>org.simantics.utils.ui</module>\r
-        <module>org.simantics.utils.ui.workbench</module>\r
-        <module>org.simantics.viewpoint.ontology</module>\r
-        <module>org.simantics.views</module>\r
-        <module>org.simantics.views.ontology</module>\r
-        <module>org.simantics.views.swt</module>\r
-        <module>org.simantics.views.swt.client</module>\r
-        <module>org.simantics.wiki.ui</module>\r
-        <module>org.simantics.workbench</module>\r
-        <module>org.simantics.workbench.ontology</module>\r
-        <module>org.simantics.workbench.search</module>\r
-        <module>winterwell.markdown</module>\r
-    </modules>\r
-</project>\r
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.simantics</groupId>
+    <artifactId>org.simantics.root.bundles</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <parent>
+        <groupId>org.simantics</groupId>
+        <artifactId>org.simantics.root</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.eclipse.tycho</groupId>
+                <artifactId>tycho-compiler-plugin</artifactId>
+                <version>${tycho.version}</version>
+                <configuration>
+                    <compilerArgument>-err:-forbidden</compilerArgument>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.eclipse.tycho</groupId>
+                <artifactId>tycho-source-plugin</artifactId>
+                <version>${tycho.version}</version>
+                <executions>
+                    <execution>
+                        <id>plugin-source</id>
+                        <goals>
+                            <goal>plugin-source</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <modules>
+        <module>com.famfamfam.silk</module>
+        <module>org.simantics</module>
+        <module>org.simantics.action.ontology</module>
+        <module>org.simantics.acorn</module>
+        <module>org.simantics.annotation.ontology</module>
+        <module>org.simantics.annotation.ui</module>
+        <module>org.simantics.application</module>
+        <module>org.simantics.backup</module>
+        <module>org.simantics.backup.db</module>
+        <module>org.simantics.backup.ontology</module>
+        <module>org.simantics.basicexpression</module>
+        <module>org.simantics.browsing.ui</module>
+        <module>org.simantics.browsing.ui.common</module>
+        <module>org.simantics.browsing.ui.graph</module>
+        <module>org.simantics.browsing.ui.graph.impl</module>
+        <module>org.simantics.browsing.ui.model</module>
+        <module>org.simantics.browsing.ui.ontology</module>
+        <module>org.simantics.browsing.ui.platform</module>
+        <module>org.simantics.browsing.ui.swt</module>
+        <module>org.simantics.charts</module>
+        <module>org.simantics.charts.ontology</module>
+        <module>org.simantics.color.ontology</module>
+        <module>org.simantics.common</module>
+        <module>org.simantics.compressions</module>
+        <module>org.simantics.databoard</module>
+        <module>org.simantics.datatypes</module>
+        <module>org.simantics.datatypes.ontology</module>
+        <module>org.simantics.db</module>
+        <module>org.simantics.db.common</module>
+        <module>org.simantics.db.impl</module>
+        <module>org.simantics.db.indexing</module>
+        <module>org.simantics.db.layer0</module>
+        <module>org.simantics.db.management</module>
+        <module>org.simantics.db.procore</module>
+        <module>org.simantics.db.procore.server.environment</module>
+        <module>org.simantics.db.procore.ui</module>
+        <module>org.simantics.db.server</module>
+        <module>org.simantics.db.services</module>
+        <module>org.simantics.debug.browser</module>
+        <module>org.simantics.debug.browser.ui</module>
+        <module>org.simantics.debug.graphical</module>
+        <module>org.simantics.debug.ui</module>
+        <module>org.simantics.diagram</module>
+        <module>org.simantics.diagram.connection</module>
+        <module>org.simantics.diagram.ontology</module>
+        <module>org.simantics.diagram.profile</module>
+        <module>org.simantics.document</module>
+        <module>org.simantics.document.base.ontology</module>
+        <module>org.simantics.document.linking.ontology</module>
+        <module>org.simantics.document.linking.ui</module>
+        <module>org.simantics.document.ontology</module>
+        <module>org.simantics.document.server</module>
+        <module>org.simantics.document.server.io</module>
+        <module>org.simantics.document.swt.core</module>
+        <module>org.simantics.document.swt.ontology</module>
+        <module>org.simantics.document.ui</module>
+        <module>org.simantics.document.ui.ontology</module>
+        <module>org.simantics.dublincore.ontology</module>
+        <module>org.simantics.editors</module>
+        <module>org.simantics.editors.win32</module>
+        <module>org.simantics.equation</module>
+        <module>org.simantics.event</module>
+        <module>org.simantics.event.ontology</module>
+        <module>org.simantics.excel</module>
+        <module>org.simantics.export.core</module>
+        <module>org.simantics.export.ui</module>
+        <module>org.simantics.fastlz</module>
+        <module>org.simantics.fileimport</module>
+        <module>org.simantics.fileimport.ui</module>
+        <module>org.simantics.g2d</module>
+        <module>org.simantics.g2d.ontology</module>
+        <module>org.simantics.graph</module>
+        <module>org.simantics.graph.compiler</module>
+        <module>org.simantics.graph.db</module>
+        <module>org.simantics.graphfile</module>
+        <module>org.simantics.graphfile.ontology</module>
+        <module>org.simantics.graphviz</module>
+        <module>org.simantics.graphviz.ui</module>
+        <module>org.simantics.history</module>
+        <module>org.simantics.image.ontology</module>
+        <module>org.simantics.image.ui</module>
+        <module>org.simantics.image2.ontology</module>
+        <module>org.simantics.issues</module>
+        <module>org.simantics.issues.common</module>
+        <module>org.simantics.issues.ontology</module>
+        <module>org.simantics.issues.ui</module>
+        <module>org.simantics.issues.ui.ontology</module>
+        <module>org.simantics.layer0</module>
+        <module>org.simantics.layer0.utils</module>
+        <module>org.simantics.layer0x.ontology</module>
+        <module>org.simantics.logback.configuration</module>
+        <module>org.simantics.ltk</module>
+        <module>org.simantics.ltk.antlr</module>
+        <module>org.simantics.lz4</module>
+        <module>org.simantics.mapping</module>
+        <module>org.simantics.message</module>
+        <module>org.simantics.message.ui</module>
+        <module>org.simantics.migration.ui</module>
+        <module>org.simantics.modeling</module>
+        <module>org.simantics.modeling.ontology</module>
+        <module>org.simantics.modeling.template2d.ontology</module>
+        <module>org.simantics.modeling.template2d.ui</module>
+        <module>org.simantics.modeling.ui</module>
+        <module>org.simantics.nativemem</module>
+        <module>org.simantics.objmap2</module>
+        <module>org.simantics.platform.ui.ontology</module>
+        <module>org.simantics.project</module>
+        <module>org.simantics.project.ontology</module>
+        <module>org.simantics.scenegraph</module>
+        <module>org.simantics.scenegraph.loader</module>
+        <module>org.simantics.scenegraph.ontology</module>
+        <module>org.simantics.scenegraph.profile</module>
+        <module>org.simantics.scenegraph.swing</module>
+        <module>org.simantics.scenegraph.ui</module>
+        <module>org.simantics.scl.commands</module>
+        <module>org.simantics.scl.compiler</module>
+        <module>org.simantics.scl.compiler.dummy</module>
+        <module>org.simantics.scl.data</module>
+        <module>org.simantics.scl.db</module>
+        <module>org.simantics.scl.expressions</module>
+        <module>org.simantics.scl.osgi</module>
+        <module>org.simantics.scl.reflection</module>
+        <module>org.simantics.scl.runtime</module>
+        <module>org.simantics.scl.ui</module>
+        <module>org.simantics.scl.ui.editor</module>
+        <module>org.simantics.selectionview</module>
+        <module>org.simantics.selectionview.ontology</module>
+        <module>org.simantics.selectionview.ui.ontology</module>
+        <module>org.simantics.silk.ontology</module>
+        <module>org.simantics.simulation</module>
+        <module>org.simantics.simulation.ontology</module>
+        <module>org.simantics.simulation.sequences</module>
+        <module>org.simantics.simulation.ui</module>
+        <module>org.simantics.simulator.variable</module>
+        <module>org.simantics.softwareconfiguration.ontology</module>
+        <module>org.simantics.spreadsheet</module>
+        <module>org.simantics.spreadsheet.common</module>
+        <module>org.simantics.spreadsheet.graph</module>
+        <module>org.simantics.spreadsheet.ontology</module>
+        <module>org.simantics.spreadsheet.ui</module>
+        <module>org.simantics.structural.ontology</module>
+        <module>org.simantics.structural.synchronization</module>
+        <module>org.simantics.structural.synchronization.client</module>
+        <module>org.simantics.structural.ui</module>
+        <module>org.simantics.structural2</module>
+        <module>org.simantics.team.ui</module>
+        <module>org.simantics.threadlog</module>
+        <module>org.simantics.trend</module>
+        <module>org.simantics.ui</module>
+        <module>org.simantics.user.ontology</module>
+        <module>org.simantics.utils</module>
+        <module>org.simantics.utils.datastructures</module>
+        <module>org.simantics.utils.thread</module>
+        <module>org.simantics.utils.thread.swt</module>
+        <module>org.simantics.utils.ui</module>
+        <module>org.simantics.utils.ui.workbench</module>
+        <module>org.simantics.viewpoint.ontology</module>
+        <module>org.simantics.views</module>
+        <module>org.simantics.views.ontology</module>
+        <module>org.simantics.views.swt</module>
+        <module>org.simantics.views.swt.client</module>
+        <module>org.simantics.wiki.ui</module>
+        <module>org.simantics.workbench</module>
+        <module>org.simantics.workbench.ontology</module>
+        <module>org.simantics.workbench.search</module>
+        <module>winterwell.markdown</module>
+    </modules>
+</project>
index d11d8aa0b9d1a0e28e59053aa0f8c8d3d59a2efd..c1610fdc6f21f32e5d1e922dd14e38fc1848bd4a 100644 (file)
@@ -690,4 +690,11 @@ This Agreement is governed by the laws of the State of New York and the intellec
          version="0.0.0"
          unpack="false"/>
 
          version="0.0.0"
          unpack="false"/>
 
+   <plugin
+         id="org.simantics.logback.configuration"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         fragment="true"/>
+
 </feature>
 </feature>