X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=inline;f=bundles%2Forg.simantics%2Fsrc%2Forg%2Fsimantics%2FSimanticsPlatform.java;h=c5ed8fd1e6374b70294bf65ecd5a4034b40b2efa;hb=refs%2Fchanges%2F73%2F4673%2F1;hp=7e6bd9dd9be5c7c134baff73223061f535ce6e92;hpb=ffdf83729b496d5afe74c7888075bb17ce1c4bbb;p=simantics%2Fplatform.git
diff --git a/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java b/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java
index 7e6bd9dd9..c5ed8fd1e 100644
--- a/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java
+++ b/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java
@@ -1,1041 +1,1137 @@
-/*******************************************************************************
- * 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;
-
-/**
- * SimanticsPlatform performs procedures required in order to get simantics
- * workbench into operational state. This consists of the following steps:
- *
- */
-public class SimanticsPlatform implements LifecycleListener {
-
- /**
- * 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.
- */
- 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 platformTGs = new HashMap();
- try {
-
- // Get a list of bundles installed into the database
- progressMonitor.subTask("find installed bundles from database");
- Map installedTGs = new HashMap();
- 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 tgs = new ArrayList();
- 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 installTGs = new ArrayList();
- // Create list of TGs to update,
- Map reinstallTGs = new TreeMap();
- for (Entry 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 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 analyzer = new GraphDependencyAnalyzer();
- for(GraphBundle tg : installTGs) analyzer.addGraph(tg, tg.getGraph());
- for(GraphBundle tg : reinstallTGs.keySet()) analyzer.addGraph(tg, tg.getGraph());
- if(!analyzer.analyzeDependency()) {
- Collection> problems = analyzer.getConflicts();
- StringBuilder sb = new StringBuilder();
- for (Pair problem : problems) {
- sb.append("Conflict with "+problem.first+" and "+problem.second+".\n");
- }
- throw new PlatformException(sb.toString());
- }
- else if(!session.syncRequest( analyzer.queryExternalDependenciesSatisfied )) {
- Collection 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 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 empty = new ArrayList();
- 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 publishedFeatureGroups = ProjectFeatures.getInstallGroupsOfPublishedFeatures();
- Collection groupsWithoutVersion = GroupReference.stripVersions(publishedFeatureGroups);
-
- // final List Platform_Features = new ArrayList();
- //
- // // Convert graph instances
- // Collection platformGraphs = new ArrayList();
- // 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() {
-
- @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(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 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.
- *
- *
- * If workspacePolicy is FixErrors, there is an attempt to fix unexpected
- * errors. It includes installing database files, installing ontologies, and
- * installing project features.
- *
- *
- * In SWB this is handled in SimanticsWorkbenchAdvisor#openWindows().
- *
- *
- * 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 null
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");
-
- 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 /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.defaultLogError(e);
- }
- boolean loadProject = true;
- try {
-
- sessionContext = SimanticsPlatform.INSTANCE.createSessionContext(true);
- // This must be before setSessionContext since some listeners might query this
- sessionContext.setHint(SimanticsKeys.KEY_PROJECT, SimanticsPlatform.INSTANCE.projectResource);
-
- Simantics.setSessionContext(sessionContext);
-
- // 1. Put ResourceBinding that throws an exception to General Bindings
- simanticsBindings = new SimanticsBindings( null );
- Bindings.classBindingFactory.addFactory( simanticsBindings );
-
-
- // 2. Create session-specific second Binding context (Databoard) and
- // put that to Session as a service
- Session session = sessionContext.getSession();
- Databoard sessionDataboard = new Databoard();
- session.registerService(Databoard.class, sessionDataboard);
- simanticsBindings2 = new SimanticsBindings( session );
- sessionDataboard.classBindingFactory.addFactory( simanticsBindings2 );
-
- // Register datatype bindings
- Bindings.defaultBindingFactory.getRepository().put(RGB.Integer.BINDING.type(), RGB.Integer.BINDING);
- Bindings.defaultBindingFactory.getRepository().put(Font.BINDING.type(), Font.BINDING);
-
- if(loadProject) {
-
- TimeLogger.log("Load projects");
- project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource);
-
- sessionContext.setHint(ProjectKeys.KEY_PROJECT, project);
- TimeLogger.log("Loading projects complete");
-
- project.activate();
- TimeLogger.log("Project activated");
- }
-
- } catch (DatabaseException e) {
- Logger.defaultLogError(e);
- throw new PlatformException(e);
- } catch (ProjectException e) {
- boolean hasStackTrace = e.getStackTrace().length > 0;
- if (!hasStackTrace)
- throw new PlatformException(e.getMessage(), hasStackTrace);
- throw new PlatformException(e, hasStackTrace);
- }
-
- running = true;
-
- return sessionContext;
-
- }
-
- public SessionContext createSessionContext(boolean init) throws PlatformException {
- try {
- // Construct and initialize SessionContext from Session.
- SessionContext sessionContext = SessionContext.create(session, init);
- if (init)
- sessionContext.registerServices();
- return sessionContext;
- } catch (DatabaseException e) {
- throw new PlatformException(e);
- }
- }
-
-// private static File getIgnorePrerequisitesFile(URL workspaceUrl) {
-// if (workspaceUrl == null)
-// return null;
-// return new File(workspaceUrl.getPath(), ".ignorePrerequisites");
-// }
-//
-// private void ensurePrerequisites(IProgressMonitor progressMonitor, PlatformUserAgent userAgent) throws PlatformException {
-// Location loc = Platform.getInstanceLocation();
-// File ignorePrerequisites = getIgnorePrerequisitesFile(loc.getURL());
-// if (loc.isSet() && ignorePrerequisites != null) {
-// if (ignorePrerequisites.exists() || ignorePrerequisites.isFile())
-// return;
-// }
-//
-// try {
-// ServerEnvironment.ensureServerDependenciesMet();
-// } catch (ExecutionEnvironmentException e) {
-// // Not installed properly, ask user whether to try installation.
-// try {
-// StringBuilder msg = new StringBuilder();
-// msg.append("Your system seems to be missing the following prerequisites for running this application:\n\n");
-// for (Product product : e.requiredProducts)
-// msg.append("\t" + product.getDescription() + "\n");
-// msg.append("\nYou can either install the missing components now or ignore and attempt to start the application without them. Ignore Always will ignore this question for this workspace.");
-// msg.append("\n\nSelecting Cancel will close the application.");
-//
-// int selection = 0;
-// if (userAgent != null) {
-// selection = userAgent.showPrompt("Missing Prerequisites", msg.toString(), new String[] {
-// "Install Pre-requisites",
-// "Ignore Now",
-// "Ignore Always",
-// "Cancel"
-// }, selection);
-// }
-// boolean tryInstall = false;
-// switch (selection) {
-// case 0:
-// tryInstall = true;
-// break;
-// case 2:
-// ignorePrerequisites.createNewFile();
-// case 1:
-// break;
-// case 3:
-// case -1:
-// throw new CancelStartupException();
-// }
-//
-// if (tryInstall) {
-// // Try to install it and check for success afterwards.
-// ServerEnvironment.tryInstallDependencies(progressMonitor);
-// ServerEnvironment.ensureServerDependenciesMet();
-// }
-// } catch (InstallException ie) {
-// throw new PlatformException(ie);
-// } catch (ExecutionEnvironmentException eee) {
-// throw new PlatformException(eee);
-// } catch (IOException ie) {
-// throw new PlatformException(ie);
-// }
-// }
-// }
-
- /**
- * Shutdown Simantics Platform.
- *
- * In SWB this is handled in SimanticsWorkbenchAdvisor#disconnectFromWorkspace.
- *
- * @param progressMonitor optional progress monitor
- * @throws PlatformException
- */
- public void shutdown(IProgressMonitor progressMonitor) throws PlatformException
- {
- SubMonitor progress = SubMonitor.convert(progressMonitor, 100);
- PlatformException platformException = null;
- try {
- progress.subTask("Close Project");
- if (project != null) {
- project.safeDispose();
- }
- progress.worked(10);
-
- running = false;
- progress.subTask("Close Database Session");
- Databoard databoard = null;
- if (sessionContext != null) {
- Session s = sessionContext.peekSession();
- if (s != null) {
- databoard = s.peekService(Databoard.class);
-
- progress.subTask("Flushing Index Caches");
- try {
- Simantics.flushIndexCaches(progress.newChild(20), s);
- } catch (Throwable t) {
- Logger.defaultLogError(t);
- }
- }
-
- progress.subTask("Close Database Session");
- sessionContext.safeDispose();
- sessionContext = null;
- Simantics.setSessionContext(null);
- }
- if (simanticsBindings != null) {
- Bindings.classBindingFactory.removeFactory( simanticsBindings );
- simanticsBindings = null;
- }
- if (databoard != null) {
- if (simanticsBindings2 != null) {
- databoard.classBindingFactory.removeFactory( simanticsBindings2 );
- simanticsBindings2 = null;
- }
- databoard.clear();
- }
-
- // Make sure Simantics clipboard doesn't store unwanted session data references.
- Simantics.setClipboard(new SimanticsClipboardImpl());
-
- progress.worked(30);
-
- session = null;
- projectResource = null;
-
- DependenciesRelation.assertFinishedTracking();
-
- } catch (Exception e) {
- platformException = new PlatformException("Failed to shutdown Simantics Platform", e);
- }
-
- progress.worked(10);
- progress.subTask("Shutting down database");
- try {
- if (null != databasebManagement)
- databasebManagement.shutdown();
- } catch (Throwable t) {
- Logger.defaultLogError(t);
- }
- progress.worked(10);
-
- progress.subTask("Clearing Workspace Temporary Directory");
- try {
- Simantics.clearTemporaryDirectory();
- } catch (Throwable t) {
- Logger.defaultLogError(t);
- }
- progress.worked(10);
- if (null != platformException)
- throw platformException;
- }
-
- // TODO: consider removing this in the future ??
- @Override
- public void stateChanged(LifecycleState newState) {
- if(newState == LifecycleState.CLOSED) {
- if(running) {
- if(Platform.isRunning()) {
- mainThread.interrupt();
- }
- }
- }
- }
-
- /**
- * @return true
if discard was successful, false
- * 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());
- }
- }
-
-}
-
+/*******************************************************************************
+ * Copyright (c) 2007, 2018 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.nio.file.Files;
+import java.nio.file.Path;
+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.datalocation.Location;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.ini4j.Ini;
+import org.ini4j.InvalidFileFormatException;
+import org.simantics.SimanticsPlatform.OntologyRecoveryPolicy;
+import org.simantics.SimanticsPlatform.RecoveryPolicy;
+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.processor.MergingDelayedWriteProcessor;
+import org.simantics.db.common.processor.MergingGraphRequestProcessor;
+import org.simantics.db.common.request.ObjectsWithType;
+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.indexing.DatabaseIndexing;
+import org.simantics.db.layer0.genericrelation.DependenciesRelation;
+import org.simantics.db.layer0.genericrelation.IndexException;
+import org.simantics.db.layer0.genericrelation.IndexedRelations;
+import org.simantics.db.layer0.request.PossibleResource;
+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.request.Write;
+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.db.services.GlobalServiceInitializer;
+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.ImportResult;
+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.TimedSessionCache;
+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.SessionDescriptor;
+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.scl.compiler.module.repository.ModuleRepository;
+import org.simantics.scl.osgi.SCLOsgi;
+import org.simantics.utils.FileUtils;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.strings.EString;
+import org.simantics.utils.threads.ExecutorWorker;
+import org.simantics.utils.threads.ThreadUtils;
+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:
+ *
+ * - Asserting there is Database
+ *
+ * - Starting Database process
+ *
+ * - Opening a session to Database process
+ *
+ * - Asserting required ontologies or other transferable graphs are installed in the database
+ *
+ * - Asserting required project is installed in the database
+ *
+ * - Asserting Simantics Features are installed in the database
+ *
+ * - Asserting Simantics Features are installed to the project
+ *
+ * - Shutdown: Save Session, Close session, Kill Database process
+ *
+ *
+ *
+ * @author Toni Kalajainen
+ */
+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, Bypass}
+
+ /**
+ * 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;
+
+ /** ID of the database driver that the platform is currently using */
+ private String currentDatabaseDriver;
+
+ /** 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 Thread mainThread;
+
+ private Thread shutdownHook = new Thread() {
+ @Override
+ public void run() {
+ try {
+ LOGGER.warn("Simantics platform was not properly shut down. Executing safety shutdown hook.");
+ shutdown(null, false);
+ } catch (PlatformException e) {
+ LOGGER.error("Simantics Platform shutdown hook execution failed.", e);
+ log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Simantics Platform shutdown hook execution failed.", e));
+ }
+ }
+ };
+
+ /**
+ * 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.
+ */
+ 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 SessionDescriptor setupDatabase(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, PlatformUserAgent userAgent) throws PlatformException {
+ if (progressMonitor == null)
+ progressMonitor = new NullProgressMonitor();
+ Path workspaceLocation = Platform.getLocation().toFile().toPath();
+ Path dbLocation = dbLocation();
+ Path dbIniPath = workspaceLocation.resolve("db.ini");
+ // The driver file overrides any command line arguments to prevent
+ // using the wrong driver for an existing database directory.
+ ServerManager serverManager;
+ try {
+ Ini dbIni = loadOrCreateDatabaseIni(dbIniPath, databaseDriverId);
+ databaseDriverId = dbIni.get("driver", "id");
+ serverManager = ServerManagerFactory.create(databaseDriverId, dbLocation.toAbsolutePath().toString());
+ } catch (DatabaseException | IOException e) {
+ throw new PlatformException("Failed to initialize database ServerManager with driver " + databaseDriverId, 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, "Initializing database at " + dbLocation + " with driver " + databaseDriverId));
+ progressMonitor.setTaskName("Creating database at " + dbLocation);
+ databasebManagement = serverManager.getManagement(dbLocation.toFile());
+ databasebManagement.create();
+ currentDatabaseDriver = databaseDriverId;
+ // Create layer0.
+ return serverManager.createDatabase(dbLocation.toFile());
+ } 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 {
+
+ SubMonitor monitor = SubMonitor.convert(progressMonitor, 100);
+
+ monitor.setTaskName("Compile dynamic ontologies");
+ PlatformUtil.compileAllDynamicOntologies();
+
+ String message = "Asserting all ontologies are installed";
+ LOGGER.info(message);
+ monitor.setTaskName(message);
+
+ DatabaseManagement mgmt = new DatabaseManagement();
+ Map platformTGs = new HashMap<>();
+ try {
+
+ // Get a list of bundles installed into the database
+ message = "find installed bundles from database";
+ monitor.subTask(message);
+ LOGGER.info(message);
+ Map installedTGs = new HashMap<>();
+ 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)
+ message = "load all transferable graphs from platform";
+ monitor.subTask(message);
+ LOGGER.info(message);
+ Collection tgs = PlatformUtil.getAllGraphs();
+ message = "extend bundles to compile versions";
+ monitor.subTask(message);
+ LOGGER.info(message);
+ 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
+ message = "check bundle reinstallation demand";
+ monitor.subTask(message);
+ LOGGER.info(message);
+ List installTGs = new ArrayList<>();
+ // Create list of TGs to update,
+ Map reinstallTGs = new TreeMap<>();
+ for (Entry 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 || ontologyPolicy == OntologyRecoveryPolicy.Bypass) {
+ 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 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.");
+ if (ontologyPolicy == OntologyRecoveryPolicy.ThrowError)
+ throw new PlatformException(sb.toString());
+ else
+ log.log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, 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");
+ }
+
+ boolean serviceModeEntered = false;
+
+ if (ontologyPolicy == OntologyRecoveryPolicy.Merge) {
+ message = "Merging ontology changes";
+ monitor.subTask(message);
+ LOGGER.info(message);
+ // Sort missing TGs into install order
+ GraphDependencyAnalyzer analyzer = new GraphDependencyAnalyzer();
+ for(GraphBundle tg : installTGs) analyzer.addGraph(tg, tg.getGraph());
+ for(GraphBundle tg : reinstallTGs.keySet()) analyzer.addGraph(tg, tg.getGraph());
+ if(!analyzer.analyzeDependency()) {
+ Collection> problems = analyzer.getConflicts();
+ StringBuilder sb = new StringBuilder();
+ for (Pair problem : problems) {
+ sb.append("Conflict with "+problem.first+" and "+problem.second+".\n");
+ }
+ throw new PlatformException(sb.toString());
+ } else if(!session.syncRequest( analyzer.queryExternalDependenciesSatisfied )) {
+ Collection 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());
+ }
+
+ message = "Analyzed graph bundles";
+ monitor.subTask(message);
+ LOGGER.info(message);
+
+ List sortedBundles = analyzer.getSortedGraphs();
+ if(!sortedBundles.isEmpty()) {
+
+ session.syncRequest((Write) graph -> {
+ 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);
+
+ boolean createImmutable = tg.getImmutable();
+
+ if (oldTG==null) {
+
+ session.getService(XSupport.class).setServiceMode(true, createImmutable);
+
+ // Flush all queries once to allow even immutable request results to be invalidated
+ // because ontology installation affects immutable content and queries related to
+ // immutable content would not get invalidated at all otherwise.
+ if (!serviceModeEntered) {
+ serviceModeEntered = true;
+ session.getService(QueryControl.class).flush();
+ }
+
+ // Install TG
+ log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Installing "+tg.toString()+" - "+tg.getName()));
+ ImportResult result = TransferableGraphs.importGraph1(session, new TGTransferableGraphSource(tg.getGraph()), advisor, null);
+ if (!result.missingExternals.isEmpty()) {
+ log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Import of " + tg.toString() + " was missing the following external entities:\n" + EString.implode(result.missingExternals)));
+ }
+ } else {
+ if(!createImmutable)
+ continue;
+
+ // 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((Write) graph -> {
+ graph.setClusterSet4NewResource(graph.getRootLibrary());
+ graph.flushCluster();
+ });
+
+ if (mergedOntologies)
+ DatabaseIndexing.deleteAllIndexes();
+ }
+ }
+ session.getService(XSupport.class).setServiceMode(false, false);
+ if (serviceModeEntered) {
+ // Flush all queries to ensure that queries that should now
+ // be immutable are not left as mutable in the query cache.
+ session.getService(QueryControl.class).flush();
+ }
+ }
+ message = "Ontologies synchronized";
+ monitor.subTask(message);
+ LOGGER.info(message);
+ monitor.worked(100);
+ } 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 {
+
+ SubMonitor monitor = SubMonitor.convert(progressMonitor, 10);
+
+ final DatabaseManagement mgmt = new DatabaseManagement();
+
+ monitor.setTaskName("Asserting project resource exists in the database");
+ try {
+ projectResource = session.syncRequest(new PossibleResource(projectURI));
+ if (projectResource == null) {
+ // 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 empty = new ArrayList();
+ 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);
+ }
+ monitor.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 publishedFeatureGroups = ProjectFeatures.getInstallGroupsOfPublishedFeatures();
+ Collection groupsWithoutVersion = GroupReference.stripVersions(publishedFeatureGroups);
+
+ try {
+ session.syncRequest(
+ (Write) graph ->
+ Projects.setProjectInstalledGroups(graph, projectResource, groupsWithoutVersion));
+ } 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() {
+
+ @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(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 {
+ // TODO: fix this to use Path APIs
+ File dbLocation = dbLocation().toFile();
+ if(!dbLocation.exists())
+ return;
+ try { // Load driver
+ Driver driver = Manager.getDriver("acorn");
+ 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 fileFilter) throws PlatformException, IllegalStateException, IOException {
+ File file = Platform.getLocation().toFile();
+ if (null != fileFilter)
+ FileUtils.deleteAllWithFilter(file , fileFilter);
+ resetDatabase(monitor);
+ }
+
+ private static Path tryGetInstallLocation() {
+ Location l = Platform.getInstallLocation();
+ return l == null ? null : new File(l.getURL().getPath()).toPath();
+ }
+
+ public Path databaseExists() {
+ Path dbLocation = dbLocation();
+ if(Files.exists(dbLocation))
+ return dbLocation;
+ return null;
+ }
+
+ public Path dbLocation() {
+ Path workspaceLocation = Platform.getLocation().toFile().toPath();
+ return workspaceLocation.resolve("db");
+ }
+
+ /**
+ * Start-up the platform. The procedure consists of 8 steps. Once everything
+ * is up and running, all fields are set property.
+ *
+ *
+ * If workspacePolicy is FixErrors, there is an attempt to fix unexpected
+ * errors. It includes installing database files, installing ontologies, and
+ * installing project features.
+ *
+ *
+ * In Simantics Workbench this is handled in
+ * SimanticsWorkbenchAdvisor#openWindows()
.
+ *
+ *
+ * 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 null
to resort to default measures
+ * @throws PlatformException
+ */
+ public synchronized SessionContext startUp(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy,
+ OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize, PlatformUserAgent userAgent)
+ throws PlatformException
+ {
+
+ assert(!running);
+ LOGGER.info("Beginning of SimanticsPlatform.startUp");
+
+ SubMonitor monitor = SubMonitor.convert(progressMonitor, 1000);
+
+ // 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();
+ LOGGER.info("Consulted platform pre-startup extensions");
+
+ // 0.1. Clear all temporary files
+ Simantics.clearTemporaryDirectory();
+ LOGGER.info("Cleared temporary directory");
+
+ // 0.2 Clear VariableRepository.repository static map which holds references to SessionImplDb
+ VariableRepository.clear();
+
+ // 0.2.1 Activate org.simantics.scl.osgi to prime the SCL compiler early.
+ @SuppressWarnings("unused")
+ ModuleRepository modRepo = SCLOsgi.MODULE_REPOSITORY;
+
+ // 0.3 Handle baseline database before opening db
+ @SuppressWarnings("unused")
+ boolean usingBaseline = DatabaseBaselines.handleBaselineDatabase(tryGetInstallLocation(), databaseExists() != null);
+
+ // 1. Assert there is a database at /db
+ SessionDescriptor sessionDescriptor = setupDatabase(databaseDriverId, monitor.newChild(200, SubMonitor.SUPPRESS_NONE), workspacePolicy, userAgent);
+ session = sessionDescriptor.getSession();
+ LOGGER.info("Database setup complete");
+
+ // 2. Delete all indexes if we cannot be certain they are up-to-date
+ // A full index rebuild will be done later, before project activation.
+ XSupport support = session.getService(XSupport.class);
+ if (support.rolledback()) {
+ try {
+ DatabaseIndexing.deleteAllIndexes();
+ } catch (IOException e) {
+ throw new PlatformException(e);
+ }
+ }
+
+ // 3. Assert all graphs, and correct versions, are installed to the database
+ synchronizeOntologies(monitor.newChild(400, SubMonitor.SUPPRESS_NONE), ontologyPolicy, requireSynchronize);
+
+ // 4. Assert simantics.cfg exists
+ boolean installProject = assertConfiguration(monitor.newChild(25, SubMonitor.SUPPRESS_NONE),workspacePolicy);
+
+ // 5. Assert Project Resource is installed in the database
+ installProject = assertProject(monitor.newChild(25, SubMonitor.SUPPRESS_NONE), workspacePolicy, installProject);
+
+ // 6. Install all features into project, if in debug mode
+ updateInstalledGroups(monitor.newChild(25), true); //installProject);
+ LOGGER.info("Installed all features into project");
+
+ // 7. Assert L0.Session in database for this session
+ assertSessionModel(monitor.newChild(25, SubMonitor.SUPPRESS_NONE));
+
+ session.getService(XSupport.class).setServiceMode(false, false);
+
+ try {
+ String message = "Flush query cache";
+ monitor.setTaskName(message);
+ LOGGER.info(message);
+ session.syncRequest((Write) graph -> {
+ QueryControl qc = graph.getService(QueryControl.class);
+ qc.flush(graph);
+ });
+ } catch (DatabaseException e) {
+ LOGGER.error("Flushing queries failed.", e);
+ }
+ boolean loadProject = true;
+ try {
+ String message = "Open database session";
+ monitor.setTaskName(message);
+ LOGGER.info(message);
+ 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
+ message = "Put ResourceBinding that throws an exception to General Bindings";
+ LOGGER.info(message);
+ simanticsBindings = new SimanticsBindings();
+ Bindings.classBindingFactory.addFactory( simanticsBindings );
+
+ Session session = sessionContext.getSession();
+ session.registerService(Databoard.class, Bindings.databoard);
+
+ // Register datatype bindings
+ message = "Register datatype bindings";
+ LOGGER.info(message);
+ Bindings.defaultBindingFactory.getRepository().put(RGB.Integer.BINDING.type(), RGB.Integer.BINDING);
+ Bindings.defaultBindingFactory.getRepository().put(Font.BINDING.type(), Font.BINDING);
+
+ if (support.rolledback() || sessionDescriptor.isFreshDatabase()) {
+ message = "Rebuilding all indexes";
+ LOGGER.info(message);
+ monitor.setTaskName(message);
+ try {
+ session.getService(IndexedRelations.class).fullRebuild(monitor.newChild(100), session);
+ } catch (IndexException e) {
+ LOGGER.error("Failed to re-build all indexes", e);
+ }
+ } else {
+ monitor.worked(100);
+ }
+
+ if(loadProject) {
+ message = "Load project";
+ monitor.setTaskName(message);
+ LOGGER.info(message);
+ project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource);
+ sessionContext.setHint(ProjectKeys.KEY_PROJECT, project);
+ monitor.worked(100);
+ message = "Loading projects complete";
+ LOGGER.info(message);
+
+ message = "Activate project";
+ monitor.setTaskName(message);
+ LOGGER.info(message);
+ project.activate();
+ monitor.worked(100);
+ LOGGER.info("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;
+
+ // #7650: improve shutdown robustness in all applications that use the platform
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
+
+ // Discard database session undo history at this point to prevent
+ // the user from undoing any initialization operations performed
+ // by the platform startup.
+ SimanticsPlatform.INSTANCE.discardSessionUndoHistory();
+ LOGGER.info("Discarded session undo history");
+
+ return sessionContext;
+
+ }
+
+ public void registerServices(SessionContext context) {
+ new GlobalServiceInitializer().initialize(session);
+ session.registerService(MergingGraphRequestProcessor.class, new MergingGraphRequestProcessor("SessionService", session, 20));
+ session.registerService(MergingDelayedWriteProcessor.class, new MergingDelayedWriteProcessor(session, 20));
+ }
+
+
+ public SessionContext createSessionContext(boolean init) throws PlatformException {
+ try {
+ // Construct and initialize SessionContext from Session.
+ SessionContext sessionContext = SessionContext.create(session, init);
+ String message = "Session context created";
+ LOGGER.info(message);
+ if (init) {
+ registerServices(sessionContext);
+ message = "Session services registered";
+ LOGGER.info(message);
+ }
+ return sessionContext;
+ } catch (DatabaseException e) {
+ throw new PlatformException(e);
+ }
+ }
+
+ /**
+ * Perform normal shutdown for the Simantics Platform.
+ *
+ * @param progressMonitor optional progress monitor
+ * @throws PlatformException
+ * @see {@link #shutdown(IProgressMonitor, boolean)}
+ */
+ public synchronized void shutdown(IProgressMonitor progressMonitor) throws PlatformException {
+ shutdown(progressMonitor, true);
+ }
+
+ /**
+ * Shutdown Simantics Platform.
+ *
+ * In Simantics Workbench this is handled in
+ * SimanticsWorkbenchAdvisor#disconnectFromWorkspace
.
+ *
+ * @param progressMonitor
+ * optional progress monitor
+ * @param clearTemporaryFiles
+ * allow or prevent deletion of temporary files at the end of the
+ * shutdown procedure
+ * @throws PlatformException
+ */
+ public synchronized void shutdown(IProgressMonitor progressMonitor, boolean clearTemporaryFiles) throws PlatformException
+ {
+ SubMonitor progress = SubMonitor.convert(progressMonitor, 100);
+ PlatformException platformException = null;
+ try {
+ progress.subTask("Close Project");
+ if (project != null) {
+ project.safeDispose();
+ }
+ progress.worked(10);
+
+ // NOP at the moment
+ TimedSessionCache.close();
+
+ progress.subTask("Thread pools");
+ ThreadUtils.shutdown();
+ ExecutorWorker.shutdown();
+ progress.worked(5);
+
+ running = false;
+ progress.subTask("Close Database Session");
+ if (sessionContext != null) {
+ Session s = sessionContext.peekSession();
+ if (s != null) {
+ 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;
+ }
+
+ // Make sure Simantics clipboard doesn't store unwanted session data references.
+ Simantics.setClipboard(new SimanticsClipboardImpl());
+
+ progress.worked(50);
+
+ session = null;
+ projectResource = null;
+ currentDatabaseDriver = 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("Clear index status");
+ try {
+ // Everything ok, clear index dirty state.
+ DatabaseIndexing.clearAllDirty();
+ } catch (IOException e) {
+ LOGGER.error("Problems encountered while refreshing database index states, see exception for details.", e);
+ }
+ progress.worked(5);
+
+ if (clearTemporaryFiles) {
+ 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;
+
+ // #7650: improve shutdown robustness in all applications that use the platform
+ Runtime.getRuntime().removeShutdownHook(shutdownHook);
+ }
+
+ // 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 true
if discard was successful, false
+ * 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.
+ if (currentDatabaseDriver != null)
+ databaseDriverId = currentDatabaseDriver;
+ 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());
+ }
+ }
+
+ private Ini loadOrCreateDatabaseIni(Path path, String databaseDriverId)
+ throws InvalidFileFormatException, IOException
+ {
+ File f = path.toFile();
+ Ini dbIni = Files.isRegularFile(path) ? new Ini(f) : new Ini();
+ String iniId = dbIni != null ? dbIni.get("driver", "id") : null;
+ if (iniId == null) {
+ dbIni.put("driver", "id", databaseDriverId);
+ dbIni.store(f);
+ }
+ return dbIni;
+ }
+
+}