1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics;
\r
14 import static org.simantics.db.common.utils.Transaction.commit;
\r
15 import static org.simantics.db.common.utils.Transaction.endTransaction;
\r
16 import static org.simantics.db.common.utils.Transaction.readGraph;
\r
17 import static org.simantics.db.common.utils.Transaction.startTransaction;
\r
18 import static org.simantics.db.common.utils.Transaction.writeGraph;
\r
20 import java.io.File;
\r
21 import java.io.IOException;
\r
22 import java.util.ArrayList;
\r
23 import java.util.Collection;
\r
24 import java.util.HashMap;
\r
25 import java.util.List;
\r
26 import java.util.Map;
\r
27 import java.util.Map.Entry;
\r
28 import java.util.Properties;
\r
29 import java.util.Set;
\r
30 import java.util.TreeMap;
\r
31 import java.util.UUID;
\r
33 import org.eclipse.core.runtime.ILog;
\r
34 import org.eclipse.core.runtime.IProduct;
\r
35 import org.eclipse.core.runtime.IProgressMonitor;
\r
36 import org.eclipse.core.runtime.IStatus;
\r
37 import org.eclipse.core.runtime.NullProgressMonitor;
\r
38 import org.eclipse.core.runtime.Platform;
\r
39 import org.eclipse.core.runtime.Status;
\r
40 import org.eclipse.core.runtime.SubMonitor;
\r
41 import org.eclipse.osgi.service.resolver.BundleDescription;
\r
42 import org.simantics.databoard.Bindings;
\r
43 import org.simantics.databoard.Databoard;
\r
44 import org.simantics.datatypes.literal.Font;
\r
45 import org.simantics.datatypes.literal.RGB;
\r
46 import org.simantics.db.Driver;
\r
47 import org.simantics.db.Driver.Management;
\r
48 import org.simantics.db.Manager;
\r
49 import org.simantics.db.ReadGraph;
\r
50 import org.simantics.db.Resource;
\r
51 import org.simantics.db.Session;
\r
52 import org.simantics.db.SessionModel;
\r
53 import org.simantics.db.UndoContext;
\r
54 import org.simantics.db.VirtualGraph;
\r
55 import org.simantics.db.WriteGraph;
\r
56 import org.simantics.db.common.request.ObjectsWithType;
\r
57 import org.simantics.db.common.request.Queries;
\r
58 import org.simantics.db.common.request.WriteRequest;
\r
59 import org.simantics.db.common.request.WriteResultRequest;
\r
60 import org.simantics.db.common.utils.Transaction;
\r
61 import org.simantics.db.exception.ClusterSetExistException;
\r
62 import org.simantics.db.exception.DatabaseException;
\r
63 import org.simantics.db.exception.ResourceNotFoundException;
\r
64 import org.simantics.db.indexing.DatabaseIndexing;
\r
65 import org.simantics.db.layer0.genericrelation.DependenciesRelation;
\r
66 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
\r
67 import org.simantics.db.layer0.util.SimanticsKeys;
\r
68 import org.simantics.db.layer0.util.TGTransferableGraphSource;
\r
69 import org.simantics.db.layer0.variable.VariableRepository;
\r
70 import org.simantics.db.management.SessionContext;
\r
71 import org.simantics.db.request.Read;
\r
72 import org.simantics.db.service.LifecycleSupport.LifecycleListener;
\r
73 import org.simantics.db.service.LifecycleSupport.LifecycleState;
\r
74 import org.simantics.db.service.QueryControl;
\r
75 import org.simantics.db.service.UndoRedoSupport;
\r
76 import org.simantics.db.service.VirtualGraphSupport;
\r
77 import org.simantics.db.service.XSupport;
\r
78 import org.simantics.graph.db.GraphDependencyAnalyzer;
\r
79 import org.simantics.graph.db.GraphDependencyAnalyzer.IU;
\r
80 import org.simantics.graph.db.GraphDependencyAnalyzer.IdentityNode;
\r
81 import org.simantics.graph.db.IImportAdvisor;
\r
82 import org.simantics.graph.db.TransferableGraphs;
\r
83 import org.simantics.graph.diff.Diff;
\r
84 import org.simantics.graph.diff.TransferableGraphDelta1;
\r
85 import org.simantics.internal.Activator;
\r
86 import org.simantics.internal.startup.StartupExtensions;
\r
87 import org.simantics.layer0.Layer0;
\r
88 import org.simantics.operation.Layer0X;
\r
89 import org.simantics.project.IProject;
\r
90 import org.simantics.project.ProjectFeatures;
\r
91 import org.simantics.project.ProjectKeys;
\r
92 import org.simantics.project.Projects;
\r
93 import org.simantics.project.exception.ProjectException;
\r
94 import org.simantics.project.features.registry.GroupReference;
\r
95 import org.simantics.project.management.DatabaseManagement;
\r
96 import org.simantics.project.management.GraphBundle;
\r
97 import org.simantics.project.management.GraphBundleEx;
\r
98 import org.simantics.project.management.GraphBundleRef;
\r
99 import org.simantics.project.management.PlatformUtil;
\r
100 import org.simantics.project.management.ServerManager;
\r
101 import org.simantics.project.management.ServerManagerFactory;
\r
102 import org.simantics.project.management.WorkspaceUtil;
\r
103 import org.simantics.utils.FileUtils;
\r
104 import org.simantics.utils.datastructures.Pair;
\r
105 import org.simantics.utils.logging.TimeLogger;
\r
108 * SimanticsPlatform performs procedures required in order to get simantics
\r
109 * workbench into operational state. This consists of the following steps:
\r
111 * <li> Asserting there is Database
\r
113 * <li> Starting Database process
\r
115 * <li> Opening a session to Database process
\r
117 * <li> Asserting required ontologies or other transferable graphs are installed in the database
\r
119 * <li> Asserting required project is installed in the database
\r
121 * <li> Asserting Simantics Features are installed in the database
\r
123 * <li> Asserting Simantics Features are installed to the project
\r
125 * <li> Shutdown: Save Session, Close session, Kill Database process
\r
129 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
\r
131 public class SimanticsPlatform implements LifecycleListener {
\r
134 * The policy is relevant when developing Simantics from Eclipse IDE.
\r
135 * It is applied when the ontology in the database of a workspace doesn't match
\r
136 * a newer ontology in the Eclipse workspace.
\r
138 public static enum OntologyRecoveryPolicy { ThrowError, Merge, ReinstallDatabase }
\r
141 * This policy dictates how the Simantics platform startup should react if
\r
142 * the started workspace is not set up properly. The alternatives are to
\r
143 * just throw an error and fail or to attempt all possible measures to fix
\r
144 * the encountered problems.
\r
146 public static enum RecoveryPolicy { ThrowError, FixError }
\r
148 /** Singleton instance, started in SimanticsWorkbenchAdvisor */
\r
149 public static final SimanticsPlatform INSTANCE = new SimanticsPlatform();
\r
151 /** Set to true when the Simantics Platform is in good-and-go condition */
\r
152 public boolean running;
\r
154 /** Database Session */
\r
155 public Session session;
\r
156 private Management databasebManagement;
\r
158 /** Database session context */
\r
159 public SessionContext sessionContext;
\r
161 /** Project identifier in Database */
\r
162 public String projectURI;
\r
164 /** Project name */
\r
165 public String projectName;
\r
167 /** Project resource */
\r
168 public Resource projectResource;
\r
170 /** Session specific bindings */
\r
171 public SimanticsBindings simanticsBindings;
\r
172 public SimanticsBindings simanticsBindings2;
\r
174 public Thread mainThread;
\r
177 * The {@link IProject} activated by
\r
178 * {@link #startUp(IProgressMonitor, RecoveryPolicy, OntologyRecoveryPolicy, ServerAddress, PlatformUserAgent)}
\r
180 private IProject project;
\r
182 protected ILog log;
\r
185 * Create a new simantics plaform manager in uninitialized state and
\r
186 * with default policies. <p>
\r
188 public SimanticsPlatform() {
\r
189 log = Platform.getLog(Activator.getBundleContext().getBundle());
\r
190 mainThread = Thread.currentThread();
\r
193 public String getApplicationClientId() {
\r
194 IProduct product = Platform.getProduct();
\r
195 if(product == null) return "noProduct";//UUID.randomUUID().toString();
\r
196 String application = product.getApplication();
\r
197 return application != null ? application : UUID.randomUUID().toString();
\r
200 private Session setupDatabase(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, PlatformUserAgent userAgent) throws PlatformException {
\r
201 if (progressMonitor == null)
\r
202 progressMonitor = new NullProgressMonitor();
\r
203 File dbLocation = Platform.getLocation().append("db").toFile();
\r
204 ServerManager serverManager;
\r
206 serverManager = ServerManagerFactory.create(databaseDriverId, dbLocation.getAbsolutePath());
\r
207 } catch (DatabaseException | IOException e) {
\r
208 throw new PlatformException("Failed to initialize Server Manager", e);
\r
210 progressMonitor.beginTask("Setting up Simantics Database", 100);
\r
211 progressMonitor.setTaskName("Asserting Database is installed.");
\r
212 String msg = "Failed to initialize Simantics database.";
\r
215 log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Creating database at " + dbLocation));
\r
216 progressMonitor.setTaskName("Creating database at " + dbLocation);
\r
217 databasebManagement = serverManager.getManagement(dbLocation);
\r
218 databasebManagement.create();
\r
220 return serverManager.createDatabase(dbLocation);
\r
221 } catch (DatabaseException e) {
\r
222 throw new PlatformException(msg, e);
\r
223 } catch (Throwable e) {
\r
224 throw new PlatformException(msg, e);
\r
226 progressMonitor.worked(20);
\r
230 public void synchronizeOntologies(IProgressMonitor progressMonitor, OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize) throws PlatformException {
\r
232 if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
\r
234 final DatabaseManagement mgmt = new DatabaseManagement();
\r
236 PlatformUtil.compileAllDynamicOntologies();
\r
238 progressMonitor.setTaskName("Asserting all ontologies are installed");
\r
239 final Map<GraphBundleRef, GraphBundleEx> platformTGs = new HashMap<GraphBundleRef, GraphBundleEx>();
\r
242 // Get a list of bundles installed into the database
\r
243 progressMonitor.subTask("find installed bundles from database");
\r
244 Map<GraphBundleRef, GraphBundleEx> installedTGs = new HashMap<GraphBundleRef, GraphBundleEx>();
\r
245 for (GraphBundle b : session.syncRequest( mgmt.GraphBundleQuery )) {
\r
246 installedTGs.put(GraphBundleRef.of(b), GraphBundleEx.extend(b));
\r
249 if(!requireSynchronize && installedTGs.size() > 1 && !Platform.inDevelopmentMode()) return;
\r
250 // if(installedTGs.size() > 1) return;
\r
252 // Get a list of all bundles in the platform (Bundle Context)
\r
253 List<GraphBundle> tgs = new ArrayList<GraphBundle>();
\r
254 progressMonitor.subTask("load all transferable graphs from platform");
\r
255 PlatformUtil.getAllGraphs(tgs);
\r
256 progressMonitor.subTask("extend bundles to compile versions");
\r
257 for (GraphBundle b : tgs) {
\r
258 GraphBundleEx gbe = GraphBundleEx.extend(b);
\r
260 platformTGs.put(GraphBundleRef.of(b), gbe);
\r
263 // Compile a list of TGs that need to be installed or reinstalled in the database
\r
264 progressMonitor.subTask("check bundle reinstallation demand");
\r
265 List<GraphBundleEx> installTGs = new ArrayList<GraphBundleEx>();
\r
266 // Create list of TGs to update, <newTg, oldTg>
\r
267 Map<GraphBundleEx,GraphBundleEx> reinstallTGs = new TreeMap<GraphBundleEx,GraphBundleEx>();
\r
268 for (Entry<GraphBundleRef, GraphBundleEx> e : platformTGs.entrySet()) {
\r
269 GraphBundleRef key = e.getKey();
\r
270 GraphBundleEx platformBundle = e.getValue();
\r
271 GraphBundleEx existingBundle = installedTGs.get(key);
\r
273 // System.out.println("GraphBundleRef key=" + key.toString());
\r
275 if (existingBundle == null) {
\r
276 // Bundle did not exist in the database, put it into list of bundles to install
\r
277 installTGs.add(platformBundle);
\r
280 // Bundle exists in the database
\r
281 boolean platformBundleIsNewer = existingBundle.getVersion().compareTo(platformBundle.getVersion())<0;
\r
282 if (!platformBundleIsNewer)
\r
284 // Check hash of transferable graph to know whether to update or not.
\r
285 if (platformBundle.getHashcode() == existingBundle.getHashcode())
\r
287 System.out.println("Ontology hashcodes do not match: platform bundle="
\r
288 + platformBundle.getVersionedId() + ", hash=" + platformBundle.getHashcode()
\r
289 + "; existing bundle=" + existingBundle.getVersionedId() + ", hash=" + existingBundle.getHashcode());
\r
290 reinstallTGs.put(platformBundle, existingBundle);
\r
294 // Database is missing graphs
\r
295 if (!installTGs.isEmpty() || !reinstallTGs.isEmpty()) {
\r
296 session.getService(XSupport.class).setServiceMode(true, true);
\r
299 if (ontologyPolicy == OntologyRecoveryPolicy.ThrowError) {
\r
300 StringBuilder sb = new StringBuilder("The following graphs are not installed in the database: ");
\r
301 if (!installTGs.isEmpty()) {
\r
303 for (GraphBundleEx e : installTGs) {
\r
304 if (i>0) sb.append(", ");
\r
306 sb.append(e.toString());
\r
308 sb.append(" is missing from the database.\n");
\r
310 if (!reinstallTGs.isEmpty()) {
\r
312 for (Entry<GraphBundleEx, GraphBundleEx> e : reinstallTGs.entrySet()) {
\r
313 if (i>0) sb.append(", ");
\r
315 sb.append(e.getKey().toString());
\r
317 sb.append(" Database/Platform Bundle version mismatch.\n");
\r
319 sb.append("Hint: Use -fixErrors to install the graphs.");
\r
320 throw new PlatformException(sb.toString());
\r
322 // Reinstall database
\r
323 if (ontologyPolicy == OntologyRecoveryPolicy.ReinstallDatabase) {
\r
324 log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Reinstalling the database."));
\r
333 throw new PlatformException("Reinstalling Database, NOT IMPLEMENTED");
\r
336 if (ontologyPolicy == OntologyRecoveryPolicy.Merge) {
\r
337 progressMonitor.subTask("Merging ontology changes");
\r
338 // Sort missing TGs into install order
\r
339 GraphDependencyAnalyzer<GraphBundle> analyzer = new GraphDependencyAnalyzer<GraphBundle>();
\r
340 for(GraphBundle tg : installTGs) analyzer.addGraph(tg, tg.getGraph());
\r
341 for(GraphBundle tg : reinstallTGs.keySet()) analyzer.addGraph(tg, tg.getGraph());
\r
342 if(!analyzer.analyzeDependency()) {
\r
343 Collection<Pair<GraphBundle, GraphBundle>> problems = analyzer.getConflicts();
\r
344 StringBuilder sb = new StringBuilder();
\r
345 for (Pair<GraphBundle, GraphBundle> problem : problems) {
\r
346 sb.append("Conflict with "+problem.first+" and "+problem.second+".\n");
\r
348 throw new PlatformException(sb.toString());
\r
350 else if(!session.syncRequest( analyzer.queryExternalDependenciesSatisfied )) {
\r
351 Collection<IdentityNode> unsatisfiedDependencies = analyzer.getUnsatisfiedDependencies();
\r
352 StringBuilder sb = new StringBuilder();
\r
353 for (IdentityNode dep: unsatisfiedDependencies) {
\r
354 sb.append("Unsatisfied Dependency "+dep+". Required by\n");
\r
355 for(IU iu : GraphDependencyAnalyzer.toCollection(dep.getRequires())) {
\r
356 sb.append(" " + ((GraphBundle)iu.getId()).getId() + "\n");
\r
359 throw new PlatformException(sb.toString());
\r
362 List<GraphBundle> sortedBundles = analyzer.getSortedGraphs();
\r
363 if(!sortedBundles.isEmpty()) {
\r
365 session.syncRequest(new WriteRequest() {
\r
367 public void perform(WriteGraph graph) throws DatabaseException {
\r
369 graph.newClusterSet(graph.getRootLibrary());
\r
370 } catch (ClusterSetExistException e) {
\r
371 // Cluster set exist already, no problem.
\r
373 graph.setClusterSet4NewResource(graph.getRootLibrary());
\r
374 graph.flushCluster();
\r
378 boolean mergedOntologies = false;
\r
381 for(final GraphBundle tg : sortedBundles) {
\r
383 final IImportAdvisor advisor = new OntologyImportAdvisor(tg, mgmt);
\r
384 final GraphBundle oldTG = reinstallTGs.get(tg);
\r
388 boolean createImmutable = tg.getImmutable();
\r
389 session.getService(XSupport.class).setServiceMode(true, createImmutable);
\r
392 log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Installing "+tg.toString()+" - "+tg.getName()));
\r
393 TransferableGraphs.importGraph1(session, new TGTransferableGraphSource(tg.getGraph()), advisor, null);
\r
396 startTransaction(session, false);
\r
397 TransferableGraphDelta1 delta = new Diff(oldTG.getGraph(), tg.getGraph()).diff();
\r
398 final long[] oldResources = oldTG.getResourceArray();
\r
399 boolean changes = TransferableGraphs.hasChanges(readGraph(), oldResources, delta);
\r
402 log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Nothing to merge for "+tg.toString()));
\r
406 log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Merging new version of "+tg.toString()));
\r
408 startTransaction(session, true);
\r
414 long[] resourceArray = TransferableGraphs.applyDelta(writeGraph(), oldResources, delta);
\r
415 tg.setResourceArray(resourceArray);
\r
416 mgmt.setGraphBundleEntry(tg);
\r
418 mergedOntologies = true;
\r
419 } catch (Throwable t) {
\r
420 throw new PlatformException(t);
\r
427 session.syncRequest(new WriteRequest() {
\r
429 public void perform(WriteGraph graph) throws DatabaseException {
\r
430 graph.setClusterSet4NewResource(graph.getRootLibrary());
\r
431 graph.flushCluster();
\r
435 if (mergedOntologies)
\r
436 DatabaseIndexing.deleteAllIndexes();
\r
439 TimeLogger.log("Ontologies synchronized.");
\r
442 session.getService(XSupport.class).setServiceMode(false, false);
\r
444 progressMonitor.worked(20);
\r
445 } catch (IOException e) {
\r
446 throw new PlatformException(e);
\r
447 } catch (DatabaseException e) {
\r
448 throw new PlatformException(e);
\r
453 public boolean assertConfiguration(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy) throws PlatformException {
\r
455 if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
\r
457 File workspaceLocation = Platform.getLocation().toFile();
\r
459 boolean installProject = false;
\r
460 progressMonitor.setTaskName("Asserting simantics.cfg is installed");
\r
462 File propertyFile = new File(workspaceLocation, "simantics.cfg");
\r
463 Properties properties;
\r
465 properties = WorkspaceUtil.readProperties(propertyFile);
\r
466 } catch (IOException e) {
\r
467 if (workspacePolicy == RecoveryPolicy.ThrowError) throw new PlatformException("Could not load "+propertyFile);
\r
469 // Create a project and write Property file
\r
470 properties = new Properties();
\r
471 properties.setProperty("project_uri", "http://Projects/Development%20Project");
\r
472 properties.setProperty("project_name", "Development Project");
\r
473 WorkspaceUtil.writeProperties(propertyFile, properties);
\r
474 installProject |= true;
\r
476 projectURI = properties.getProperty("project_uri");
\r
477 projectName = properties.getProperty("project_name");
\r
478 progressMonitor.worked(10);
\r
479 } catch (IOException e) {
\r
480 throw new PlatformException(e);
\r
483 return installProject;
\r
487 public boolean assertProject(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, boolean installProject) throws PlatformException {
\r
489 if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
\r
491 final DatabaseManagement mgmt = new DatabaseManagement();
\r
493 progressMonitor.setTaskName("Asserting project resource exists in the database");
\r
495 projectResource = session.syncRequest( Queries.resource( projectURI ) );
\r
496 } catch (ResourceNotFoundException nfe) {
\r
497 // Project was not found
\r
498 if (workspacePolicy == RecoveryPolicy.ThrowError)
\r
499 throw new PlatformException("Project Resource "+projectURI+" is not found in the database.");
\r
500 // Create empty project with no features
\r
502 Transaction.startTransaction(session, true);
\r
504 // The project needs to be created mutable.
\r
505 session.getService(XSupport.class).setServiceMode(true, false);
\r
507 ArrayList<String> empty = new ArrayList<String>();
\r
508 projectResource = mgmt.createProject(projectName, empty);
\r
509 installProject |= true;
\r
511 session.getService(XSupport.class).setServiceMode(false, false);
\r
512 Transaction.commit();
\r
514 Transaction.endTransaction();
\r
516 //session.getService( LifecycleSupport.class ).save();
\r
517 } catch (DatabaseException e) {
\r
518 throw new PlatformException("Failed to create "+projectURI, e);
\r
520 } catch (DatabaseException e) {
\r
521 throw new PlatformException("Failed to create "+projectURI, e);
\r
523 progressMonitor.worked(10);
\r
525 return installProject;
\r
529 public void updateInstalledGroups(IProgressMonitor progressMonitor, boolean installProject) throws PlatformException {
\r
531 if (installProject)
\r
533 // Attach all feature groups available in platform to created project
\r
534 progressMonitor.setTaskName("Install all features");
\r
535 Set<GroupReference> publishedFeatureGroups = ProjectFeatures.getInstallGroupsOfPublishedFeatures();
\r
536 Collection<GroupReference> groupsWithoutVersion = GroupReference.stripVersions(publishedFeatureGroups);
\r
538 // final List<String> Platform_Features = new ArrayList<String>();
\r
540 // // Convert graph instances
\r
541 // Collection<TransferableGraph1> platformGraphs = new ArrayList<TransferableGraph1>();
\r
542 // for (GraphBundleEx e : platformTGs.values()) platformGraphs.add( e.getGraph() );
\r
543 // IGraph graph = Graphs.createGraph(platformGraphs);
\r
545 // Res PublishedProjectFeatures = UriUtils.uriToPath( ProjectResource.URIs.PublishedProjectFeatures );
\r
546 // Path HasFeature = UriUtils.uriToPath( ProjectResource.URIs.HasFeature );
\r
547 // for(Res feature : graph.getObjects(PublishedProjectFeatures, HasFeature)) {
\r
548 // System.out.println("Installing Project Feature: "+feature.toString());
\r
549 // Platform_Features.add( feature.toString() );
\r
553 Transaction.startTransaction(session, true);
\r
555 // for (String feature : Platform_Features) {
\r
557 // getResource(feature);
\r
558 // } catch(ResourceNotFoundException e) {
\r
559 // System.out.println(feature+" not found");
\r
561 // mgmt.installFeature(projectResource, feature);
\r
563 Projects.setProjectInstalledGroups(writeGraph(), projectResource, groupsWithoutVersion);
\r
564 Transaction.commit();
\r
566 Transaction.endTransaction();
\r
568 //session.getService( LifecycleSupport.class ).save();
\r
569 } catch(DatabaseException ae) {
\r
570 throw new PlatformException("Failed to install features", ae);
\r
572 progressMonitor.worked(10);
\r
577 public void assertSessionModel(IProgressMonitor progressMonitor) throws PlatformException {
\r
579 Properties properties = session.getService(Properties.class);
\r
580 final String clientId = properties.getProperty("clientId");
\r
584 // Currently this needs to be done before data becomes available
\r
585 VirtualGraphSupport support = session.getService(VirtualGraphSupport.class);
\r
586 VirtualGraph activations = support.getWorkspacePersistent("activations");
\r
588 Resource sessionModel = session.syncRequest(new Read<Resource>() {
\r
591 public Resource perform(ReadGraph graph) throws DatabaseException {
\r
593 Layer0X L0X = Layer0X.getInstance(graph);
\r
594 for(Resource sessionModel : graph.syncRequest(new ObjectsWithType(graph.getRootLibrary(), L0X.HasSession, L0X.Session))) {
\r
595 String id = graph.getPossibleRelatedValue(sessionModel, L0X.Session_HasClientId);
\r
596 if(id != null && id.equals(clientId)) return sessionModel;
\r
604 if(sessionModel == null) {
\r
606 sessionModel = session.syncRequest(new WriteResultRequest<Resource>(activations) {
\r
609 public Resource perform(WriteGraph graph) throws DatabaseException {
\r
610 Layer0 L0 = Layer0.getInstance(graph);
\r
611 Layer0X L0X = Layer0X.getInstance(graph);
\r
612 Resource session = graph.newResource();
\r
613 graph.claim(session, L0.InstanceOf, null, L0X.Session);
\r
614 graph.claim(session, L0X.Session_HasUser, null, graph.getResource("http://Users/AdminUser"));
\r
615 graph.addLiteral(session, L0X.Session_HasClientId, L0X.Session_HasClientId_Inverse, clientId, Bindings.STRING);
\r
616 graph.claim(graph.getRootLibrary(), L0X.HasSession, session);
\r
623 session.registerService(SessionModel.class, new PlatformSessionModel(sessionModel));
\r
624 } catch (DatabaseException e) {
\r
625 throw new PlatformException(e);
\r
630 static class PlatformSessionModel implements SessionModel {
\r
631 private final Resource sessionModel;
\r
633 public PlatformSessionModel(Resource model) {
\r
634 this.sessionModel = model;
\r
638 public Resource getResource() {
\r
639 return sessionModel;
\r
643 public void resetDatabase(IProgressMonitor monitor) throws PlatformException {
\r
644 File dbLocation = Platform.getLocation().append("db").toFile();
\r
645 if(!dbLocation.exists()) return;
\r
646 try { // Load driver
\r
647 Driver driver = Manager.getDriver("procore");
\r
648 Management management = driver.getManagement(dbLocation.getAbsolutePath(), null);
\r
649 management.delete();
\r
650 } catch (DatabaseException e) {
\r
651 throw new PlatformException("Failed to remove database at " + dbLocation.getAbsolutePath(), e);
\r
653 // We have created extra files to database folder which have to be deleted also.
\r
654 // This is an awful idea! Do not create extra files to database folder!
\r
655 Throwable t = null;
\r
656 for (int i=0; i<10; ++i) {
\r
658 FileUtils.deleteAll(dbLocation);
\r
661 } catch (IOException e) {
\r
662 // Assuming this has been thrown because delete file/folder failed.
\r
667 } catch (InterruptedException e) {
\r
668 // Ignoring interrupted exception.
\r
672 throw new PlatformException("Failed to remove database folder at " + dbLocation.getAbsolutePath(), t);
\r
674 public void resetWorkspace(IProgressMonitor monitor, ArrayList<String> fileFilter) throws PlatformException, IllegalStateException, IOException {
\r
675 File file = Platform.getLocation().toFile();
\r
676 if (null != fileFilter)
\r
677 FileUtils.deleteAllWithFilter(file , fileFilter);
\r
678 resetDatabase(monitor);
\r
682 * Start-up the platform. The procedure consists of 8 steps. Once everything
\r
683 * is up and running, all fields are set property.
\r
686 * If workspacePolicy is FixErrors, there is an attempt to fix unexpected
\r
687 * errors. It includes installing database files, installing ontologies, and
\r
688 * installing project features.
\r
691 * In SWB this is handled in SimanticsWorkbenchAdvisor#openWindows().
\r
694 * If remote server is given, simantics plaform takes connection there
\r
695 * instead of local server at "db/".
\r
697 * @param workspacePolicy action to take on workspace/database related
\r
699 * @param ontologyPolicy action to take on ontology mismatch
\r
700 * @param progressMonitor optional progress monitor
\r
701 * @param userAgent interface for resorting to user feedback during platform
\r
702 * startup or <code>null</code> to resort to default measures
\r
703 * @throws PlatformException
\r
705 public SessionContext startUp(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy,
\r
706 OntologyRecoveryPolicy ontologyPolicy, boolean requireSynchronize, PlatformUserAgent userAgent)
\r
707 throws PlatformException
\r
711 TimeLogger.log("Beginning of SimanticsPlatform.startUp");
\r
713 if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
\r
715 // For debugging on what kind of platform automatic tests are running in
\r
716 // case there are problems.
\r
717 if ("true".equals(System.getProperty("org.simantics.dumpBundleState")))
\r
718 dumpPlatformBundleState();
\r
720 // 0. Consult all startup extensions before doing anything with the workspace.
\r
721 StartupExtensions.consultStartupExtensions();
\r
722 TimeLogger.log("Consulted platform pre-startup extensions");
\r
724 // 0.1. Clear all temporary files
\r
725 Simantics.clearTemporaryDirectory();
\r
726 TimeLogger.log("Cleared temporary directory");
\r
728 // 0.2 Clear VariableRepository.repository static map which holds references to SessionImplDb
\r
729 VariableRepository.clear();
\r
731 // 1. Assert there is a database at <workspace>/db
\r
732 session = setupDatabase(databaseDriverId, progressMonitor, workspacePolicy, userAgent);
\r
733 TimeLogger.log("Database setup complete");
\r
735 // 2. Assert all graphs, and correct versions, are installed to the database
\r
736 synchronizeOntologies(progressMonitor, ontologyPolicy, requireSynchronize);
\r
737 TimeLogger.log("Synchronized ontologies");
\r
739 // 4. Assert simantics.cfg exists
\r
740 boolean installProject = assertConfiguration(progressMonitor,workspacePolicy);
\r
742 // 5. Assert Project Resource is installed in the database
\r
743 installProject = assertProject(progressMonitor, workspacePolicy, installProject);
\r
745 // 6. Install all features into project, if in debug mode
\r
746 updateInstalledGroups(progressMonitor, installProject);
\r
747 TimeLogger.log("Installed all features into project");
\r
749 // 7. Assert L0.Session in database for this session
\r
750 assertSessionModel(progressMonitor);
\r
752 session.getService(XSupport.class).setServiceMode(false, false);
\r
755 session.sync(new WriteRequest() {
\r
758 public void perform(WriteGraph graph) throws DatabaseException {
\r
759 QueryControl qc = graph.getService(QueryControl.class);
\r
764 TimeLogger.log("Flushed queries");
\r
765 } catch (DatabaseException e) {
\r
766 Logger.defaultLogError(e);
\r
768 boolean loadProject = true;
\r
771 sessionContext = SimanticsPlatform.INSTANCE.createSessionContext(true);
\r
772 // This must be before setSessionContext since some listeners might query this
\r
773 sessionContext.setHint(SimanticsKeys.KEY_PROJECT, SimanticsPlatform.INSTANCE.projectResource);
\r
775 Simantics.setSessionContext(sessionContext);
\r
777 // 1. Put ResourceBinding that throws an exception to General Bindings
\r
778 simanticsBindings = new SimanticsBindings( null );
\r
779 Bindings.classBindingFactory.addFactory( simanticsBindings );
\r
782 // 2. Create session-specific second Binding context (Databoard) and
\r
783 // put that to Session as a service
\r
784 Session session = sessionContext.getSession();
\r
785 Databoard sessionDataboard = new Databoard();
\r
786 session.registerService(Databoard.class, sessionDataboard);
\r
787 simanticsBindings2 = new SimanticsBindings( session );
\r
788 sessionDataboard.classBindingFactory.addFactory( simanticsBindings2 );
\r
790 // Register datatype bindings
\r
791 Bindings.defaultBindingFactory.getRepository().put(RGB.Integer.BINDING.type(), RGB.Integer.BINDING);
\r
792 Bindings.defaultBindingFactory.getRepository().put(Font.BINDING.type(), Font.BINDING);
\r
796 TimeLogger.log("Load projects");
\r
797 project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource);
\r
799 sessionContext.setHint(ProjectKeys.KEY_PROJECT, project);
\r
800 TimeLogger.log("Loading projects complete");
\r
802 project.activate();
\r
803 TimeLogger.log("Project activated");
\r
806 } catch (DatabaseException e) {
\r
807 Logger.defaultLogError(e);
\r
808 throw new PlatformException(e);
\r
809 } catch (ProjectException e) {
\r
810 boolean hasStackTrace = e.getStackTrace().length > 0;
\r
811 if (!hasStackTrace)
\r
812 throw new PlatformException(e.getMessage(), hasStackTrace);
\r
813 throw new PlatformException(e, hasStackTrace);
\r
818 return sessionContext;
\r
822 public SessionContext createSessionContext(boolean init) throws PlatformException {
\r
824 // Construct and initialize SessionContext from Session.
\r
825 SessionContext sessionContext = SessionContext.create(session, init);
\r
827 sessionContext.registerServices();
\r
828 return sessionContext;
\r
829 } catch (DatabaseException e) {
\r
830 throw new PlatformException(e);
\r
834 // private static File getIgnorePrerequisitesFile(URL workspaceUrl) {
\r
835 // if (workspaceUrl == null)
\r
837 // return new File(workspaceUrl.getPath(), ".ignorePrerequisites");
\r
840 // private void ensurePrerequisites(IProgressMonitor progressMonitor, PlatformUserAgent userAgent) throws PlatformException {
\r
841 // Location loc = Platform.getInstanceLocation();
\r
842 // File ignorePrerequisites = getIgnorePrerequisitesFile(loc.getURL());
\r
843 // if (loc.isSet() && ignorePrerequisites != null) {
\r
844 // if (ignorePrerequisites.exists() || ignorePrerequisites.isFile())
\r
849 // ServerEnvironment.ensureServerDependenciesMet();
\r
850 // } catch (ExecutionEnvironmentException e) {
\r
851 // // Not installed properly, ask user whether to try installation.
\r
853 // StringBuilder msg = new StringBuilder();
\r
854 // msg.append("Your system seems to be missing the following prerequisites for running this application:\n\n");
\r
855 // for (Product product : e.requiredProducts)
\r
856 // msg.append("\t" + product.getDescription() + "\n");
\r
857 // msg.append("\nYou can either install the missing components now or ignore and attempt to start the application without them. Ignore Always will ignore this question for this workspace.");
\r
858 // msg.append("\n\nSelecting Cancel will close the application.");
\r
860 // int selection = 0;
\r
861 // if (userAgent != null) {
\r
862 // selection = userAgent.showPrompt("Missing Prerequisites", msg.toString(), new String[] {
\r
863 // "Install Pre-requisites",
\r
865 // "Ignore Always",
\r
869 // boolean tryInstall = false;
\r
870 // switch (selection) {
\r
872 // tryInstall = true;
\r
875 // ignorePrerequisites.createNewFile();
\r
880 // throw new CancelStartupException();
\r
883 // if (tryInstall) {
\r
884 // // Try to install it and check for success afterwards.
\r
885 // ServerEnvironment.tryInstallDependencies(progressMonitor);
\r
886 // ServerEnvironment.ensureServerDependenciesMet();
\r
888 // } catch (InstallException ie) {
\r
889 // throw new PlatformException(ie);
\r
890 // } catch (ExecutionEnvironmentException eee) {
\r
891 // throw new PlatformException(eee);
\r
892 // } catch (IOException ie) {
\r
893 // throw new PlatformException(ie);
\r
899 * Shutdown Simantics Platform.
\r
901 * In SWB this is handled in SimanticsWorkbenchAdvisor#disconnectFromWorkspace.
\r
903 * @param progressMonitor optional progress monitor
\r
904 * @throws PlatformException
\r
906 public void shutdown(IProgressMonitor progressMonitor) throws PlatformException
\r
908 SubMonitor progress = SubMonitor.convert(progressMonitor, 100);
\r
909 PlatformException platformException = null;
\r
911 progress.subTask("Close Project");
\r
912 if (project != null) {
\r
913 project.safeDispose();
\r
915 progress.worked(10);
\r
918 progress.subTask("Close Database Session");
\r
919 Databoard databoard = null;
\r
920 if (sessionContext != null) {
\r
921 Session s = sessionContext.peekSession();
\r
923 databoard = s.peekService(Databoard.class);
\r
925 progress.subTask("Flushing Index Caches");
\r
927 Simantics.flushIndexCaches(progress.newChild(20), s);
\r
928 } catch (Throwable t) {
\r
929 Logger.defaultLogError(t);
\r
933 progress.subTask("Close Database Session");
\r
934 sessionContext.safeDispose();
\r
935 sessionContext = null;
\r
936 Simantics.setSessionContext(null);
\r
938 if (simanticsBindings != null) {
\r
939 Bindings.classBindingFactory.removeFactory( simanticsBindings );
\r
940 simanticsBindings = null;
\r
942 if (databoard != null) {
\r
943 if (simanticsBindings2 != null) {
\r
944 databoard.classBindingFactory.removeFactory( simanticsBindings2 );
\r
945 simanticsBindings2 = null;
\r
950 // Make sure Simantics clipboard doesn't store unwanted session data references.
\r
951 Simantics.setClipboard(new SimanticsClipboardImpl());
\r
953 progress.worked(30);
\r
956 projectResource = null;
\r
958 DependenciesRelation.assertFinishedTracking();
\r
960 } catch (Exception e) {
\r
961 platformException = new PlatformException("Failed to shutdown Simantics Platform", e);
\r
964 progress.worked(10);
\r
965 progress.subTask("Shutting down database");
\r
967 if (null != databasebManagement)
\r
968 databasebManagement.shutdown();
\r
969 } catch (Throwable t) {
\r
970 Logger.defaultLogError(t);
\r
972 progress.worked(10);
\r
974 progress.subTask("Clearing Workspace Temporary Directory");
\r
976 Simantics.clearTemporaryDirectory();
\r
977 } catch (Throwable t) {
\r
978 Logger.defaultLogError(t);
\r
980 progress.worked(10);
\r
981 if (null != platformException)
\r
982 throw platformException;
\r
985 // TODO: consider removing this in the future ??
\r
987 public void stateChanged(LifecycleState newState) {
\r
988 if(newState == LifecycleState.CLOSED) {
\r
990 if(Platform.isRunning()) {
\r
991 mainThread.interrupt();
\r
998 * @return <code>true</code> if discard was successful, <code>false</code>
\r
999 * if there was no session, {@link UndoRedoSupport} or
\r
1000 * {@link UndoContext} to discard through
\r
1002 public boolean discardSessionUndoHistory() {
\r
1003 Session s = session;
\r
1005 UndoRedoSupport urs = s.peekService(UndoRedoSupport.class);
\r
1006 if (urs != null) {
\r
1007 UndoContext uc = urs.getUndoContext(s);
\r
1017 public void reconnect(String databaseDriverId) throws Exception {
\r
1018 // Starts database server.
\r
1019 SimanticsPlatform.INSTANCE.startUp(databaseDriverId, null, RecoveryPolicy.ThrowError, OntologyRecoveryPolicy.ThrowError, true, null);
\r
1022 private void dumpPlatformBundleState() {
\r
1023 BundleDescription[] bs = Platform.getPlatformAdmin().getState().getBundles();
\r
1024 System.out.println("Total bundles: " + bs.length);
\r
1025 for (BundleDescription b : bs) {
\r
1026 System.out.format("%-80s @ %s\n", b.toString(), b.getLocation());
\r