X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics%2Fsrc%2Forg%2Fsimantics%2FSimanticsPlatform.java;h=8b1ac1bced1659d414c17dbf6930b11500bbed2b;hp=211b286a9401e290c0f5819bf9c5d76c035f9a5b;hb=48bb50bb6640506d1f150ca8e4fa5a6e878464be;hpb=571533bb34f06bbe3e868dd730d4cf5e793039a4 diff --git a/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java b/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java index 211b286a9..8b1ac1bce 100644 --- a/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java +++ b/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java @@ -22,9 +22,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -35,8 +32,6 @@ import java.util.Properties; import java.util.Set; import java.util.TreeMap; import java.util.UUID; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import org.eclipse.core.runtime.ILog; import org.eclipse.core.runtime.IProduct; @@ -46,6 +41,7 @@ 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; @@ -64,14 +60,15 @@ 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.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.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; @@ -101,6 +98,7 @@ 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; @@ -188,7 +186,6 @@ public class SimanticsPlatform implements LifecycleListener { /** Session specific bindings */ public SimanticsBindings simanticsBindings; - public SimanticsBindings simanticsBindings2; public Thread mainThread; @@ -229,7 +226,7 @@ public class SimanticsPlatform implements LifecycleListener { return application != null ? application : UUID.randomUUID().toString(); } - private Session setupDatabase(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, PlatformUserAgent userAgent) throws PlatformException { + 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(); @@ -268,19 +265,24 @@ public class SimanticsPlatform implements LifecycleListener { public void synchronizeOntologies(IProgressMonitor progressMonitor, OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize) throws PlatformException { - if (progressMonitor == null) progressMonitor = new NullProgressMonitor(); - - final DatabaseManagement mgmt = new DatabaseManagement(); + SubMonitor monitor = SubMonitor.convert(progressMonitor, 100); + monitor.setTaskName("Compile dynamic ontologies"); PlatformUtil.compileAllDynamicOntologies(); - progressMonitor.setTaskName("Asserting all ontologies are installed"); - final Map platformTGs = new HashMap(); + 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 - progressMonitor.subTask("find installed bundles from database"); - Map installedTGs = new HashMap(); + 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)); } @@ -289,10 +291,13 @@ public class SimanticsPlatform implements LifecycleListener { // 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"); + 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(); @@ -300,10 +305,12 @@ public class SimanticsPlatform implements LifecycleListener { } // 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(); + 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(); + Map reinstallTGs = new TreeMap<>(); for (Entry e : platformTGs.entrySet()) { GraphBundleRef key = e.getKey(); GraphBundleEx platformBundle = e.getValue(); @@ -373,7 +380,9 @@ public class SimanticsPlatform implements LifecycleListener { } if (ontologyPolicy == OntologyRecoveryPolicy.Merge) { - progressMonitor.subTask("Merging ontology changes"); + 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()); @@ -449,11 +458,9 @@ public class SimanticsPlatform implements LifecycleListener { 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); @@ -475,13 +482,10 @@ public class SimanticsPlatform implements LifecycleListener { if (mergedOntologies) DatabaseIndexing.deleteAllIndexes(); } - - TimeLogger.log("Ontologies synchronized."); - } session.getService(XSupport.class).setServiceMode(false, false); } - progressMonitor.worked(20); + monitor.worked(100); } catch (IOException e) { throw new PlatformException(e); } catch (DatabaseException e) { @@ -526,41 +530,42 @@ public class SimanticsPlatform implements LifecycleListener { public boolean assertProject(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, boolean installProject) throws PlatformException { - if (progressMonitor == null) progressMonitor = new NullProgressMonitor(); + SubMonitor monitor = SubMonitor.convert(progressMonitor, 10); final DatabaseManagement mgmt = new DatabaseManagement(); - progressMonitor.setTaskName("Asserting project resource exists in the database"); + monitor.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); + 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 { - // The project needs to be created mutable. - session.getService(XSupport.class).setServiceMode(true, false); + 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; + 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(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); } - //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); + monitor.worked(10); return installProject; @@ -691,73 +696,58 @@ public class SimanticsPlatform implements LifecycleListener { resetDatabase(monitor); } - public boolean handleBaselineDatabase() throws PlatformException { - Path workspaceLocation = Platform.getLocation().toFile().toPath(); - Path baselineIndicatorFile = workspaceLocation.resolve(".baselined"); - if (Files.isRegularFile(baselineIndicatorFile)) { - // This means that the workspace has already been initialized from - // a database baseline and further initialization is not necessary. - return true; - } + private static Path tryGetInstallLocation() { + Location l = Platform.getInstallLocation(); + return l == null ? null : new File(l.getURL().getPath()).toPath(); + } + private Path resolveBaselineFile() throws PlatformException { String dbBaselineArchive = System.getProperty("org.simantics.db.baseline", null); if (dbBaselineArchive == null) - return false; + return null; Path baseline = Paths.get(dbBaselineArchive); - if (!Files.isRegularFile(baseline)) - throw new PlatformException("Specified database baseline archive " + baseline + " does not exist. Cannot initialize workspace database."); - - validateBaselineFile(baseline); - validateWorkspaceForBaselineInitialization(workspaceLocation); - - try { - Files.createDirectories(workspaceLocation); - FileUtils.extractZip(baseline.toFile(), workspaceLocation.toFile()); - Files.write(baselineIndicatorFile, baselineIndicatorContents(baselineIndicatorFile)); - return true; - } catch (IOException e) { - throw new PlatformException(e); + if (baseline.isAbsolute()) { + if (!Files.isRegularFile(baseline)) + throw new PlatformException("Specified database baseline archive " + baseline + + " does not exist. Cannot initialize workspace database from baseline."); + return baseline; } - } - private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern("d. MMM yyyy HH:mm:ss"); - - private static byte[] baselineIndicatorContents(Path path) throws IOException { - return String.format("%s%n%s%n", - path.toString(), - Instant.now().atZone(ZoneId.systemDefault()).format(TIMESTAMP_FORMAT)) - .getBytes("UTF-8"); + // Relative path resolution order: + // 1. from the platform "install location" + // 2. from working directory + Path installLocation = tryGetInstallLocation(); + if (installLocation != null) { + Path installedBaseline = installLocation.resolve(dbBaselineArchive); + if (Files.isRegularFile(installedBaseline)) + return installedBaseline; + } + if (!Files.isRegularFile(baseline)) + throw new PlatformException("Specified database baseline archive " + baseline + + " does not exist in either the install location (" + installLocation + + ") or the working directory (" + Paths.get(".").toAbsolutePath() + + "). Cannot initialize workspace database."); + return null; } - private void validateWorkspaceForBaselineInitialization(Path workspaceLocation) throws PlatformException { - try { - Path db = workspaceLocation.resolve("db"); - if (Files.exists(db)) - throw new PlatformException("Database location " + db + " already exists. Cannot re-initialize workspace from baseline."); - Path index = workspaceLocation.resolve(".metadata/.plugins/org.simantics.db.indexing"); - if (!Files.exists(index) || !isEmptyDirectory(index)) - throw new PlatformException("Index location " + index + " already exists. Cannot re-initialize workspace from baseline."); - } catch (IOException e) { - throw new PlatformException("Failed to validate workspace for baseline initialization", e); + private boolean handleBaselineDatabase() throws PlatformException { + Path workspaceLocation = Platform.getLocation().toFile().toPath(); + Path baselineIndicatorFile = workspaceLocation.resolve(".baselined"); + if (Files.isRegularFile(baselineIndicatorFile)) { + // This means that the workspace has already been initialized from + // a database baseline and further initialization is not necessary. + return true; } - } - private static boolean isEmptyDirectory(Path dir) throws IOException { - return Files.walk(dir).count() == 1; - } + Path baseline = resolveBaselineFile(); + if (baseline == null) + return false; - private void validateBaselineFile(Path baseline) throws PlatformException { - try (ZipFile zip = new ZipFile(baseline.toFile())) { - ZipEntry db = zip.getEntry("db"); - if (db == null) - throw new PlatformException("Baseline archive does not contain database directory 'db'"); - ZipEntry index = zip.getEntry(".metadata/.plugins/org.simantics.db.indexing"); - if (index == null) - throw new PlatformException("Baseline archive does not contain database index directory '.metadata/.plugins/org.simantics.db.indexing'"); - } catch (IOException e) { - throw new PlatformException("Failed to validate baseline archive " + baseline, e); - } + DatabaseBaselines.validateBaselineFile(baseline); + DatabaseBaselines.validateWorkspaceForBaselineInitialization(workspaceLocation); + DatabaseBaselines.initializeWorkspaceWithBaseline(baseline, workspaceLocation, baselineIndicatorFile); + return true; } /** @@ -794,8 +784,8 @@ public class SimanticsPlatform implements LifecycleListener { TimeLogger.log("Beginning of SimanticsPlatform.startUp"); LOGGER.info("Beginning of SimanticsPlatform.startUp"); - - if (progressMonitor == null) progressMonitor = new NullProgressMonitor(); + + SubMonitor monitor = SubMonitor.convert(progressMonitor, 1000); // For debugging on what kind of platform automatic tests are running in // case there are problems. @@ -812,15 +802,18 @@ public class SimanticsPlatform implements LifecycleListener { // 0.2 Clear VariableRepository.repository static map which holds references to SessionImplDb VariableRepository.clear(); - + // 0.3 Handle baseline database before opening db + @SuppressWarnings("unused") boolean usingBaseline = handleBaselineDatabase(); - + // 1. Assert there is a database at /db - session = setupDatabase(databaseDriverId, progressMonitor, workspacePolicy, userAgent); + SessionDescriptor sessionDescriptor = setupDatabase(databaseDriverId, monitor.newChild(200, SubMonitor.SUPPRESS_NONE), workspacePolicy, userAgent); + session = sessionDescriptor.getSession(); TimeLogger.log("Database setup complete"); - // 1.1 + // 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 { @@ -829,29 +822,28 @@ public class SimanticsPlatform implements LifecycleListener { throw new PlatformException(e); } } - - // 2. Assert all graphs, and correct versions, are installed to the database - if(!usingBaseline) { - synchronizeOntologies(progressMonitor, ontologyPolicy, requireSynchronize); - TimeLogger.log("Synchronized ontologies"); - } + + // 3. Assert all graphs, and correct versions, are installed to the database + synchronizeOntologies(monitor.newChild(400, SubMonitor.SUPPRESS_NONE), ontologyPolicy, requireSynchronize); + TimeLogger.log("Synchronized ontologies"); // 4. Assert simantics.cfg exists - boolean installProject = assertConfiguration(progressMonitor,workspacePolicy); + boolean installProject = assertConfiguration(monitor.newChild(25, SubMonitor.SUPPRESS_NONE),workspacePolicy); // 5. Assert Project Resource is installed in the database - installProject = assertProject(progressMonitor, workspacePolicy, installProject); + installProject = assertProject(monitor.newChild(25, SubMonitor.SUPPRESS_NONE), workspacePolicy, installProject); // 6. Install all features into project, if in debug mode - updateInstalledGroups(progressMonitor, true); //installProject); + updateInstalledGroups(monitor.newChild(25), true); //installProject); TimeLogger.log("Installed all features into project"); // 7. Assert L0.Session in database for this session - assertSessionModel(progressMonitor); + assertSessionModel(monitor.newChild(25, SubMonitor.SUPPRESS_NONE)); session.getService(XSupport.class).setServiceMode(false, false); try { + monitor.setTaskName("Flush query cache"); session.syncRequest((Write) graph -> { QueryControl qc = graph.getService(QueryControl.class); qc.flush(graph); @@ -863,6 +855,7 @@ public class SimanticsPlatform implements LifecycleListener { boolean loadProject = true; try { + monitor.setTaskName("Open database session"); sessionContext = SimanticsPlatform.INSTANCE.createSessionContext(true); // This must be before setSessionContext since some listeners might query this sessionContext.setHint(SimanticsKeys.KEY_PROJECT, SimanticsPlatform.INSTANCE.projectResource); @@ -870,31 +863,38 @@ public class SimanticsPlatform implements LifecycleListener { Simantics.setSessionContext(sessionContext); // 1. Put ResourceBinding that throws an exception to General Bindings - simanticsBindings = new SimanticsBindings( null ); + simanticsBindings = new SimanticsBindings(); 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 ); + session.registerService(Databoard.class, Bindings.databoard); // 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) { + if (support.rolledback() || sessionDescriptor.isFreshDatabase()) { + monitor.setTaskName("Rebuilding all indexes"); + 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); + } - TimeLogger.log("Load projects"); + if(loadProject) { + TimeLogger.log("Load project"); + monitor.setTaskName("Load project"); project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource); - sessionContext.setHint(ProjectKeys.KEY_PROJECT, project); + monitor.worked(100); TimeLogger.log("Loading projects complete"); + monitor.setTaskName("Activate project"); project.activate(); + monitor.worked(100); TimeLogger.log("Project activated"); } @@ -975,12 +975,9 @@ public class SimanticsPlatform implements LifecycleListener { 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); @@ -998,13 +995,6 @@ public class SimanticsPlatform implements LifecycleListener { 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());