]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Merge commit 'ffdf837'
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Tue, 27 Sep 2016 22:54:05 +0000 (01:54 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Tue, 27 Sep 2016 22:54:05 +0000 (01:54 +0300)
Resolved conflicts from:
bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/GraphSessionVirtual.java
bundles/org.simantics.db.server/src/org/simantics/db/server/internal/SessionI.java
bundles/org.simantics.db/src/org/simantics/db/Database.java
bundles/org.simantics.db/src/org/simantics/db/service/ClusterSetsSupport.java
bundles/org.simantics.modeling/src/org/simantics/modeling/SCL.java
bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java
bundles/org.simantics/src/org/simantics/SimanticsPlatform.java

1  2 
bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ClusterSetsSupportImpl.java
bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ClusterSetsSupportImpl2.java
bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/GraphSessionVirtual.java
bundles/org.simantics.modeling/src/org/simantics/modeling/SCL.java
bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java
bundles/org.simantics/src/org/simantics/SimanticsPlatform.java

index ed1689ea48c4994baa534d0596fd2f9132decff2,db28af306b384be7284c9b54741a69e359f2c6db..33950652cff5957b8fa6bdea13d05b57b805462d
@@@ -77,10 -77,10 +77,15 @@@ public class ClusterSetsSupportImpl2 im
              clusterSets.touch();\r
          }\r
      }\r
 +    \r
 +    @Override\r
 +    public void setReadDirectory(Path read) {\r
 +        this.readDirectory = read;\r
 +    }\r
  \r
+     @Override\r
+     public void setReadDirectory(Path read) {\r
+         this.readDirectory = read;\r
+     }\r
\r
  }\r
index d1e0064249ea0314929c40f9cfd4ceab481477b0,1dc1b015a931b137dd6944cbaddc56566db45690..f6eba7eb8c3d188c5283d6cbee078ac6eed0d640
@@@ -215,4 -214,4 +214,4 @@@ class GraphSessionVirtual extends Graph
             id = virtualGraphServerSupport.createVirtual();\r
          return id;\r
      }\r
--}
++}
index bfa42b40e18707e020bd27b0d0a9fb9de3654a8f,52909e018bb36df8d1723d23b37f7321a46d0867..24e50c0f7606c2cdde27fefdb0fb8a20a2d32d65
@@@ -23,12 -23,9 +22,13 @@@ import org.simantics.db.layer0.request.
  import org.simantics.db.layer0.util.RemoverUtil;\r
  import org.simantics.db.layer0.util.SimanticsClipboard;\r
  import org.simantics.db.service.DebugSupport;\r
+ import org.simantics.db.service.ServiceActivityMonitor;\r
 +import org.slf4j.Logger;\r
 +import org.slf4j.LoggerFactory;\r
  \r
  public class SCL {\r
 +    private static final Logger LOGGER = LoggerFactory.getLogger(SCL.class);\r
 +\r
      public static void killPlatformWrite(WriteGraph graph) throws DatabaseException {\r
          // Currently not supported.\r
          // Would be relatively easy to support the desired functionality.\r
index 0bce2a5680cc57cc0af696be3faf7953cd1bb0db,d75f1e47672941e9f81eaabf8f7efd8b8d8833d6..bce220c9c3ae24fb64f8248766f0dce4956c1f8f
 -/*******************************************************************************\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.getCause());\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);
++            Activator.logError(getClass().getSimpleName() + ".openWindows failed", e.getCause());
 +        } 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 09d632a3edce942d288a44d8f1b8a19d51cda9c6,7e6bd9dd9be5c7c134baff73223061f535ce6e92..11013eaf7e32ffd1f09fbc4477ed074c2dad21e7
 -/*******************************************************************************\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
 -        // 1.1 \r
 -        XSupport support = session.getService(XSupport.class);\r
 -        if (support.rolledback()) {\r
 -            try {\r
 -                DatabaseIndexing.deleteAllIndexes();\r
 -            } catch (IOException e) {\r
 -                throw new PlatformException(e);\r
 -            }\r
 -        }\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.Logger;
 +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 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");
++        
++        // 1.1 
++        XSupport support = session.getService(XSupport.class);
++        if (support.rolledback()) {
++            try {
++                DatabaseIndexing.deleteAllIndexes();
++            } catch (IOException e) {
++                throw new PlatformException(e);
++            }
++        }
++        
 +        // 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.error("Flushing queries failed.", 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.error("Platform startup failed.", 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.error("Failed to flush index caches.", 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.error("Database shutdown failed.", t);
 +        }
 +        progress.worked(10);
 +
 +        progress.subTask("Clearing Workspace Temporary Directory");
 +        try {
 +            Simantics.clearTemporaryDirectory();
 +        } catch (Throwable t) {
 +            LOGGER.error("Failed to clear the temporary directory.", 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());
 +        }
 +    }
 +
 +}
 +