]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics/src/org/simantics/SimanticsPlatform.java
Merge commit 'ffdf837'
[simantics/platform.git] / bundles / org.simantics / src / org / simantics / SimanticsPlatform.java
index 7e6bd9dd9be5c7c134baff73223061f535ce6e92..11013eaf7e32ffd1f09fbc4477ed074c2dad21e7 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics;\r
-\r
-import static org.simantics.db.common.utils.Transaction.commit;\r
-import static org.simantics.db.common.utils.Transaction.endTransaction;\r
-import static org.simantics.db.common.utils.Transaction.readGraph;\r
-import static org.simantics.db.common.utils.Transaction.startTransaction;\r
-import static org.simantics.db.common.utils.Transaction.writeGraph;\r
-\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Map.Entry;\r
-import java.util.Properties;\r
-import java.util.Set;\r
-import java.util.TreeMap;\r
-import java.util.UUID;\r
-\r
-import org.eclipse.core.runtime.ILog;\r
-import org.eclipse.core.runtime.IProduct;\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.core.runtime.IStatus;\r
-import org.eclipse.core.runtime.NullProgressMonitor;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.eclipse.core.runtime.Status;\r
-import org.eclipse.core.runtime.SubMonitor;\r
-import org.eclipse.osgi.service.resolver.BundleDescription;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.Databoard;\r
-import org.simantics.datatypes.literal.Font;\r
-import org.simantics.datatypes.literal.RGB;\r
-import org.simantics.db.Driver;\r
-import org.simantics.db.Driver.Management;\r
-import org.simantics.db.Manager;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.SessionModel;\r
-import org.simantics.db.UndoContext;\r
-import org.simantics.db.VirtualGraph;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.request.ObjectsWithType;\r
-import org.simantics.db.common.request.Queries;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.common.request.WriteResultRequest;\r
-import org.simantics.db.common.utils.Transaction;\r
-import org.simantics.db.exception.ClusterSetExistException;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ResourceNotFoundException;\r
-import org.simantics.db.indexing.DatabaseIndexing;\r
-import org.simantics.db.layer0.genericrelation.DependenciesRelation;\r
-import org.simantics.db.layer0.util.SimanticsClipboardImpl;\r
-import org.simantics.db.layer0.util.SimanticsKeys;\r
-import org.simantics.db.layer0.util.TGTransferableGraphSource;\r
-import org.simantics.db.layer0.variable.VariableRepository;\r
-import org.simantics.db.management.SessionContext;\r
-import org.simantics.db.request.Read;\r
-import org.simantics.db.service.LifecycleSupport.LifecycleListener;\r
-import org.simantics.db.service.LifecycleSupport.LifecycleState;\r
-import org.simantics.db.service.QueryControl;\r
-import org.simantics.db.service.UndoRedoSupport;\r
-import org.simantics.db.service.VirtualGraphSupport;\r
-import org.simantics.db.service.XSupport;\r
-import org.simantics.graph.db.GraphDependencyAnalyzer;\r
-import org.simantics.graph.db.GraphDependencyAnalyzer.IU;\r
-import org.simantics.graph.db.GraphDependencyAnalyzer.IdentityNode;\r
-import org.simantics.graph.db.IImportAdvisor;\r
-import org.simantics.graph.db.TransferableGraphs;\r
-import org.simantics.graph.diff.Diff;\r
-import org.simantics.graph.diff.TransferableGraphDelta1;\r
-import org.simantics.internal.Activator;\r
-import org.simantics.internal.startup.StartupExtensions;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.operation.Layer0X;\r
-import org.simantics.project.IProject;\r
-import org.simantics.project.ProjectFeatures;\r
-import org.simantics.project.ProjectKeys;\r
-import org.simantics.project.Projects;\r
-import org.simantics.project.exception.ProjectException;\r
-import org.simantics.project.features.registry.GroupReference;\r
-import org.simantics.project.management.DatabaseManagement;\r
-import org.simantics.project.management.GraphBundle;\r
-import org.simantics.project.management.GraphBundleEx;\r
-import org.simantics.project.management.GraphBundleRef;\r
-import org.simantics.project.management.PlatformUtil;\r
-import org.simantics.project.management.ServerManager;\r
-import org.simantics.project.management.ServerManagerFactory;\r
-import org.simantics.project.management.WorkspaceUtil;\r
-import org.simantics.utils.FileUtils;\r
-import org.simantics.utils.datastructures.Pair;\r
-import org.simantics.utils.logging.TimeLogger;\r
-\r
-/**\r
- * SimanticsPlatform performs procedures required in order to get simantics\r
- * workbench into operational state. This consists of the following steps:\r
- * <ul>\r
- *     <li> Asserting there is Database\r
- *     </li>\r
- *     <li> Starting Database process\r
- *     </li>\r
- *     <li> Opening a session to Database process\r
- *     </li>\r
- *     <li> Asserting required ontologies or other transferable graphs are installed in the database\r
- *     </li>\r
- *     <li> Asserting required project is installed in the database\r
- *     </li>\r
- *     <li> Asserting Simantics Features are installed in the database\r
- *     </li>\r
- *     <li> Asserting Simantics Features are installed to the project\r
- *     </li>\r
- *     <li> Shutdown: Save Session, Close session, Kill Database process\r
- *     </li>\r
- * </ul>\r
- *\r
- * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
- */\r
-public class SimanticsPlatform implements LifecycleListener {\r
-\r
-    /**\r
-     * The policy is relevant when developing Simantics from Eclipse IDE.\r
-     * It is applied when the ontology in the database of a workspace doesn't match\r
-     * a newer ontology in the Eclipse workspace.\r
-     */\r
-    public static enum OntologyRecoveryPolicy { ThrowError, Merge, ReinstallDatabase }\r
-\r
-    /**\r
-     * This policy dictates how the Simantics platform startup should react if\r
-     * the started workspace is not set up properly. The alternatives are to\r
-     * just throw an error and fail or to attempt all possible measures to fix\r
-     * the encountered problems.\r
-     */\r
-    public static enum RecoveryPolicy { ThrowError, FixError }\r
-\r
-    /** Singleton instance, started in SimanticsWorkbenchAdvisor */\r
-    public static final SimanticsPlatform INSTANCE = new SimanticsPlatform();\r
-\r
-    /** Set to true when the Simantics Platform is in good-and-go condition */\r
-    public boolean running;\r
-\r
-    /** Database Session */\r
-    public Session session;\r
-    private Management databasebManagement;\r
-\r
-    /** Database session context */\r
-    public SessionContext sessionContext;\r
-\r
-    /** Project identifier in Database */\r
-    public String projectURI;\r
-\r
-    /** Project name */\r
-    public String projectName;\r
-\r
-    /** Project resource */\r
-    public Resource projectResource;\r
-\r
-    /** Session specific bindings */\r
-    public SimanticsBindings simanticsBindings;\r
-    public SimanticsBindings simanticsBindings2;\r
-\r
-    public Thread mainThread;\r
-\r
-    /**\r
-     * The {@link IProject} activated by\r
-     * {@link #startUp(IProgressMonitor, RecoveryPolicy, OntologyRecoveryPolicy, ServerAddress, PlatformUserAgent)}\r
-     */\r
-    private IProject project;\r
-\r
-    protected ILog log;\r
-\r
-    /**\r
-     * Create a new simantics plaform manager in uninitialized state and\r
-     * with default policies. <p>\r
-     */\r
-    public SimanticsPlatform() {\r
-        log = Platform.getLog(Activator.getBundleContext().getBundle());\r
-        mainThread = Thread.currentThread();\r
-    }\r
-\r
-    public String getApplicationClientId() {\r
-        IProduct product = Platform.getProduct();\r
-        if(product == null) return "noProduct";//UUID.randomUUID().toString();\r
-        String application = product.getApplication();\r
-        return application != null ? application : UUID.randomUUID().toString();\r
-    }\r
-\r
-    private Session setupDatabase(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, PlatformUserAgent userAgent) throws PlatformException {\r
-        if (progressMonitor == null)\r
-            progressMonitor = new NullProgressMonitor();\r
-        File dbLocation = Platform.getLocation().append("db").toFile();\r
-        ServerManager serverManager;\r
-        try {\r
-            serverManager = ServerManagerFactory.create(databaseDriverId, dbLocation.getAbsolutePath());\r
-        } catch (DatabaseException | IOException e) {\r
-            throw new PlatformException("Failed to initialize Server Manager", e);\r
-        }\r
-        progressMonitor.beginTask("Setting up Simantics Database", 100);\r
-        progressMonitor.setTaskName("Asserting Database is installed.");\r
-        String msg = "Failed to initialize Simantics database.";\r
-        try {\r
-            // Create database\r
-            log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Creating database at " + dbLocation));\r
-            progressMonitor.setTaskName("Creating database at " + dbLocation);\r
-            databasebManagement = serverManager.getManagement(dbLocation);\r
-            databasebManagement.create();\r
-            // Create layer0.\r
-            return serverManager.createDatabase(dbLocation);\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException(msg, e);\r
-        } catch (Throwable e) {\r
-            throw new PlatformException(msg, e);\r
-        } finally {\r
-            progressMonitor.worked(20);\r
-        }\r
-    }\r
-\r
-    public void synchronizeOntologies(IProgressMonitor progressMonitor, OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize) throws PlatformException {\r
-\r
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();\r
-\r
-        final DatabaseManagement mgmt = new DatabaseManagement();\r
-\r
-        PlatformUtil.compileAllDynamicOntologies();\r
-\r
-        progressMonitor.setTaskName("Asserting all ontologies are installed");\r
-        final Map<GraphBundleRef, GraphBundleEx> platformTGs = new HashMap<GraphBundleRef, GraphBundleEx>();\r
-        try {\r
-\r
-            // Get a list of bundles installed into the database\r
-            progressMonitor.subTask("find installed bundles from database");\r
-            Map<GraphBundleRef, GraphBundleEx> installedTGs = new HashMap<GraphBundleRef, GraphBundleEx>();\r
-            for (GraphBundle b : session.syncRequest( mgmt.GraphBundleQuery )) {\r
-                installedTGs.put(GraphBundleRef.of(b), GraphBundleEx.extend(b));\r
-            }\r
-\r
-            if(!requireSynchronize && installedTGs.size() > 1 && !Platform.inDevelopmentMode()) return;\r
-//            if(installedTGs.size() > 1) return;\r
-\r
-            // Get a list of all bundles in the platform (Bundle Context)\r
-            List<GraphBundle> tgs = new ArrayList<GraphBundle>();\r
-            progressMonitor.subTask("load all transferable graphs from platform");\r
-            PlatformUtil.getAllGraphs(tgs);\r
-            progressMonitor.subTask("extend bundles to compile versions");\r
-            for (GraphBundle b : tgs) {\r
-                GraphBundleEx gbe = GraphBundleEx.extend(b);\r
-                gbe.build();\r
-                platformTGs.put(GraphBundleRef.of(b), gbe);\r
-            }\r
-\r
-            // Compile a list of TGs that need to be installed or reinstalled in the database\r
-            progressMonitor.subTask("check bundle reinstallation demand");\r
-            List<GraphBundleEx> installTGs = new ArrayList<GraphBundleEx>();\r
-            // Create list of TGs to update, <newTg, oldTg>\r
-            Map<GraphBundleEx,GraphBundleEx> reinstallTGs = new TreeMap<GraphBundleEx,GraphBundleEx>();\r
-            for (Entry<GraphBundleRef, GraphBundleEx> e : platformTGs.entrySet()) {\r
-                GraphBundleRef key = e.getKey();\r
-                GraphBundleEx platformBundle = e.getValue();\r
-                GraphBundleEx existingBundle = installedTGs.get(key);\r
-                \r
-//                System.out.println("GraphBundleRef key=" + key.toString());\r
-                \r
-                if (existingBundle == null) {\r
-                    // Bundle did not exist in the database, put it into list of bundles to install\r
-                    installTGs.add(platformBundle);\r
-                }\r
-                else {\r
-                    // Bundle exists in the database\r
-                    boolean platformBundleIsNewer = existingBundle.getVersion().compareTo(platformBundle.getVersion())<0;\r
-                    if (!platformBundleIsNewer)\r
-                        continue;\r
-                    // Check hash of transferable graph to know whether to update or not.\r
-                    if (platformBundle.getHashcode() == existingBundle.getHashcode())\r
-                        continue;\r
-                    //System.out.println("Ontology hashcodes do not match: platform bundle="\r
-                    //        + platformBundle.getVersionedId() + ", hash=" + platformBundle.getHashcode()\r
-                    //        + "; existing bundle=" + existingBundle.getVersionedId() + ", hash=" + existingBundle.getHashcode());\r
-                    reinstallTGs.put(platformBundle, existingBundle);\r
-                }\r
-            }\r
-            // INSTALL\r
-            // Database is missing graphs\r
-            if (!installTGs.isEmpty() || !reinstallTGs.isEmpty()) {\r
-                session.getService(XSupport.class).setServiceMode(true, true);\r
-\r
-                // Throw error\r
-                if (ontologyPolicy == OntologyRecoveryPolicy.ThrowError) {\r
-                    StringBuilder sb = new StringBuilder("The following graphs are not installed in the database: ");\r
-                    if (!installTGs.isEmpty()) {\r
-                        int i = 0;\r
-                        for (GraphBundleEx e : installTGs) {\r
-                            if (i>0) sb.append(", ");\r
-                            i++;\r
-                            sb.append(e.toString());\r
-                        }\r
-                        sb.append(" is missing from the database.\n");\r
-                    }\r
-                    if (!reinstallTGs.isEmpty()) {\r
-                        int i = 0;\r
-                        for (Entry<GraphBundleEx, GraphBundleEx> e : reinstallTGs.entrySet()) {\r
-                            if (i>0) sb.append(", ");\r
-                            i++;\r
-                            sb.append(e.getKey().toString());\r
-                        }\r
-                        sb.append(" Database/Platform Bundle version mismatch.\n");\r
-                    }\r
-                    sb.append("Hint: Use -fixErrors to install the graphs.");\r
-                    throw new PlatformException(sb.toString());\r
-                }\r
-                // Reinstall database\r
-                if (ontologyPolicy == OntologyRecoveryPolicy.ReinstallDatabase) {\r
-                    log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Reinstalling the database."));\r
-                    // TODO Install DB\r
-                    // Stop Session\r
-                    // Kill Process\r
-                    // Delete Database\r
-                    // Create Database\r
-                    // Start Database\r
-                    // Open Session\r
-                    // Install TGs\r
-                    throw new PlatformException("Reinstalling Database, NOT IMPLEMENTED");\r
-                }\r
-\r
-                if (ontologyPolicy == OntologyRecoveryPolicy.Merge) {\r
-                    progressMonitor.subTask("Merging ontology changes");\r
-                    // Sort missing TGs into install order\r
-                    GraphDependencyAnalyzer<GraphBundle> analyzer = new GraphDependencyAnalyzer<GraphBundle>();\r
-                    for(GraphBundle tg : installTGs) analyzer.addGraph(tg, tg.getGraph());\r
-                    for(GraphBundle tg : reinstallTGs.keySet()) analyzer.addGraph(tg, tg.getGraph());\r
-                    if(!analyzer.analyzeDependency()) {\r
-                        Collection<Pair<GraphBundle, GraphBundle>> problems = analyzer.getConflicts();\r
-                        StringBuilder sb = new StringBuilder();\r
-                        for (Pair<GraphBundle, GraphBundle> problem : problems) {\r
-                            sb.append("Conflict with "+problem.first+" and "+problem.second+".\n");\r
-                        }\r
-                        throw new PlatformException(sb.toString());\r
-                    }\r
-                    else if(!session.syncRequest( analyzer.queryExternalDependenciesSatisfied )) {\r
-                        Collection<IdentityNode> unsatisfiedDependencies = analyzer.getUnsatisfiedDependencies();\r
-                        StringBuilder sb = new StringBuilder();\r
-                        for (IdentityNode dep: unsatisfiedDependencies) {\r
-                            sb.append("Unsatisfied Dependency "+dep+". Required by\n");\r
-                            for(IU iu : GraphDependencyAnalyzer.toCollection(dep.getRequires())) {\r
-                                sb.append("    " + ((GraphBundle)iu.getId()).getId() + "\n");\r
-                            }\r
-                        }\r
-                        throw new PlatformException(sb.toString());\r
-                    }\r
-                    \r
-                    List<GraphBundle> sortedBundles = analyzer.getSortedGraphs();\r
-                    if(!sortedBundles.isEmpty()) {\r
-                       \r
-                        session.syncRequest(new WriteRequest() {\r
-                            @Override\r
-                            public void perform(WriteGraph graph) throws DatabaseException {\r
-                                try {\r
-                                    graph.newClusterSet(graph.getRootLibrary());\r
-                                } catch (ClusterSetExistException e) {\r
-                                    // Cluster set exist already, no problem.\r
-                                }\r
-                                graph.setClusterSet4NewResource(graph.getRootLibrary());\r
-                                graph.flushCluster();\r
-                            }\r
-                        });\r
-\r
-                        boolean mergedOntologies = false;\r
-\r
-                        // Install TGs\r
-                        for(final GraphBundle tg : sortedBundles) {\r
-\r
-                               final IImportAdvisor advisor = new OntologyImportAdvisor(tg, mgmt);\r
-                               final GraphBundle oldTG = reinstallTGs.get(tg);\r
-\r
-                               if (oldTG==null) {\r
-                                       \r
-                                       boolean createImmutable = tg.getImmutable();\r
-                                session.getService(XSupport.class).setServiceMode(true, createImmutable);\r
-\r
-                                       // Install TG\r
-                                       log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Installing "+tg.toString()+" - "+tg.getName()));\r
-                                       TransferableGraphs.importGraph1(session, new TGTransferableGraphSource(tg.getGraph()), advisor, null);\r
-                               } else {\r
-                                       // Merge TG\r
-                                       startTransaction(session, false);\r
-                                       TransferableGraphDelta1 delta = new Diff(oldTG.getGraph(), tg.getGraph()).diff();\r
-                                       final long[] oldResources = oldTG.getResourceArray();\r
-                                       boolean changes = TransferableGraphs.hasChanges(readGraph(), oldResources, delta);\r
-                                       endTransaction();\r
-                                       if (!changes) {\r
-                                           //log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Nothing to merge for "+tg.toString()));\r
-                                           continue;\r
-                                       }\r
-\r
-                                log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Merging new version of "+tg.toString()));\r
-\r
-                                       startTransaction(session, true);\r
-                                       \r
-                                       //delta.print();\r
-                                       try {\r
-                                               \r
-                                               \r
-                                               long[] resourceArray = TransferableGraphs.applyDelta(writeGraph(), oldResources, delta);\r
-                                               tg.setResourceArray(resourceArray);\r
-                                               mgmt.setGraphBundleEntry(tg);\r
-                                               commit();\r
-                                               mergedOntologies = true;\r
-                                       } catch (Throwable t) {\r
-                                               throw new PlatformException(t);\r
-                                       } finally {\r
-                                               endTransaction();\r
-                                       }\r
-                               }\r
-                        }\r
-                        \r
-                        session.syncRequest(new WriteRequest() {\r
-                            @Override\r
-                            public void perform(WriteGraph graph) throws DatabaseException {\r
-                                graph.setClusterSet4NewResource(graph.getRootLibrary());\r
-                                graph.flushCluster();\r
-                            }\r
-                        });\r
-\r
-                        if (mergedOntologies)\r
-                            DatabaseIndexing.deleteAllIndexes();\r
-                    }\r
-\r
-                    TimeLogger.log("Ontologies synchronized.");\r
-                    \r
-                }\r
-                session.getService(XSupport.class).setServiceMode(false, false);\r
-            }\r
-            progressMonitor.worked(20);\r
-        } catch (IOException e) {\r
-            throw new PlatformException(e);\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException(e);\r
-        }\r
-\r
-    }\r
-\r
-    public boolean assertConfiguration(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy) throws PlatformException {\r
-\r
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();\r
-\r
-        File workspaceLocation = Platform.getLocation().toFile();\r
-\r
-        boolean installProject = false;\r
-        progressMonitor.setTaskName("Asserting simantics.cfg is installed");\r
-        try {\r
-            File propertyFile = new File(workspaceLocation, "simantics.cfg");\r
-            Properties properties;\r
-            try {\r
-                properties = WorkspaceUtil.readProperties(propertyFile);\r
-            } catch (IOException e) {\r
-                if (workspacePolicy == RecoveryPolicy.ThrowError) throw new PlatformException("Could not load "+propertyFile);\r
-\r
-                // Create a project and write Property file\r
-                properties = new Properties();\r
-                properties.setProperty("project_uri", "http://Projects/Development%20Project");\r
-                properties.setProperty("project_name", "Development Project");\r
-                WorkspaceUtil.writeProperties(propertyFile, properties);\r
-                installProject |= true;\r
-            }\r
-            projectURI = properties.getProperty("project_uri");\r
-            projectName = properties.getProperty("project_name");\r
-            progressMonitor.worked(10);\r
-        } catch (IOException e) {\r
-            throw new PlatformException(e);\r
-        }\r
-\r
-        return installProject;\r
-\r
-    }\r
-\r
-    public boolean assertProject(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, boolean installProject) throws PlatformException {\r
-\r
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();\r
-\r
-        final DatabaseManagement mgmt = new DatabaseManagement();\r
-\r
-        progressMonitor.setTaskName("Asserting project resource exists in the database");\r
-        try {\r
-            projectResource = session.syncRequest( Queries.resource( projectURI ) );\r
-        } catch (ResourceNotFoundException nfe) {\r
-            // Project was not found\r
-            if (workspacePolicy == RecoveryPolicy.ThrowError)\r
-                throw new PlatformException("Project Resource "+projectURI+" is not found in the database.");\r
-            // Create empty project with no features\r
-            try {\r
-                Transaction.startTransaction(session, true);\r
-                try {\r
-                    // The project needs to be created mutable.\r
-                    session.getService(XSupport.class).setServiceMode(true, false);\r
-\r
-                    ArrayList<String> empty = new ArrayList<String>();\r
-                    projectResource = mgmt.createProject(projectName, empty);\r
-                    installProject |= true;\r
-\r
-                    session.getService(XSupport.class).setServiceMode(false, false);\r
-                    Transaction.commit();\r
-                } finally {\r
-                    Transaction.endTransaction();\r
-                }\r
-                //session.getService( LifecycleSupport.class ).save();\r
-            } catch (DatabaseException e) {\r
-                throw new PlatformException("Failed to create "+projectURI, e);\r
-            }\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException("Failed to create "+projectURI, e);\r
-        }\r
-        progressMonitor.worked(10);\r
-\r
-        return installProject;\r
-\r
-    }\r
-\r
-    public void updateInstalledGroups(IProgressMonitor progressMonitor, boolean installProject) throws PlatformException {\r
-\r
-        if (installProject)\r
-        {\r
-            // Attach all feature groups available in platform to created project\r
-            progressMonitor.setTaskName("Install all features");\r
-            Set<GroupReference> publishedFeatureGroups = ProjectFeatures.getInstallGroupsOfPublishedFeatures();\r
-            Collection<GroupReference> groupsWithoutVersion = GroupReference.stripVersions(publishedFeatureGroups);\r
-\r
-    //        final List<String> Platform_Features = new ArrayList<String>();\r
-    //\r
-    //        // Convert graph instances\r
-    //        Collection<TransferableGraph1> platformGraphs = new ArrayList<TransferableGraph1>();\r
-    //        for (GraphBundleEx e : platformTGs.values()) platformGraphs.add( e.getGraph() );\r
-    //        IGraph graph = Graphs.createGraph(platformGraphs);\r
-    //\r
-    //        Res    PublishedProjectFeatures = UriUtils.uriToPath( ProjectResource.URIs.PublishedProjectFeatures );\r
-    //        Path   HasFeature = UriUtils.uriToPath( ProjectResource.URIs.HasFeature );\r
-    //        for(Res feature : graph.getObjects(PublishedProjectFeatures, HasFeature)) {\r
-    //            System.out.println("Installing Project Feature: "+feature.toString());\r
-    //            Platform_Features.add( feature.toString() );\r
-    //        }\r
-\r
-            try {\r
-                Transaction.startTransaction(session, true);\r
-                try {\r
-    //                for (String feature : Platform_Features) {\r
-    //                    try {\r
-    //                        getResource(feature);\r
-    //                    } catch(ResourceNotFoundException e) {\r
-    //                        System.out.println(feature+" not found");\r
-    //                    }\r
-    //                    mgmt.installFeature(projectResource, feature);\r
-    //                }\r
-                    Projects.setProjectInstalledGroups(writeGraph(), projectResource, groupsWithoutVersion);\r
-                    Transaction.commit();\r
-                } finally {\r
-                    Transaction.endTransaction();\r
-                }\r
-                //session.getService( LifecycleSupport.class ).save();\r
-            } catch(DatabaseException ae) {\r
-                throw new PlatformException("Failed to install features", ae);\r
-            }\r
-            progressMonitor.worked(10);\r
-        }\r
-\r
-    }\r
-\r
-    public void assertSessionModel(IProgressMonitor progressMonitor) throws PlatformException {\r
-\r
-        Properties properties = session.getService(Properties.class);\r
-        final String clientId = properties.getProperty("clientId");\r
-\r
-        try {\r
-\r
-            // Currently this needs to be done before data becomes available\r
-            VirtualGraphSupport support = session.getService(VirtualGraphSupport.class);\r
-            VirtualGraph activations = support.getWorkspacePersistent("activations");\r
-\r
-            Resource sessionModel = session.syncRequest(new Read<Resource>() {\r
-\r
-                @Override\r
-                public Resource perform(ReadGraph graph) throws DatabaseException {\r
-\r
-                    Layer0X L0X = Layer0X.getInstance(graph);\r
-                    for(Resource sessionModel : graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0X.HasSession, L0X.Session))) {\r
-                        String id = graph.getPossibleRelatedValue(sessionModel, L0X.Session_HasClientId);\r
-                        if(id != null && id.equals(clientId)) return sessionModel;\r
-                    }\r
-                    return null;\r
-\r
-                }\r
-\r
-            });\r
-\r
-            if(sessionModel == null) {\r
-\r
-                sessionModel = session.syncRequest(new WriteResultRequest<Resource>(activations) {\r
-\r
-                    @Override\r
-                    public Resource perform(WriteGraph graph) throws DatabaseException {\r
-                        Layer0 L0 = Layer0.getInstance(graph);\r
-                        Layer0X L0X = Layer0X.getInstance(graph);\r
-                        Resource session = graph.newResource();\r
-                        graph.claim(session, L0.InstanceOf, null, L0X.Session);\r
-                        graph.claim(session, L0X.Session_HasUser, null, graph.getResource("http://Users/AdminUser"));\r
-                        graph.addLiteral(session, L0X.Session_HasClientId, L0X.Session_HasClientId_Inverse, clientId, Bindings.STRING);\r
-                        graph.claim(graph.getRootLibrary(), L0X.HasSession, session);\r
-                        return session;\r
-                    }\r
-                });\r
-\r
-            }\r
-\r
-            session.registerService(SessionModel.class, new PlatformSessionModel(sessionModel));\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException(e);\r
-        }\r
-\r
-    }\r
-\r
-    static class PlatformSessionModel implements SessionModel {\r
-        private final Resource sessionModel;\r
-\r
-        public PlatformSessionModel(Resource model) {\r
-            this.sessionModel = model;\r
-        }\r
-\r
-        @Override\r
-        public Resource getResource() {\r
-            return sessionModel;\r
-        }\r
-    }\r
-\r
-    public void resetDatabase(IProgressMonitor monitor) throws PlatformException {\r
-        File dbLocation = Platform.getLocation().append("db").toFile();\r
-        if(!dbLocation.exists()) return;\r
-        try { // Load driver\r
-            Driver driver = Manager.getDriver("procore");\r
-            Management management = driver.getManagement(dbLocation.getAbsolutePath(), null);\r
-            management.delete();\r
-        } catch (DatabaseException e) {\r
-            throw new PlatformException("Failed to remove database at " + dbLocation.getAbsolutePath(), e);\r
-        }\r
-        // We have created extra files to database folder which have to be deleted also.\r
-        // This is an awful idea! Do not create extra files to database folder!\r
-        Throwable t = null;\r
-        for (int i=0; i<10; ++i) {\r
-            try {\r
-                FileUtils.deleteAll(dbLocation);\r
-                t = null;\r
-                break;\r
-            } catch (IOException e) {\r
-                // Assuming this has been thrown because delete file/folder failed.\r
-                t = e;\r
-            }\r
-            try {\r
-                Thread.sleep(200);\r
-            } catch (InterruptedException e) {\r
-                // Ignoring interrupted exception.\r
-            }\r
-        }\r
-        if (null != t)\r
-            throw new PlatformException("Failed to remove database folder at " + dbLocation.getAbsolutePath(), t);\r
-    }\r
-    public void resetWorkspace(IProgressMonitor monitor, ArrayList<String> fileFilter) throws PlatformException, IllegalStateException, IOException {\r
-        File file = Platform.getLocation().toFile();\r
-        if (null != fileFilter)\r
-            FileUtils.deleteAllWithFilter(file , fileFilter);\r
-        resetDatabase(monitor);\r
-    }\r
-\r
-    /**\r
-     * Start-up the platform. The procedure consists of 8 steps. Once everything\r
-     * is up and running, all fields are set property.\r
-     * <p>\r
-     *\r
-     * If workspacePolicy is FixErrors, there is an attempt to fix unexpected\r
-     * errors. It includes installing database files, installing ontologies, and\r
-     * installing project features.\r
-     * <p>\r
-     *\r
-     * In SWB this is handled in SimanticsWorkbenchAdvisor#openWindows().\r
-     * <p>\r
-     *\r
-     * If remote server is given, simantics plaform takes connection there\r
-     * instead of local server at "db/".\r
-     *\r
-     * @param workspacePolicy action to take on workspace/database related\r
-     *        errors\r
-     * @param ontologyPolicy action to take on ontology mismatch\r
-     * @param progressMonitor optional progress monitor\r
-     * @param userAgent interface for resorting to user feedback during platform\r
-     *        startup or <code>null</code> to resort to default measures\r
-     * @throws PlatformException\r
-     */\r
-    public SessionContext startUp(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy,\r
-            OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize, PlatformUserAgent userAgent)\r
-    throws PlatformException\r
-    {\r
-\r
-        assert(!running);\r
-        TimeLogger.log("Beginning of SimanticsPlatform.startUp");\r
-\r
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();\r
-\r
-        // For debugging on what kind of platform automatic tests are running in\r
-        // case there are problems.\r
-        if ("true".equals(System.getProperty("org.simantics.dumpBundleState")))\r
-            dumpPlatformBundleState();\r
-\r
-        // 0. Consult all startup extensions before doing anything with the workspace.\r
-        StartupExtensions.consultStartupExtensions();\r
-        TimeLogger.log("Consulted platform pre-startup extensions");\r
-\r
-        // 0.1. Clear all temporary files\r
-        Simantics.clearTemporaryDirectory();\r
-        TimeLogger.log("Cleared temporary directory");\r
-\r
-        // 0.2 Clear VariableRepository.repository static map which holds references to SessionImplDb\r
-        VariableRepository.clear();\r
-        \r
-        // 1. Assert there is a database at <workspace>/db\r
-        session = setupDatabase(databaseDriverId, progressMonitor, workspacePolicy, userAgent);\r
-        TimeLogger.log("Database setup complete");\r
-        \r
-        // 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());
+        }
+    }
+
+}
+