From bcbe7aa23f42b82ff6fe4304943193c04858096c Mon Sep 17 00:00:00 2001 From: jsimomaa Date: Fri, 23 Sep 2016 16:14:33 +0300 Subject: [PATCH] Adding configuration logging for Simantics platform with SLF4J and Logback Adding logback.xml file to org.simantics.logback.configuration bundle for configuring logback logging refs #6705 Change-Id: I67abe04ed0d6a54b6a45fb3591bbb6b5a3991b2a --- .../.classpath | 7 + .../.project | 28 + .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 7 + .../build.properties | 5 + .../logback.xml | 18 + .../META-INF/MANIFEST.MF | 10 +- .../internal/SimanticsWorkbenchAdvisor.java | 2461 +++++++++-------- .../SimanticsWorkbenchApplication.java | 1253 +++++---- bundles/org.simantics/META-INF/MANIFEST.MF | 5 +- .../src/org/simantics/SimanticsPlatform.java | 2067 +++++++------- bundles/pom.xml | 419 +-- .../org.simantics.rcp.feature/feature.xml | 7 + 13 files changed, 3195 insertions(+), 3099 deletions(-) create mode 100644 bundles/org.simantics.logback.configuration/.classpath create mode 100644 bundles/org.simantics.logback.configuration/.project create mode 100644 bundles/org.simantics.logback.configuration/.settings/org.eclipse.jdt.core.prefs create mode 100644 bundles/org.simantics.logback.configuration/META-INF/MANIFEST.MF create mode 100644 bundles/org.simantics.logback.configuration/build.properties create mode 100644 bundles/org.simantics.logback.configuration/logback.xml diff --git a/bundles/org.simantics.logback.configuration/.classpath b/bundles/org.simantics.logback.configuration/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/bundles/org.simantics.logback.configuration/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.simantics.logback.configuration/.project b/bundles/org.simantics.logback.configuration/.project new file mode 100644 index 000000000..3fdee5609 --- /dev/null +++ b/bundles/org.simantics.logback.configuration/.project @@ -0,0 +1,28 @@ + + + org.simantics.logback.configuration + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/bundles/org.simantics.logback.configuration/.settings/org.eclipse.jdt.core.prefs b/bundles/org.simantics.logback.configuration/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/bundles/org.simantics.logback.configuration/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/bundles/org.simantics.logback.configuration/META-INF/MANIFEST.MF b/bundles/org.simantics.logback.configuration/META-INF/MANIFEST.MF new file mode 100644 index 000000000..504d772e2 --- /dev/null +++ b/bundles/org.simantics.logback.configuration/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Configuration +Bundle-SymbolicName: org.simantics.logback.configuration +Bundle-Version: 1.0.0.qualifier +Fragment-Host: ch.qos.logback.classic;bundle-version="1.1.7" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 diff --git a/bundles/org.simantics.logback.configuration/build.properties b/bundles/org.simantics.logback.configuration/build.properties new file mode 100644 index 000000000..f9c250446 --- /dev/null +++ b/bundles/org.simantics.logback.configuration/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + logback.xml diff --git a/bundles/org.simantics.logback.configuration/logback.xml b/bundles/org.simantics.logback.configuration/logback.xml new file mode 100644 index 000000000..38dc39338 --- /dev/null +++ b/bundles/org.simantics.logback.configuration/logback.xml @@ -0,0 +1,18 @@ + + + + + + + %-5p [%d] %c: %m%n%rEx + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.simantics.workbench/META-INF/MANIFEST.MF b/bundles/org.simantics.workbench/META-INF/MANIFEST.MF index 76a575878..887f49377 100644 --- a/bundles/org.simantics.workbench/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.workbench/META-INF/MANIFEST.MF @@ -6,8 +6,8 @@ Bundle-Version: 1.5.1.qualifier Bundle-Activator: org.simantics.workbench.internal.Activator Bundle-Vendor: VTT Technical Research Centre of Finland Bundle-Localization: plugin -Export-Package: org.simantics.workbench, - org.simantics.workbench.internal, +Export-Package: org.simantics.workbench, + org.simantics.workbench.internal, org.simantics.workbench.internal.contributions.search Require-Bundle: com.ibm.icu, org.eclipse.core.runtime, @@ -44,6 +44,10 @@ Require-Bundle: com.ibm.icu, org.eclipse.e4.core.di;bundle-version="1.5.0", org.eclipse.e4.ui.di;bundle-version="1.1.0", org.eclipse.e4.core.contexts, - org.eclipse.e4.ui.services + org.eclipse.e4.ui.services, + org.slf4j.api;bundle-version="1.7.20", + ch.qos.logback.classic;bundle-version="1.1.7", + ch.qos.logback.core;bundle-version="1.1.7" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy +Bundle-ClassPath: . diff --git a/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java b/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java index 67a8101cf..0bce2a568 100644 --- a/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java +++ b/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java @@ -1,1228 +1,1233 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.workbench.internal; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.text.Collator; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Map; -import java.util.TreeMap; - -import org.eclipse.core.internal.resources.Workspace; -import org.eclipse.core.net.proxy.IProxyService; -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.resources.WorkspaceJob; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.FileLocator; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IBundleGroup; -import org.eclipse.core.runtime.IBundleGroupProvider; -import org.eclipse.core.runtime.ILog; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.MultiStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.ProgressMonitorWrapper; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.e4.core.contexts.IEclipseContext; -import org.eclipse.e4.ui.internal.workbench.E4Workbench; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.dialogs.IDialogSettings; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.dialogs.TrayDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.util.Policy; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IPerspectiveDescriptor; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.application.IWorkbenchConfigurer; -import org.eclipse.ui.application.IWorkbenchWindowConfigurer; -import org.eclipse.ui.application.WorkbenchAdvisor; -import org.eclipse.ui.application.WorkbenchWindowAdvisor; -import org.eclipse.ui.ide.IDE; -import org.eclipse.ui.internal.ISelectionConversionService; -import org.eclipse.ui.internal.Workbench; -import org.eclipse.ui.internal.ide.AboutInfo; -import org.eclipse.ui.internal.ide.IDEInternalPreferences; -import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages; -import org.eclipse.ui.internal.ide.IDESelectionConversionService; -import org.eclipse.ui.internal.ide.IDEWorkbenchActivityHelper; -import org.eclipse.ui.internal.ide.IDEWorkbenchErrorHandler; -import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; -import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; -import org.eclipse.ui.internal.ide.undo.WorkspaceUndoMonitor; -import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog; -import org.eclipse.ui.keys.IBindingService; -import org.eclipse.ui.progress.IProgressService; -import org.eclipse.ui.statushandlers.AbstractStatusHandler; -import org.osgi.framework.Bundle; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.Version; -import org.simantics.CancelStartupException; -import org.simantics.PlatformException; -import org.simantics.Simantics; -import org.simantics.SimanticsPlatform; -import org.simantics.SimanticsPlatform.OntologyRecoveryPolicy; -import org.simantics.SimanticsPlatform.RecoveryPolicy; -import org.simantics.application.arguments.IArguments; -import org.simantics.application.arguments.SimanticsArguments; -import org.simantics.db.common.Indexing; -import org.simantics.db.indexing.DatabaseIndexing; -import org.simantics.db.procore.server.environment.RebootRequiredException; -import org.simantics.db.procore.server.environment.windows.Product; -import org.simantics.internal.TimedSessionCache; -import org.simantics.project.IProject; -import org.simantics.project.ProjectKeys; -import org.simantics.ui.SimanticsUI; -import org.simantics.ui.jobs.SessionGarbageCollectorJob; -import org.simantics.ui.workbench.PerspectiveBarsActivator; -import org.simantics.ui.workbench.PerspectiveContextActivator; -import org.simantics.utils.logging.TimeLogger; -import org.simantics.utils.threads.ThreadUtils; -import org.simantics.utils.ui.dialogs.ShowError; -import org.simantics.utils.ui.dialogs.ShowMessage; - - -/** - * @author Tuukka Lehtonen - */ -public class SimanticsWorkbenchAdvisor extends WorkbenchAdvisor { - - private static final boolean PROFILE_PLATFORM_STARTUP = false; - - private static final String SHUT_DOWN_TASK = "Shutting down..."; - - private static final String SHUT_DOWN_PLATFORM_TASK = "Shutting down platform..."; - - private static final String WORKBENCH_PREFERENCE_CATEGORY_ID = "org.eclipse.ui.preferencePages.Workbench"; //$NON-NLS-1$ - - /** - * The dialog setting key to access the known installed features since the - * last time the workbench was run. - */ - private static final String INSTALLED_FEATURES = "installedFeatures"; //$NON-NLS-1$ - - /** - * The arguments received by the application. - */ - protected final IArguments args; - - protected final boolean restoredPreviousSession = false; - - /** - * Only true while opening the initial windows during {@link #openWindows()}. - * Used by {@link SimanticsWorkbenchWindowAdvisor#postWindowOpen()} to - * recognize when to skip all one-time initialization. - */ - protected boolean workbenchWindowsInitialized = false; - - /** - * Whether or not to save unsaved database changes before exiting the - * workbench. - */ - protected boolean saveAtExit = false; - - /** - * Ordered map of versioned feature ids -> info that are new for this - * session; null if uninitialized. Key type: - * String, Value type: AboutInfo. - */ - private Map newlyAddedBundleGroups; - - /** - * Array of AboutInfo for all new installed features that - * specify a welcome perspective. - */ - private AboutInfo[] welcomePerspectiveInfos = null; - - /** - * Helper for managing activites in response to workspace changes. - */ - private IDEWorkbenchActivityHelper activityHelper = null; - - /** - * Helper for managing work that is performed when the system is otherwise - * idle. - */ - private IDEIdleHelper idleHelper; - - private Listener settingsChangeListener; - - /** - * Support class for monitoring workspace changes and periodically - * validating the undo history - */ - private WorkspaceUndoMonitor workspaceUndoMonitor; - - /** - * The IDE workbench error handler. - */ - private AbstractStatusHandler ideWorkbenchErrorHandler; - - /** - * Helper class used to process delayed events. - */ - private DelayedEventsProcessor delayedEventsProcessor; - - /** - * Creates a new workbench advisor instance. - * @param processor - */ - public SimanticsWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) { - super(); - this.args = args; - this.delayedEventsProcessor = processor; - - Listener closeListener = new Listener() { - public void handleEvent(Event event) { - boolean doExit = SimanticsWorkbenchWindowAdvisor.promptOnExit(null); - event.doit = doExit; - if (!doExit) - event.type = SWT.None; - } - }; - Display.getDefault().addListener(SWT.Close, closeListener); - } - - public IArguments getArguments() { - return args; - } - - public boolean workbenchInitialized() { - return workbenchWindowsInitialized; - } - - public boolean restoredPreviousSession() { - return restoredPreviousSession; - } - - boolean saveAtExit() { - return saveAtExit; - } - - void setSaveAtExit(boolean saveAtExit) { - this.saveAtExit = saveAtExit; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.application.WorkbenchAdvisor#initialize - */ - @Override - public void initialize(IWorkbenchConfigurer configurer) { - // By default, we always save and restore the workbench state. - configurer.setSaveAndRestore(true); - - checkWorkspaceDatabaseIndexes(); - - // Start tracking the active perspective to activate contexts based on it. - new PerspectiveContextActivator(); - new PerspectiveBarsActivator(); - - // register workspace adapters - IDE.registerAdapters(); - - // register shared images - declareWorkbenchImages(); - - // initialize the activity helper - activityHelper = IDEWorkbenchActivityHelper.getInstance(); - - // initialize idle handler - idleHelper = new IDEIdleHelper(configurer); - - // initialize the workspace undo monitor - workspaceUndoMonitor = WorkspaceUndoMonitor.getInstance(); - - // show Help button in JFace dialogs - TrayDialog.setDialogHelpAvailable(true); - - Policy.setComparator(Collator.getInstance()); - } - - private void checkWorkspaceDatabaseIndexes() { - try { - DatabaseIndexing.validateIndexes(); - } catch (IOException e) { - Activator.logError("Problems encountered while checking database indexes, see exception for details.", e); - } - } - - public WorkbenchWindowAdvisor createWorkbenchWindowAdvisorClass(SimanticsWorkbenchAdvisor advisor, IWorkbenchWindowConfigurer configurer) { - return new SimanticsWorkbenchWindowAdvisor(this, configurer); - } - - @Override - public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { - // Attach database session watchdog. - new SessionWatchdog().attach( Simantics.getSessionContextProvider() ); - - return createWorkbenchWindowAdvisorClass(this, configurer); - } - - /** - * For gaining direct access to super.openWindows() in implementations - * inheriting this one. - */ - public boolean openWindowsSuper() { - return super.openWindows(); - } - - /** - * Sadly we do not know why key bindings are lost and why this helps. But it - * does. Visiting the Keys preference page and pressing OK uses - * this the same call and it seems to salvage the bindings that have been in - * some cases destroyed by BindingToModelProcessor. - * - *

- * Related links: - * https://techblog.ralph-schuster.eu/2013/10/13/eclipsee4-problem-with-key-bindings/comment-page-1/ - * https://www.eclipse.org/forums/index.php/t/550175/ - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=461037 - * - * @see platform issue #6353 - */ - private void fixBindings() { - try { - IBindingService bs = PlatformUI.getWorkbench().getAdapter(IBindingService.class); - bs.savePreferences(bs.getActiveScheme(), bs.getBindings()); - } catch (IOException e) { - Activator.logError(getClass().getSimpleName() + ".fixBindings failed", e); - } - } - - @Override - public boolean openWindows() { - boolean platformOk = startPlatform(); - TimeLogger.log("SimanticsWorkbenchAdvisor.startPlatform finished"); - - if (platformOk) { - // At this point workbenchConfigurer.getSaveAndRestore() - // returns false iff something has gone terribly wrong - // before this. Currently saveAndRestore is always true. - boolean windowsOpened = super.openWindows(); - TimeLogger.log("Opened windows"); - if (windowsOpened) { - workbenchWindowsInitialized = true; - - // Start the database garbage collector after a short while. - SessionGarbageCollectorJob.getInstance().scheduleAfterQuietTime(); - - // Discard database session undo history at this point to prevent - // the user from undoing any initialization operations performed - // by the platform startup. - SimanticsPlatform.INSTANCE.discardSessionUndoHistory(); - TimeLogger.log("Discarded session undo history"); - - // #6353: Workaround for - fixBindings(); - - return true; - } - } - - // Make sure platform shutdown is ran if window opening fails. - try { - platformShutdownRunnable.run(null); - } catch (InvocationTargetException e) { - Activator.logError(getClass().getSimpleName() + ".openWindows failed", e); - } catch (InterruptedException e) { - Activator.logError(getClass().getSimpleName() + ".openWindows failed", e); - } - return false; - } - - protected boolean startPlatform() { - // Verify selected perspective - if (args.contains(SimanticsArguments.PERSPECTIVE)) { - String perspectiveId = args.get(SimanticsArguments.PERSPECTIVE); - IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(perspectiveId); - if (perspective == null) { - StringBuilder msg = new StringBuilder(); - msg.append("Requested perspective not found: '" + perspectiveId + "'\n"); - msg.append("Valid alternatives are:\n"); - for (IPerspectiveDescriptor pd : PlatformUI.getWorkbench().getPerspectiveRegistry().getPerspectives()) { - msg.append(" " + pd.getId() + "\n"); - } - - ShowMessage.syncShowError("Invalid Perspective", msg.toString()); - return false; - } - } - - ILog log = Platform.getLog(Activator.getDefault().getBundle()); - - try { - // - // - // Create Simantics Platform Helper. - // - // If Simantics is started from Eclipse IDE or with -fixerrors option, - // there is an attempt to fix errors. - // - // On ontology mismatch, there is an attempt to merge new ontology to the - // existing database. With -reinstall, the database is cleaned and - // reinstalled. - // - // - - RecoveryPolicy workspacePolicy = Platform.inDevelopmentMode() ? RecoveryPolicy.FixError : RecoveryPolicy.ThrowError; - OntologyRecoveryPolicy ontologyPolicy = Platform.inDevelopmentMode() ? OntologyRecoveryPolicy.Merge : OntologyRecoveryPolicy.ThrowError; - - if (args.contains(SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS)) { - workspacePolicy = RecoveryPolicy.FixError; - ontologyPolicy = OntologyRecoveryPolicy.Merge; - } - - boolean requireSynchronize = true; - - if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) { - ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase; - } - - if (args.contains(SimanticsArguments.DO_NOT_SYNCHRONIZE_ONTOLOGIES)) { - requireSynchronize = false; - } - - if (args.contains(SimanticsArguments.DISABLE_INDEX)) { - Indexing.setDefaultDependenciesIndexingEnabled(false); - } - - if (args.contains(SimanticsArguments.SERVER)) { - String serverAddress = args.get(SimanticsArguments.SERVER); - throw new PlatformException("Argument not supported: " + SimanticsArguments.SERVER + " " + serverAddress); - } - - String databaseDriverId = Simantics.getDefaultDatabaseDriver(); - if (args.contains(SimanticsArguments.DATABASE_ID)) { - databaseDriverId = args.get(SimanticsArguments.DATABASE_ID); - Simantics.setDefaultDatabaseDriver(databaseDriverId); - } - - IProgressMonitor mon = null; - if (PROFILE_PLATFORM_STARTUP) - mon = new TimingProgressMonitor(); - SimanticsPlatform.INSTANCE.startUp(databaseDriverId, mon, workspacePolicy, ontologyPolicy, requireSynchronize, new JFaceUserAgent()); - - // Make sure that the default perspective comes from the project if - // the project has set ProjectKeys#DEFAULT_PERSPECTIVE. - // This might go wrong if project features interact with - // PerspectiveRegistry while configuring themselves, since that will - // cause an invocation to #getInitialWindowPerspectiveId() while - // the project has not yet been properly initialized. - getWorkbenchConfigurer().getWorkbench().getPerspectiveRegistry().setDefaultPerspective(getInitialWindowPerspectiveId()); - TimeLogger.log("Completed setting default perspective"); - - return true; - } catch (CancelStartupException e) { - return false; - } catch (PlatformException e) { - boolean hasStackTrace = e.getStackTrace().length > 0; - Throwable ee = e; - while (ee.getCause() != null) { - ee = ee.getCause(); - hasStackTrace = ee.getStackTrace().length > 0; - } - - log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), hasStackTrace ? e : null)); - if (hasStackTrace) { - new ShowError("Platform Initialization Failed", "Simantics Platform initialization failed:\n\n" + e.getMessage(), e, true); - } else { - StringBuilder sb = new StringBuilder(256); - sb.append(e.getMessage()); - for (Throwable c=e.getCause(); null != c && null != c.getMessage(); c=c.getCause()) - sb.append("\ncause: ").append(c.getMessage()); - new ShowError("Startup Failed", sb.toString(), (Exception) null, true); - } - - return false; - } catch (Exception e) { - log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e)); - - Throwable cause = e.getCause(); - if (cause instanceof RebootRequiredException) { - RebootRequiredException rre = (RebootRequiredException) cause; - StringBuilder msg = new StringBuilder(); - msg.append("The application must be restarted after installing the following products:\n"); - for (Product product : rre.products) - msg.append("\t" + product + "\n"); - msg.append("\nThe application will now close."); - MessageDialog.openInformation(null, "Restart Required", msg.toString()); - } else { - new ShowError("Platform Startup Failed", "Simantics Platform startup failed:\n\n" + e.getMessage(), e, true); - } - return false; - } - - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.application.WorkbenchAdvisor#preStartup() - */ - @Override - public void preStartup() { - - // Suspend background jobs while we startup - Job.getJobManager().suspend(); - - // Register the build actions - IProgressService service = PlatformUI.getWorkbench() - .getProgressService(); - ImageDescriptor newImage = IDEInternalWorkbenchImages - .getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC); - service.registerIconForFamily(newImage, - ResourcesPlugin.FAMILY_MANUAL_BUILD); - service.registerIconForFamily(newImage, - ResourcesPlugin.FAMILY_AUTO_BUILD); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.application.WorkbenchAdvisor#postStartup() - */ - @Override - public void postStartup() { - try { - refreshFromLocal(); - activateProxyService(); - ((Workbench) PlatformUI.getWorkbench()).registerService( - ISelectionConversionService.class, - new IDESelectionConversionService()); - - initializeSettingsChangeListener(); - Display.getCurrent().addListener(SWT.Settings, - settingsChangeListener); - } finally {// Resume background jobs after we startup - Job.getJobManager().resume(); - } - } - - /** - * Activate the proxy service by obtaining it. - */ - private void activateProxyService() { - Bundle bundle = Platform.getBundle("org.eclipse.ui.ide"); //$NON-NLS-1$ - Object proxyService = null; - if (bundle != null) { - ServiceReference ref = bundle.getBundleContext().getServiceReference(IProxyService.class.getName()); - if (ref != null) - proxyService = bundle.getBundleContext().getService(ref); - } - if (proxyService == null) { - IDEWorkbenchPlugin.log("Proxy service could not be found."); //$NON-NLS-1$ - } - } - - /** - * Initialize the listener for settings changes. - */ - private void initializeSettingsChangeListener() { - settingsChangeListener = new Listener() { - - boolean currentHighContrast = Display.getCurrent() - .getHighContrast(); - - @Override - public void handleEvent(org.eclipse.swt.widgets.Event event) { - if (Display.getCurrent().getHighContrast() == currentHighContrast) - return; - - currentHighContrast = !currentHighContrast; - - // make sure they really want to do this - if (new MessageDialog(null, - IDEWorkbenchMessages.SystemSettingsChange_title, null, - IDEWorkbenchMessages.SystemSettingsChange_message, - MessageDialog.QUESTION, new String[] { - IDEWorkbenchMessages.SystemSettingsChange_yes, - IDEWorkbenchMessages.SystemSettingsChange_no }, - 1).open() == Window.OK) { - PlatformUI.getWorkbench().restart(); - } - } - }; - - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.application.WorkbenchAdvisor#postShutdown - */ - @Override - public void postShutdown() { - if (activityHelper != null) { - activityHelper.shutdown(); - activityHelper = null; - } - if (idleHelper != null) { - idleHelper.shutdown(); - idleHelper = null; - } - if (workspaceUndoMonitor != null) { - workspaceUndoMonitor.shutdown(); - workspaceUndoMonitor = null; - } - if (IDEWorkbenchPlugin.getPluginWorkspace() != null) { - disconnectFromWorkspace(); - } - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.application.WorkbenchAdvisor#preShutdown() - */ - @Override - public boolean preShutdown() { - Display.getCurrent().removeListener(SWT.Settings, - settingsChangeListener); - return super.preShutdown(); - } - - /** - * Return true if the intro plugin is present and false otherwise. - * - * @return boolean - */ - public boolean hasIntro() { - return getWorkbenchConfigurer().getWorkbench().getIntroManager() - .hasIntro(); - } - - private void refreshFromLocal() { - String[] commandLineArgs = Platform.getCommandLineArgs(); - IPreferenceStore store = IDEWorkbenchPlugin.getDefault() - .getPreferenceStore(); - boolean refresh = store - .getBoolean(IDEInternalPreferences.REFRESH_WORKSPACE_ON_STARTUP); - if (!refresh) { - return; - } - - // Do not refresh if it was already done by core on startup. - for (int i = 0; i < commandLineArgs.length; i++) { - if (commandLineArgs[i].equalsIgnoreCase("-refresh")) { //$NON-NLS-1$ - return; - } - } - - final IContainer root = ResourcesPlugin.getWorkspace().getRoot(); - Job job = new WorkspaceJob(IDEWorkbenchMessages.Workspace_refreshing) { - @Override - public IStatus runInWorkspace(IProgressMonitor monitor) - throws CoreException { - root.refreshLocal(IResource.DEPTH_INFINITE, monitor); - return Status.OK_STATUS; - } - }; - job.setRule(root); - job.schedule(); - } - - private static class CancelableProgressMonitorWrapper extends ProgressMonitorWrapper { - private double total = 0; - private ProgressMonitorJobsDialog dialog; - - CancelableProgressMonitorWrapper(IProgressMonitor monitor, - ProgressMonitorJobsDialog dialog) { - super(monitor); - this.dialog = dialog; - } - - /* - * (non-Javadoc) - * @see org.eclipse.core.runtime.ProgressMonitorWrapper#internalWorked(double) - */ - public void internalWorked(double work) { - super.internalWorked(work); - total += work; - updateProgressDetails(); - } - - /* - * (non-Javadoc) - * @see org.eclipse.core.runtime.ProgressMonitorWrapper#worked(int) - */ - public void worked(int work) { - super.worked(work); - total += work; - updateProgressDetails(); - } - - public void beginTask(String name, int totalWork) { - super.beginTask(name, totalWork); - subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_preHistoryCompaction); - } - - private void updateProgressDetails() { - if (!isCanceled() && Math.abs(total - 4.0) < 0.0001 /* right before history compacting */) { - subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_cancelHistoryPruning); - dialog.setCancelable(true); - } - if (Math.abs(total - 5.0) < 0.0001 /* history compacting finished */) { - subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_postHistoryCompaction); - dialog.setCancelable(false); - } - } - } - - private static class CancelableProgressMonitorJobsDialog extends ProgressMonitorJobsDialog { - - public CancelableProgressMonitorJobsDialog(Shell parent) { - super(parent); - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog#createDetailsButton(org.eclipse.swt.widgets.Composite) - */ - protected void createButtonsForButtonBar(Composite parent) { - super.createButtonsForButtonBar(parent); - registerCancelButtonListener(); - } - - public void registerCancelButtonListener() { - cancel.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent e) { - subTaskLabel.setText(""); //$NON-NLS-1$ - } - }); - } - } - - - final IRunnableWithProgress platformShutdownRunnable = new IRunnableWithProgress() { - /** - * @param monitor - * the progress monitor to use for reporting progress to the - * user, or null indicating that no progress - * should be reported and the operation cannot be cancelled. - */ - @Override - public void run(IProgressMonitor monitor) { - SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_PLATFORM_TASK, 100); - try { - try { - progress.subTask("Platform"); - SimanticsPlatform.INSTANCE.shutdown(progress.newChild(50)); - } catch (PlatformException e) { - Activator.logError("Problems encountered while shutting down Simantics platform, see exception for details.", e); - } - - progress.subTask("Remaining database connections"); - SimanticsUI.closeSessions(); - progress.worked(20); - TimedSessionCache.close(); - progress.worked(20); - - progress.subTask("Thread pools"); - ThreadUtils.shutdown(); - progress.worked(5); - - progress.subTask("Clear index status"); - try { - // Everything ok, clear index dirty state. - DatabaseIndexing.clearAllDirty(); - } catch (IOException e) { - Activator.logError("Problems encountered while refreshing database index states, see exception for details.", e); - } - progress.worked(5); - - progress.setWorkRemaining(0); - } finally { - if (monitor != null) { - monitor.done(); - } - } - } - }; - - /** - * Disconnect from the workspace and close ProCore sessions. - */ - private void disconnectFromWorkspace() { - // save the workspace - final MultiStatus status = new MultiStatus( - IDEWorkbenchPlugin.IDE_WORKBENCH, 1, - IDEWorkbenchMessages.ProblemSavingWorkbench, null); - - final ProgressMonitorJobsDialog p = new CancelableProgressMonitorJobsDialog( - null); - - final boolean applyPolicy = ResourcesPlugin.getWorkspace() - .getDescription().isApplyFileStatePolicy(); - - final IRunnableWithProgress workspaceShutdownRunnable = new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor monitor) { - try { - status.merge(((Workspace) ResourcesPlugin.getWorkspace()).save(true, true, monitor)); - } catch (CoreException e) { - status.merge(e.getStatus()); - } - } - }; - - IRunnableWithProgress shutdownRunnable = new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - if (applyPolicy) - monitor = new CancelableProgressMonitorWrapper( - monitor, p); - - SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_TASK, 2); - try { - workspaceShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE)); - platformShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE)); - } finally { - monitor.done(); - } - } - }; - - try { - new ProgressMonitorJobsDialog(null).run(true, false, shutdownRunnable); - } catch (InvocationTargetException e) { - status.merge(new Status(IStatus.ERROR, - IDEWorkbenchPlugin.IDE_WORKBENCH, 1, - IDEWorkbenchMessages.InternalError, e.getTargetException())); - } catch (InterruptedException e) { - status.merge(new Status(IStatus.ERROR, - IDEWorkbenchPlugin.IDE_WORKBENCH, 1, - IDEWorkbenchMessages.InternalError, e)); - } - ErrorDialog.openError(null, - IDEWorkbenchMessages.ProblemsSavingWorkspace, null, status, - IStatus.ERROR | IStatus.WARNING); - if (!status.isOK()) { - IDEWorkbenchPlugin.log( - IDEWorkbenchMessages.ProblemsSavingWorkspace, status); - } - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.application.WorkbenchAdvisor#getDefaultPageInput - */ - @Override - public IAdaptable getDefaultPageInput() { - return ResourcesPlugin.getWorkspace().getRoot(); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.application.WorkbenchAdvisor - */ - @Override - public String getInitialWindowPerspectiveId() { - int index = PlatformUI.getWorkbench().getWorkbenchWindowCount() - 1; - - String perspectiveId = null; - AboutInfo[] welcomeInfos = getWelcomePerspectiveInfos(); - if (index >= 0 && welcomeInfos != null && index < welcomeInfos.length) { - perspectiveId = welcomeInfos[index].getWelcomePerspectiveId(); - } - - if (perspectiveId == null && args.contains(SimanticsArguments.PERSPECTIVE)) { - String id = args.get(SimanticsArguments.PERSPECTIVE); - IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(id); - if (perspective != null) - perspectiveId = id; - } - - if (perspectiveId == null) { - IProject project = SimanticsUI.peekProject(); - if (project != null) - perspectiveId = project.getHint(ProjectKeys.DEFAULT_PERSPECTIVE); - } - - //System.out.println("Initial perspective: " + perspectiveId); - - return perspectiveId; - } - - /** - * Returns the map of versioned feature ids -> info object for all installed - * features. The format of the versioned feature id (the key of the map) is - * featureId + ":" + versionId. - * - * @return map of versioned feature ids -> info object (key type: - * String, value type: AboutInfo) - * @since 3.0 - */ - private Map computeBundleGroupMap() { - // use tree map to get predicable order - Map ids = new TreeMap(); - - IBundleGroupProvider[] providers = Platform.getBundleGroupProviders(); - for (int i = 0; i < providers.length; ++i) { - IBundleGroup[] groups = providers[i].getBundleGroups(); - for (int j = 0; j < groups.length; ++j) { - IBundleGroup group = groups[j]; - AboutInfo info = new AboutInfo(group); - - String version = info.getVersionId(); - version = version == null ? "0.0.0" //$NON-NLS-1$ - : new Version(version).toString(); - String versionedFeature = group.getIdentifier() + ":" + version; //$NON-NLS-1$ - - ids.put(versionedFeature, info); - } - } - - return ids; - } - - /** - * Returns the ordered map of versioned feature ids -> AboutInfo that are - * new for this session. - * - * @return ordered map of versioned feature ids (key type: - * String) -> infos (value type: - * AboutInfo). - */ - public Map getNewlyAddedBundleGroups() { - if (newlyAddedBundleGroups == null) { - newlyAddedBundleGroups = createNewBundleGroupsMap(); - } - return newlyAddedBundleGroups; - } - - /** - * Updates the old features setting and returns a map of new features. - */ - private Map createNewBundleGroupsMap() { - // retrieve list of installed bundle groups from last session - IDialogSettings settings = IDEWorkbenchPlugin.getDefault() - .getDialogSettings(); - String[] previousFeaturesArray = settings.getArray(INSTALLED_FEATURES); - - // get a map of currently installed bundle groups and store it for next - // session - Map bundleGroups = computeBundleGroupMap(); - String[] currentFeaturesArray = new String[bundleGroups.size()]; - bundleGroups.keySet().toArray(currentFeaturesArray); - settings.put(INSTALLED_FEATURES, currentFeaturesArray); - - // remove the previously known from the current set - if (previousFeaturesArray != null) { - for (int i = 0; i < previousFeaturesArray.length; ++i) { - bundleGroups.remove(previousFeaturesArray[i]); - } - } - - return bundleGroups; - } - - /** - * Declares all IDE-specific workbench images. This includes both "shared" - * images (named in {@link IDE.SharedImages}) and internal images (named in - * {@link org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages}). - * - * @see IWorkbenchConfigurer#declareImage - */ - private void declareWorkbenchImages() { - - final String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$ - final String PATH_ELOCALTOOL = ICONS_PATH + "elcl16/"; // Enabled //$NON-NLS-1$ - - // toolbar - // icons. - final String PATH_DLOCALTOOL = ICONS_PATH + "dlcl16/"; // Disabled //$NON-NLS-1$ - // //$NON-NLS-1$ - // toolbar - // icons. - final String PATH_ETOOL = ICONS_PATH + "etool16/"; // Enabled toolbar //$NON-NLS-1$ - // //$NON-NLS-1$ - // icons. - final String PATH_DTOOL = ICONS_PATH + "dtool16/"; // Disabled toolbar //$NON-NLS-1$ - // //$NON-NLS-1$ - // icons. - final String PATH_OBJECT = ICONS_PATH + "obj16/"; // Model object //$NON-NLS-1$ - // //$NON-NLS-1$ - // icons - final String PATH_WIZBAN = ICONS_PATH + "wizban/"; // Wizard //$NON-NLS-1$ - // //$NON-NLS-1$ - // icons - - Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH); - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC, PATH_ETOOL - + "build_exec.gif", false); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_HOVER, - PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED, - PATH_DTOOL + "build_exec.gif", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC, PATH_ETOOL - + "search_src.gif", false); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_HOVER, - PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_DISABLED, - PATH_DTOOL + "search_src.gif", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ETOOL_NEXT_NAV, PATH_ETOOL - + "next_nav.gif", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ETOOL_PREVIOUS_NAV, PATH_ETOOL - + "prev_nav.gif", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_WIZBAN_NEWPRJ_WIZ, PATH_WIZBAN - + "newprj_wiz.png", false); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFOLDER_WIZ, - PATH_WIZBAN + "newfolder_wiz.png", false); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFILE_WIZ, PATH_WIZBAN - + "newfile_wiz.png", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTDIR_WIZ, - PATH_WIZBAN + "importdir_wiz.png", false); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTZIP_WIZ, - PATH_WIZBAN + "importzip_wiz.png", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTDIR_WIZ, - PATH_WIZBAN + "exportdir_wiz.png", false); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTZIP_WIZ, - PATH_WIZBAN + "exportzip_wiz.png", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ, - PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN - + "saveas_wiz.png", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG, PATH_WIZBAN - + "quick_fix.png", false); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT, - PATH_OBJECT + "prj_obj.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT - + "cprj_obj.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OPEN_MARKER, - PATH_ELOCALTOOL + "gotoobj_tsk.gif", true); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ELCL_QUICK_FIX_ENABLED, - PATH_ELOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_DLCL_QUICK_FIX_DISABLED, - PATH_DLOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ - - // task objects - // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_HPRIO_TSK, - // PATH_OBJECT+"hprio_tsk.gif"); - // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_MPRIO_TSK, - // PATH_OBJECT+"mprio_tsk.gif"); - // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LPRIO_TSK, - // PATH_OBJECT+"lprio_tsk.gif"); - - declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_TASK_TSK, - PATH_OBJECT + "taskmrk_tsk.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_BKMRK_TSK, - PATH_OBJECT + "bkmrk_tsk.gif", true); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_OBJS_COMPLETE_TSK, PATH_OBJECT - + "complete_tsk.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_OBJS_INCOMPLETE_TSK, PATH_OBJECT - + "incomplete_tsk.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM, PATH_OBJECT - + "welcome_item.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER, PATH_OBJECT - + "welcome_banner.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_OBJS_ERROR_PATH, PATH_OBJECT - + "error_tsk.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_OBJS_WARNING_PATH, PATH_OBJECT - + "warn_tsk.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_OBJS_INFO_PATH, PATH_OBJECT - + "info_tsk.gif", true); //$NON-NLS-1$ - - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_LCL_FLAT_LAYOUT, PATH_ELOCALTOOL - + "flatLayout.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_LCL_HIERARCHICAL_LAYOUT, - PATH_ELOCALTOOL + "hierarchicalLayout.gif", true); //$NON-NLS-1$ - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY, - PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$ - /* - declareWorkbenchImage(ideBundle, - IDEInternalWorkbenchImages.IMG_LCL_LINKTO_HELP, PATH_ELOCALTOOL - + "linkto_help.gif", false); //$NON-NLS-1$ - */ - - // synchronization indicator objects - // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT, - // PATH_OVERLAY+"wbet_stat.gif"); - // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_SBET_STAT, - // PATH_OVERLAY+"sbet_stat.gif"); - // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_CONFLICT_STAT, - // PATH_OVERLAY+"conflict_stat.gif"); - - // content locality indicator objects - // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_NOTLOCAL_STAT, - // PATH_STAT+"notlocal_stat.gif"); - // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LOCAL_STAT, - // PATH_STAT+"local_stat.gif"); - // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_FILLLOCAL_STAT, - // PATH_STAT+"filllocal_stat.gif"); - } - - /** - * Declares an IDE-specific workbench image. - * - * @param symbolicName - * the symbolic name of the image - * @param path - * the path of the image file; this path is relative to the base - * of the IDE plug-in - * @param shared - * true if this is a shared image, and - * false if this is not a shared image - * @see IWorkbenchConfigurer#declareImage - */ - private void declareWorkbenchImage(Bundle ideBundle, String symbolicName, - String path, boolean shared) { - URL url = FileLocator.find(ideBundle, new Path(path), null); - ImageDescriptor desc = ImageDescriptor.createFromURL(url); - getWorkbenchConfigurer().declareImage(symbolicName, desc, shared); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.application.WorkbenchAdvisor#getMainPreferencePageId - */ - @Override - public String getMainPreferencePageId() { - // indicate that we want the Workench preference page to be prominent - return WORKBENCH_PREFERENCE_CATEGORY_ID; - } - - /** - * @return the workspace location string, or null if the - * location is not being shown - */ - public String getWorkspaceLocation() { - // read command line, which has priority - IEclipseContext context = getWorkbenchConfigurer().getWorkbench().getService(IEclipseContext.class); - String location = context != null ? (String) context.get(E4Workbench.FORCED_SHOW_LOCATION) : null; - if (location != null) { - return location; - } - // read the preference - if (IDEWorkbenchPlugin.getDefault().getPreferenceStore().getBoolean(IDEInternalPreferences.SHOW_LOCATION)) { - return Platform.getLocation().toOSString(); - } - return null; - } - - /** - * @return the welcome perspective infos, or null if none or - * if they should be ignored due to the new intro being present - */ - public AboutInfo[] getWelcomePerspectiveInfos() { - if (welcomePerspectiveInfos == null) { - // support old welcome perspectives if intro plugin is not present - if (!hasIntro()) { - Map m = getNewlyAddedBundleGroups(); - ArrayList list = new ArrayList(m.size()); - for (Iterator i = m.values().iterator(); i.hasNext();) { - AboutInfo info = i.next(); - if (info != null && info.getWelcomePerspectiveId() != null - && info.getWelcomePageURL() != null) { - list.add(info); - } - } - welcomePerspectiveInfos = new AboutInfo[list.size()]; - list.toArray(welcomePerspectiveInfos); - } - } - return welcomePerspectiveInfos; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.application.WorkbenchAdvisor#getWorkbenchErrorHandler() - */ - @Override - public AbstractStatusHandler getWorkbenchErrorHandler() { - if (ideWorkbenchErrorHandler == null) { - ideWorkbenchErrorHandler = new IDEWorkbenchErrorHandler( - getWorkbenchConfigurer()); - } - return ideWorkbenchErrorHandler; - } - - /* (non-Javadoc) - * @see org.eclipse.ui.application.WorkbenchAdvisor#eventLoopIdle(org.eclipse.swt.widgets.Display) - */ - @Override - public void eventLoopIdle(Display display) { - if (delayedEventsProcessor != null) - delayedEventsProcessor.catchUp(display); - super.eventLoopIdle(display); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.workbench.internal; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +import org.eclipse.core.internal.resources.Workspace; +import org.eclipse.core.net.proxy.IProxyService; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.WorkspaceJob; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IBundleGroup; +import org.eclipse.core.runtime.IBundleGroupProvider; +import org.eclipse.core.runtime.ILog; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.ProgressMonitorWrapper; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.ui.internal.workbench.E4Workbench; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.util.Policy; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IPerspectiveDescriptor; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.application.IWorkbenchConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchAdvisor; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.internal.ISelectionConversionService; +import org.eclipse.ui.internal.Workbench; +import org.eclipse.ui.internal.ide.AboutInfo; +import org.eclipse.ui.internal.ide.IDEInternalPreferences; +import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages; +import org.eclipse.ui.internal.ide.IDESelectionConversionService; +import org.eclipse.ui.internal.ide.IDEWorkbenchActivityHelper; +import org.eclipse.ui.internal.ide.IDEWorkbenchErrorHandler; +import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; +import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; +import org.eclipse.ui.internal.ide.undo.WorkspaceUndoMonitor; +import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog; +import org.eclipse.ui.keys.IBindingService; +import org.eclipse.ui.progress.IProgressService; +import org.eclipse.ui.statushandlers.AbstractStatusHandler; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.Version; +import org.simantics.CancelStartupException; +import org.simantics.PlatformException; +import org.simantics.Simantics; +import org.simantics.SimanticsPlatform; +import org.simantics.SimanticsPlatform.OntologyRecoveryPolicy; +import org.simantics.SimanticsPlatform.RecoveryPolicy; +import org.simantics.application.arguments.IArguments; +import org.simantics.application.arguments.SimanticsArguments; +import org.simantics.db.common.Indexing; +import org.simantics.db.indexing.DatabaseIndexing; +import org.simantics.db.procore.server.environment.RebootRequiredException; +import org.simantics.db.procore.server.environment.windows.Product; +import org.simantics.internal.TimedSessionCache; +import org.simantics.project.IProject; +import org.simantics.project.ProjectKeys; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.jobs.SessionGarbageCollectorJob; +import org.simantics.ui.workbench.PerspectiveBarsActivator; +import org.simantics.ui.workbench.PerspectiveContextActivator; +import org.simantics.utils.logging.TimeLogger; +import org.simantics.utils.threads.ThreadUtils; +import org.simantics.utils.ui.dialogs.ShowError; +import org.simantics.utils.ui.dialogs.ShowMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * @author Tuukka Lehtonen + */ +public class SimanticsWorkbenchAdvisor extends WorkbenchAdvisor { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimanticsWorkbenchAdvisor.class); + + private static final boolean PROFILE_PLATFORM_STARTUP = false; + + private static final String SHUT_DOWN_TASK = "Shutting down..."; + + private static final String SHUT_DOWN_PLATFORM_TASK = "Shutting down platform..."; + + private static final String WORKBENCH_PREFERENCE_CATEGORY_ID = "org.eclipse.ui.preferencePages.Workbench"; //$NON-NLS-1$ + + /** + * The dialog setting key to access the known installed features since the + * last time the workbench was run. + */ + private static final String INSTALLED_FEATURES = "installedFeatures"; //$NON-NLS-1$ + + /** + * The arguments received by the application. + */ + protected final IArguments args; + + protected final boolean restoredPreviousSession = false; + + /** + * Only true while opening the initial windows during {@link #openWindows()}. + * Used by {@link SimanticsWorkbenchWindowAdvisor#postWindowOpen()} to + * recognize when to skip all one-time initialization. + */ + protected boolean workbenchWindowsInitialized = false; + + /** + * Whether or not to save unsaved database changes before exiting the + * workbench. + */ + protected boolean saveAtExit = false; + + /** + * Ordered map of versioned feature ids -> info that are new for this + * session; null if uninitialized. Key type: + * String, Value type: AboutInfo. + */ + private Map newlyAddedBundleGroups; + + /** + * Array of AboutInfo for all new installed features that + * specify a welcome perspective. + */ + private AboutInfo[] welcomePerspectiveInfos = null; + + /** + * Helper for managing activites in response to workspace changes. + */ + private IDEWorkbenchActivityHelper activityHelper = null; + + /** + * Helper for managing work that is performed when the system is otherwise + * idle. + */ + private IDEIdleHelper idleHelper; + + private Listener settingsChangeListener; + + /** + * Support class for monitoring workspace changes and periodically + * validating the undo history + */ + private WorkspaceUndoMonitor workspaceUndoMonitor; + + /** + * The IDE workbench error handler. + */ + private AbstractStatusHandler ideWorkbenchErrorHandler; + + /** + * Helper class used to process delayed events. + */ + private DelayedEventsProcessor delayedEventsProcessor; + + /** + * Creates a new workbench advisor instance. + * @param processor + */ + public SimanticsWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) { + super(); + this.args = args; + this.delayedEventsProcessor = processor; + + Listener closeListener = new Listener() { + public void handleEvent(Event event) { + boolean doExit = SimanticsWorkbenchWindowAdvisor.promptOnExit(null); + event.doit = doExit; + if (!doExit) + event.type = SWT.None; + } + }; + Display.getDefault().addListener(SWT.Close, closeListener); + } + + public IArguments getArguments() { + return args; + } + + public boolean workbenchInitialized() { + return workbenchWindowsInitialized; + } + + public boolean restoredPreviousSession() { + return restoredPreviousSession; + } + + boolean saveAtExit() { + return saveAtExit; + } + + void setSaveAtExit(boolean saveAtExit) { + this.saveAtExit = saveAtExit; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.application.WorkbenchAdvisor#initialize + */ + @Override + public void initialize(IWorkbenchConfigurer configurer) { + // By default, we always save and restore the workbench state. + configurer.setSaveAndRestore(true); + + checkWorkspaceDatabaseIndexes(); + + // Start tracking the active perspective to activate contexts based on it. + new PerspectiveContextActivator(); + new PerspectiveBarsActivator(); + + // register workspace adapters + IDE.registerAdapters(); + + // register shared images + declareWorkbenchImages(); + + // initialize the activity helper + activityHelper = IDEWorkbenchActivityHelper.getInstance(); + + // initialize idle handler + idleHelper = new IDEIdleHelper(configurer); + + // initialize the workspace undo monitor + workspaceUndoMonitor = WorkspaceUndoMonitor.getInstance(); + + // show Help button in JFace dialogs + TrayDialog.setDialogHelpAvailable(true); + + Policy.setComparator(Collator.getInstance()); + } + + private void checkWorkspaceDatabaseIndexes() { + try { + DatabaseIndexing.validateIndexes(); + } catch (IOException e) { + Activator.logError("Problems encountered while checking database indexes, see exception for details.", e); + } + } + + public WorkbenchWindowAdvisor createWorkbenchWindowAdvisorClass(SimanticsWorkbenchAdvisor advisor, IWorkbenchWindowConfigurer configurer) { + return new SimanticsWorkbenchWindowAdvisor(this, configurer); + } + + @Override + public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { + // Attach database session watchdog. + new SessionWatchdog().attach( Simantics.getSessionContextProvider() ); + + return createWorkbenchWindowAdvisorClass(this, configurer); + } + + /** + * For gaining direct access to super.openWindows() in implementations + * inheriting this one. + */ + public boolean openWindowsSuper() { + return super.openWindows(); + } + + /** + * Sadly we do not know why key bindings are lost and why this helps. But it + * does. Visiting the Keys preference page and pressing OK uses + * this the same call and it seems to salvage the bindings that have been in + * some cases destroyed by BindingToModelProcessor. + * + *

+ * Related links: + * https://techblog.ralph-schuster.eu/2013/10/13/eclipsee4-problem-with-key-bindings/comment-page-1/ + * https://www.eclipse.org/forums/index.php/t/550175/ + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=461037 + * + * @see platform issue #6353 + */ + private void fixBindings() { + try { + IBindingService bs = PlatformUI.getWorkbench().getAdapter(IBindingService.class); + bs.savePreferences(bs.getActiveScheme(), bs.getBindings()); + } catch (IOException e) { + Activator.logError(getClass().getSimpleName() + ".fixBindings failed", e); + } + } + + @Override + public boolean openWindows() { + boolean platformOk = startPlatform(); + LOGGER.info("startPlatform finished"); + TimeLogger.log("SimanticsWorkbenchAdvisor.startPlatform finished"); + + if (platformOk) { + // At this point workbenchConfigurer.getSaveAndRestore() + // returns false iff something has gone terribly wrong + // before this. Currently saveAndRestore is always true. + boolean windowsOpened = super.openWindows(); + TimeLogger.log("Opened windows"); + if (windowsOpened) { + workbenchWindowsInitialized = true; + + // Start the database garbage collector after a short while. + SessionGarbageCollectorJob.getInstance().scheduleAfterQuietTime(); + + // Discard database session undo history at this point to prevent + // the user from undoing any initialization operations performed + // by the platform startup. + SimanticsPlatform.INSTANCE.discardSessionUndoHistory(); + TimeLogger.log("Discarded session undo history"); + + // #6353: Workaround for + fixBindings(); + + return true; + } + } + + // Make sure platform shutdown is ran if window opening fails. + try { + platformShutdownRunnable.run(null); + } catch (InvocationTargetException e) { + Activator.logError(getClass().getSimpleName() + ".openWindows failed", e); + } catch (InterruptedException e) { + Activator.logError(getClass().getSimpleName() + ".openWindows failed", e); + } + return false; + } + + protected boolean startPlatform() { + // Verify selected perspective + if (args.contains(SimanticsArguments.PERSPECTIVE)) { + String perspectiveId = args.get(SimanticsArguments.PERSPECTIVE); + IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(perspectiveId); + if (perspective == null) { + StringBuilder msg = new StringBuilder(); + msg.append("Requested perspective not found: '" + perspectiveId + "'\n"); + msg.append("Valid alternatives are:\n"); + for (IPerspectiveDescriptor pd : PlatformUI.getWorkbench().getPerspectiveRegistry().getPerspectives()) { + msg.append(" " + pd.getId() + "\n"); + } + + ShowMessage.syncShowError("Invalid Perspective", msg.toString()); + return false; + } + } + + ILog log = Platform.getLog(Activator.getDefault().getBundle()); + + try { + // + // + // Create Simantics Platform Helper. + // + // If Simantics is started from Eclipse IDE or with -fixerrors option, + // there is an attempt to fix errors. + // + // On ontology mismatch, there is an attempt to merge new ontology to the + // existing database. With -reinstall, the database is cleaned and + // reinstalled. + // + // + + RecoveryPolicy workspacePolicy = Platform.inDevelopmentMode() ? RecoveryPolicy.FixError : RecoveryPolicy.ThrowError; + OntologyRecoveryPolicy ontologyPolicy = Platform.inDevelopmentMode() ? OntologyRecoveryPolicy.Merge : OntologyRecoveryPolicy.ThrowError; + + if (args.contains(SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS)) { + workspacePolicy = RecoveryPolicy.FixError; + ontologyPolicy = OntologyRecoveryPolicy.Merge; + } + + boolean requireSynchronize = true; + + if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) { + ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase; + } + + if (args.contains(SimanticsArguments.DO_NOT_SYNCHRONIZE_ONTOLOGIES)) { + requireSynchronize = false; + } + + if (args.contains(SimanticsArguments.DISABLE_INDEX)) { + Indexing.setDefaultDependenciesIndexingEnabled(false); + } + + if (args.contains(SimanticsArguments.SERVER)) { + String serverAddress = args.get(SimanticsArguments.SERVER); + throw new PlatformException("Argument not supported: " + SimanticsArguments.SERVER + " " + serverAddress); + } + + String databaseDriverId = Simantics.getDefaultDatabaseDriver(); + if (args.contains(SimanticsArguments.DATABASE_ID)) { + databaseDriverId = args.get(SimanticsArguments.DATABASE_ID); + Simantics.setDefaultDatabaseDriver(databaseDriverId); + } + + IProgressMonitor mon = null; + if (PROFILE_PLATFORM_STARTUP) + mon = new TimingProgressMonitor(); + SimanticsPlatform.INSTANCE.startUp(databaseDriverId, mon, workspacePolicy, ontologyPolicy, requireSynchronize, new JFaceUserAgent()); + + // Make sure that the default perspective comes from the project if + // the project has set ProjectKeys#DEFAULT_PERSPECTIVE. + // This might go wrong if project features interact with + // PerspectiveRegistry while configuring themselves, since that will + // cause an invocation to #getInitialWindowPerspectiveId() while + // the project has not yet been properly initialized. + getWorkbenchConfigurer().getWorkbench().getPerspectiveRegistry().setDefaultPerspective(getInitialWindowPerspectiveId()); + TimeLogger.log("Completed setting default perspective"); + + return true; + } catch (CancelStartupException e) { + return false; + } catch (PlatformException e) { + boolean hasStackTrace = e.getStackTrace().length > 0; + Throwable ee = e; + while (ee.getCause() != null) { + ee = ee.getCause(); + hasStackTrace = ee.getStackTrace().length > 0; + } + + log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), hasStackTrace ? e : null)); + if (hasStackTrace) { + new ShowError("Platform Initialization Failed", "Simantics Platform initialization failed:\n\n" + e.getMessage(), e, true); + } else { + StringBuilder sb = new StringBuilder(256); + sb.append(e.getMessage()); + for (Throwable c=e.getCause(); null != c && null != c.getMessage(); c=c.getCause()) + sb.append("\ncause: ").append(c.getMessage()); + new ShowError("Startup Failed", sb.toString(), (Exception) null, true); + } + + return false; + } catch (Exception e) { + log.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e)); + + Throwable cause = e.getCause(); + if (cause instanceof RebootRequiredException) { + RebootRequiredException rre = (RebootRequiredException) cause; + StringBuilder msg = new StringBuilder(); + msg.append("The application must be restarted after installing the following products:\n"); + for (Product product : rre.products) + msg.append("\t" + product + "\n"); + msg.append("\nThe application will now close."); + MessageDialog.openInformation(null, "Restart Required", msg.toString()); + } else { + new ShowError("Platform Startup Failed", "Simantics Platform startup failed:\n\n" + e.getMessage(), e, true); + } + return false; + } + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.application.WorkbenchAdvisor#preStartup() + */ + @Override + public void preStartup() { + + // Suspend background jobs while we startup + Job.getJobManager().suspend(); + + // Register the build actions + IProgressService service = PlatformUI.getWorkbench() + .getProgressService(); + ImageDescriptor newImage = IDEInternalWorkbenchImages + .getImageDescriptor(IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC); + service.registerIconForFamily(newImage, + ResourcesPlugin.FAMILY_MANUAL_BUILD); + service.registerIconForFamily(newImage, + ResourcesPlugin.FAMILY_AUTO_BUILD); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.application.WorkbenchAdvisor#postStartup() + */ + @Override + public void postStartup() { + try { + refreshFromLocal(); + activateProxyService(); + ((Workbench) PlatformUI.getWorkbench()).registerService( + ISelectionConversionService.class, + new IDESelectionConversionService()); + + initializeSettingsChangeListener(); + Display.getCurrent().addListener(SWT.Settings, + settingsChangeListener); + } finally {// Resume background jobs after we startup + Job.getJobManager().resume(); + } + } + + /** + * Activate the proxy service by obtaining it. + */ + private void activateProxyService() { + Bundle bundle = Platform.getBundle("org.eclipse.ui.ide"); //$NON-NLS-1$ + Object proxyService = null; + if (bundle != null) { + ServiceReference ref = bundle.getBundleContext().getServiceReference(IProxyService.class.getName()); + if (ref != null) + proxyService = bundle.getBundleContext().getService(ref); + } + if (proxyService == null) { + IDEWorkbenchPlugin.log("Proxy service could not be found."); //$NON-NLS-1$ + } + } + + /** + * Initialize the listener for settings changes. + */ + private void initializeSettingsChangeListener() { + settingsChangeListener = new Listener() { + + boolean currentHighContrast = Display.getCurrent() + .getHighContrast(); + + @Override + public void handleEvent(org.eclipse.swt.widgets.Event event) { + if (Display.getCurrent().getHighContrast() == currentHighContrast) + return; + + currentHighContrast = !currentHighContrast; + + // make sure they really want to do this + if (new MessageDialog(null, + IDEWorkbenchMessages.SystemSettingsChange_title, null, + IDEWorkbenchMessages.SystemSettingsChange_message, + MessageDialog.QUESTION, new String[] { + IDEWorkbenchMessages.SystemSettingsChange_yes, + IDEWorkbenchMessages.SystemSettingsChange_no }, + 1).open() == Window.OK) { + PlatformUI.getWorkbench().restart(); + } + } + }; + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.application.WorkbenchAdvisor#postShutdown + */ + @Override + public void postShutdown() { + if (activityHelper != null) { + activityHelper.shutdown(); + activityHelper = null; + } + if (idleHelper != null) { + idleHelper.shutdown(); + idleHelper = null; + } + if (workspaceUndoMonitor != null) { + workspaceUndoMonitor.shutdown(); + workspaceUndoMonitor = null; + } + if (IDEWorkbenchPlugin.getPluginWorkspace() != null) { + disconnectFromWorkspace(); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.application.WorkbenchAdvisor#preShutdown() + */ + @Override + public boolean preShutdown() { + Display.getCurrent().removeListener(SWT.Settings, + settingsChangeListener); + return super.preShutdown(); + } + + /** + * Return true if the intro plugin is present and false otherwise. + * + * @return boolean + */ + public boolean hasIntro() { + return getWorkbenchConfigurer().getWorkbench().getIntroManager() + .hasIntro(); + } + + private void refreshFromLocal() { + String[] commandLineArgs = Platform.getCommandLineArgs(); + IPreferenceStore store = IDEWorkbenchPlugin.getDefault() + .getPreferenceStore(); + boolean refresh = store + .getBoolean(IDEInternalPreferences.REFRESH_WORKSPACE_ON_STARTUP); + if (!refresh) { + return; + } + + // Do not refresh if it was already done by core on startup. + for (int i = 0; i < commandLineArgs.length; i++) { + if (commandLineArgs[i].equalsIgnoreCase("-refresh")) { //$NON-NLS-1$ + return; + } + } + + final IContainer root = ResourcesPlugin.getWorkspace().getRoot(); + Job job = new WorkspaceJob(IDEWorkbenchMessages.Workspace_refreshing) { + @Override + public IStatus runInWorkspace(IProgressMonitor monitor) + throws CoreException { + root.refreshLocal(IResource.DEPTH_INFINITE, monitor); + return Status.OK_STATUS; + } + }; + job.setRule(root); + job.schedule(); + } + + private static class CancelableProgressMonitorWrapper extends ProgressMonitorWrapper { + private double total = 0; + private ProgressMonitorJobsDialog dialog; + + CancelableProgressMonitorWrapper(IProgressMonitor monitor, + ProgressMonitorJobsDialog dialog) { + super(monitor); + this.dialog = dialog; + } + + /* + * (non-Javadoc) + * @see org.eclipse.core.runtime.ProgressMonitorWrapper#internalWorked(double) + */ + public void internalWorked(double work) { + super.internalWorked(work); + total += work; + updateProgressDetails(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.core.runtime.ProgressMonitorWrapper#worked(int) + */ + public void worked(int work) { + super.worked(work); + total += work; + updateProgressDetails(); + } + + public void beginTask(String name, int totalWork) { + super.beginTask(name, totalWork); + subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_preHistoryCompaction); + } + + private void updateProgressDetails() { + if (!isCanceled() && Math.abs(total - 4.0) < 0.0001 /* right before history compacting */) { + subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_cancelHistoryPruning); + dialog.setCancelable(true); + } + if (Math.abs(total - 5.0) < 0.0001 /* history compacting finished */) { + subTask(IDEWorkbenchMessages.IDEWorkbenchAdvisor_postHistoryCompaction); + dialog.setCancelable(false); + } + } + } + + private static class CancelableProgressMonitorJobsDialog extends ProgressMonitorJobsDialog { + + public CancelableProgressMonitorJobsDialog(Shell parent) { + super(parent); + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog#createDetailsButton(org.eclipse.swt.widgets.Composite) + */ + protected void createButtonsForButtonBar(Composite parent) { + super.createButtonsForButtonBar(parent); + registerCancelButtonListener(); + } + + public void registerCancelButtonListener() { + cancel.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + subTaskLabel.setText(""); //$NON-NLS-1$ + } + }); + } + } + + + final IRunnableWithProgress platformShutdownRunnable = new IRunnableWithProgress() { + /** + * @param monitor + * the progress monitor to use for reporting progress to the + * user, or null indicating that no progress + * should be reported and the operation cannot be cancelled. + */ + @Override + public void run(IProgressMonitor monitor) { + SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_PLATFORM_TASK, 100); + try { + try { + progress.subTask("Platform"); + SimanticsPlatform.INSTANCE.shutdown(progress.newChild(50)); + } catch (PlatformException e) { + Activator.logError("Problems encountered while shutting down Simantics platform, see exception for details.", e); + } + + progress.subTask("Remaining database connections"); + SimanticsUI.closeSessions(); + progress.worked(20); + TimedSessionCache.close(); + progress.worked(20); + + progress.subTask("Thread pools"); + ThreadUtils.shutdown(); + progress.worked(5); + + progress.subTask("Clear index status"); + try { + // Everything ok, clear index dirty state. + DatabaseIndexing.clearAllDirty(); + } catch (IOException e) { + Activator.logError("Problems encountered while refreshing database index states, see exception for details.", e); + } + progress.worked(5); + + progress.setWorkRemaining(0); + } finally { + if (monitor != null) { + monitor.done(); + } + } + } + }; + + /** + * Disconnect from the workspace and close ProCore sessions. + */ + private void disconnectFromWorkspace() { + // save the workspace + final MultiStatus status = new MultiStatus( + IDEWorkbenchPlugin.IDE_WORKBENCH, 1, + IDEWorkbenchMessages.ProblemSavingWorkbench, null); + + final ProgressMonitorJobsDialog p = new CancelableProgressMonitorJobsDialog( + null); + + final boolean applyPolicy = ResourcesPlugin.getWorkspace() + .getDescription().isApplyFileStatePolicy(); + + final IRunnableWithProgress workspaceShutdownRunnable = new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) { + try { + status.merge(((Workspace) ResourcesPlugin.getWorkspace()).save(true, true, monitor)); + } catch (CoreException e) { + status.merge(e.getStatus()); + } + } + }; + + IRunnableWithProgress shutdownRunnable = new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + if (applyPolicy) + monitor = new CancelableProgressMonitorWrapper( + monitor, p); + + SubMonitor progress = SubMonitor.convert(monitor, SHUT_DOWN_TASK, 2); + try { + workspaceShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE)); + platformShutdownRunnable.run(progress.newChild(1, SubMonitor.SUPPRESS_NONE)); + } finally { + monitor.done(); + } + } + }; + + try { + new ProgressMonitorJobsDialog(null).run(true, false, shutdownRunnable); + } catch (InvocationTargetException e) { + status.merge(new Status(IStatus.ERROR, + IDEWorkbenchPlugin.IDE_WORKBENCH, 1, + IDEWorkbenchMessages.InternalError, e.getTargetException())); + } catch (InterruptedException e) { + status.merge(new Status(IStatus.ERROR, + IDEWorkbenchPlugin.IDE_WORKBENCH, 1, + IDEWorkbenchMessages.InternalError, e)); + } + ErrorDialog.openError(null, + IDEWorkbenchMessages.ProblemsSavingWorkspace, null, status, + IStatus.ERROR | IStatus.WARNING); + if (!status.isOK()) { + IDEWorkbenchPlugin.log( + IDEWorkbenchMessages.ProblemsSavingWorkspace, status); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.application.WorkbenchAdvisor#getDefaultPageInput + */ + @Override + public IAdaptable getDefaultPageInput() { + return ResourcesPlugin.getWorkspace().getRoot(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.application.WorkbenchAdvisor + */ + @Override + public String getInitialWindowPerspectiveId() { + int index = PlatformUI.getWorkbench().getWorkbenchWindowCount() - 1; + + String perspectiveId = null; + AboutInfo[] welcomeInfos = getWelcomePerspectiveInfos(); + if (index >= 0 && welcomeInfos != null && index < welcomeInfos.length) { + perspectiveId = welcomeInfos[index].getWelcomePerspectiveId(); + } + + if (perspectiveId == null && args.contains(SimanticsArguments.PERSPECTIVE)) { + String id = args.get(SimanticsArguments.PERSPECTIVE); + IPerspectiveDescriptor perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(id); + if (perspective != null) + perspectiveId = id; + } + + if (perspectiveId == null) { + IProject project = SimanticsUI.peekProject(); + if (project != null) + perspectiveId = project.getHint(ProjectKeys.DEFAULT_PERSPECTIVE); + } + + //System.out.println("Initial perspective: " + perspectiveId); + + return perspectiveId; + } + + /** + * Returns the map of versioned feature ids -> info object for all installed + * features. The format of the versioned feature id (the key of the map) is + * featureId + ":" + versionId. + * + * @return map of versioned feature ids -> info object (key type: + * String, value type: AboutInfo) + * @since 3.0 + */ + private Map computeBundleGroupMap() { + // use tree map to get predicable order + Map ids = new TreeMap(); + + IBundleGroupProvider[] providers = Platform.getBundleGroupProviders(); + for (int i = 0; i < providers.length; ++i) { + IBundleGroup[] groups = providers[i].getBundleGroups(); + for (int j = 0; j < groups.length; ++j) { + IBundleGroup group = groups[j]; + AboutInfo info = new AboutInfo(group); + + String version = info.getVersionId(); + version = version == null ? "0.0.0" //$NON-NLS-1$ + : new Version(version).toString(); + String versionedFeature = group.getIdentifier() + ":" + version; //$NON-NLS-1$ + + ids.put(versionedFeature, info); + } + } + + return ids; + } + + /** + * Returns the ordered map of versioned feature ids -> AboutInfo that are + * new for this session. + * + * @return ordered map of versioned feature ids (key type: + * String) -> infos (value type: + * AboutInfo). + */ + public Map getNewlyAddedBundleGroups() { + if (newlyAddedBundleGroups == null) { + newlyAddedBundleGroups = createNewBundleGroupsMap(); + } + return newlyAddedBundleGroups; + } + + /** + * Updates the old features setting and returns a map of new features. + */ + private Map createNewBundleGroupsMap() { + // retrieve list of installed bundle groups from last session + IDialogSettings settings = IDEWorkbenchPlugin.getDefault() + .getDialogSettings(); + String[] previousFeaturesArray = settings.getArray(INSTALLED_FEATURES); + + // get a map of currently installed bundle groups and store it for next + // session + Map bundleGroups = computeBundleGroupMap(); + String[] currentFeaturesArray = new String[bundleGroups.size()]; + bundleGroups.keySet().toArray(currentFeaturesArray); + settings.put(INSTALLED_FEATURES, currentFeaturesArray); + + // remove the previously known from the current set + if (previousFeaturesArray != null) { + for (int i = 0; i < previousFeaturesArray.length; ++i) { + bundleGroups.remove(previousFeaturesArray[i]); + } + } + + return bundleGroups; + } + + /** + * Declares all IDE-specific workbench images. This includes both "shared" + * images (named in {@link IDE.SharedImages}) and internal images (named in + * {@link org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages}). + * + * @see IWorkbenchConfigurer#declareImage + */ + private void declareWorkbenchImages() { + + final String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$ + final String PATH_ELOCALTOOL = ICONS_PATH + "elcl16/"; // Enabled //$NON-NLS-1$ + + // toolbar + // icons. + final String PATH_DLOCALTOOL = ICONS_PATH + "dlcl16/"; // Disabled //$NON-NLS-1$ + // //$NON-NLS-1$ + // toolbar + // icons. + final String PATH_ETOOL = ICONS_PATH + "etool16/"; // Enabled toolbar //$NON-NLS-1$ + // //$NON-NLS-1$ + // icons. + final String PATH_DTOOL = ICONS_PATH + "dtool16/"; // Disabled toolbar //$NON-NLS-1$ + // //$NON-NLS-1$ + // icons. + final String PATH_OBJECT = ICONS_PATH + "obj16/"; // Model object //$NON-NLS-1$ + // //$NON-NLS-1$ + // icons + final String PATH_WIZBAN = ICONS_PATH + "wizban/"; // Wizard //$NON-NLS-1$ + // //$NON-NLS-1$ + // icons + + Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH); + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC, PATH_ETOOL + + "build_exec.gif", false); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_HOVER, + PATH_ETOOL + "build_exec.gif", false); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC_DISABLED, + PATH_DTOOL + "build_exec.gif", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC, PATH_ETOOL + + "search_src.gif", false); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_HOVER, + PATH_ETOOL + "search_src.gif", false); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ETOOL_SEARCH_SRC_DISABLED, + PATH_DTOOL + "search_src.gif", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ETOOL_NEXT_NAV, PATH_ETOOL + + "next_nav.gif", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ETOOL_PREVIOUS_NAV, PATH_ETOOL + + "prev_nav.gif", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_WIZBAN_NEWPRJ_WIZ, PATH_WIZBAN + + "newprj_wiz.png", false); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFOLDER_WIZ, + PATH_WIZBAN + "newfolder_wiz.png", false); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_WIZBAN_NEWFILE_WIZ, PATH_WIZBAN + + "newfile_wiz.png", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTDIR_WIZ, + PATH_WIZBAN + "importdir_wiz.png", false); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_WIZBAN_IMPORTZIP_WIZ, + PATH_WIZBAN + "importzip_wiz.png", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTDIR_WIZ, + PATH_WIZBAN + "exportdir_wiz.png", false); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_WIZBAN_EXPORTZIP_WIZ, + PATH_WIZBAN + "exportzip_wiz.png", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ, + PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN + + "saveas_wiz.png", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG, PATH_WIZBAN + + "quick_fix.png", false); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT, + PATH_OBJECT + "prj_obj.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT + + "cprj_obj.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OPEN_MARKER, + PATH_ELOCALTOOL + "gotoobj_tsk.gif", true); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ELCL_QUICK_FIX_ENABLED, + PATH_ELOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_DLCL_QUICK_FIX_DISABLED, + PATH_DLOCALTOOL + "smartmode_co.gif", true); //$NON-NLS-1$ + + // task objects + // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_HPRIO_TSK, + // PATH_OBJECT+"hprio_tsk.gif"); + // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_MPRIO_TSK, + // PATH_OBJECT+"mprio_tsk.gif"); + // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LPRIO_TSK, + // PATH_OBJECT+"lprio_tsk.gif"); + + declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_TASK_TSK, + PATH_OBJECT + "taskmrk_tsk.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJS_BKMRK_TSK, + PATH_OBJECT + "bkmrk_tsk.gif", true); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_OBJS_COMPLETE_TSK, PATH_OBJECT + + "complete_tsk.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_OBJS_INCOMPLETE_TSK, PATH_OBJECT + + "incomplete_tsk.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM, PATH_OBJECT + + "welcome_item.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER, PATH_OBJECT + + "welcome_banner.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_OBJS_ERROR_PATH, PATH_OBJECT + + "error_tsk.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_OBJS_WARNING_PATH, PATH_OBJECT + + "warn_tsk.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_OBJS_INFO_PATH, PATH_OBJECT + + "info_tsk.gif", true); //$NON-NLS-1$ + + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_LCL_FLAT_LAYOUT, PATH_ELOCALTOOL + + "flatLayout.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_LCL_HIERARCHICAL_LAYOUT, + PATH_ELOCALTOOL + "hierarchicalLayout.gif", true); //$NON-NLS-1$ + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY, + PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$ + /* + declareWorkbenchImage(ideBundle, + IDEInternalWorkbenchImages.IMG_LCL_LINKTO_HELP, PATH_ELOCALTOOL + + "linkto_help.gif", false); //$NON-NLS-1$ + */ + + // synchronization indicator objects + // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT, + // PATH_OVERLAY+"wbet_stat.gif"); + // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_SBET_STAT, + // PATH_OVERLAY+"sbet_stat.gif"); + // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_CONFLICT_STAT, + // PATH_OVERLAY+"conflict_stat.gif"); + + // content locality indicator objects + // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_NOTLOCAL_STAT, + // PATH_STAT+"notlocal_stat.gif"); + // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_LOCAL_STAT, + // PATH_STAT+"local_stat.gif"); + // declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_FILLLOCAL_STAT, + // PATH_STAT+"filllocal_stat.gif"); + } + + /** + * Declares an IDE-specific workbench image. + * + * @param symbolicName + * the symbolic name of the image + * @param path + * the path of the image file; this path is relative to the base + * of the IDE plug-in + * @param shared + * true if this is a shared image, and + * false if this is not a shared image + * @see IWorkbenchConfigurer#declareImage + */ + private void declareWorkbenchImage(Bundle ideBundle, String symbolicName, + String path, boolean shared) { + URL url = FileLocator.find(ideBundle, new Path(path), null); + ImageDescriptor desc = ImageDescriptor.createFromURL(url); + getWorkbenchConfigurer().declareImage(symbolicName, desc, shared); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.application.WorkbenchAdvisor#getMainPreferencePageId + */ + @Override + public String getMainPreferencePageId() { + // indicate that we want the Workench preference page to be prominent + return WORKBENCH_PREFERENCE_CATEGORY_ID; + } + + /** + * @return the workspace location string, or null if the + * location is not being shown + */ + public String getWorkspaceLocation() { + // read command line, which has priority + IEclipseContext context = getWorkbenchConfigurer().getWorkbench().getService(IEclipseContext.class); + String location = context != null ? (String) context.get(E4Workbench.FORCED_SHOW_LOCATION) : null; + if (location != null) { + return location; + } + // read the preference + if (IDEWorkbenchPlugin.getDefault().getPreferenceStore().getBoolean(IDEInternalPreferences.SHOW_LOCATION)) { + return Platform.getLocation().toOSString(); + } + return null; + } + + /** + * @return the welcome perspective infos, or null if none or + * if they should be ignored due to the new intro being present + */ + public AboutInfo[] getWelcomePerspectiveInfos() { + if (welcomePerspectiveInfos == null) { + // support old welcome perspectives if intro plugin is not present + if (!hasIntro()) { + Map m = getNewlyAddedBundleGroups(); + ArrayList list = new ArrayList(m.size()); + for (Iterator i = m.values().iterator(); i.hasNext();) { + AboutInfo info = i.next(); + if (info != null && info.getWelcomePerspectiveId() != null + && info.getWelcomePageURL() != null) { + list.add(info); + } + } + welcomePerspectiveInfos = new AboutInfo[list.size()]; + list.toArray(welcomePerspectiveInfos); + } + } + return welcomePerspectiveInfos; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.application.WorkbenchAdvisor#getWorkbenchErrorHandler() + */ + @Override + public AbstractStatusHandler getWorkbenchErrorHandler() { + if (ideWorkbenchErrorHandler == null) { + ideWorkbenchErrorHandler = new IDEWorkbenchErrorHandler( + getWorkbenchConfigurer()); + } + return ideWorkbenchErrorHandler; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.application.WorkbenchAdvisor#eventLoopIdle(org.eclipse.swt.widgets.Display) + */ + @Override + public void eventLoopIdle(Display display) { + if (delayedEventsProcessor != null) + delayedEventsProcessor.catchUp(display); + super.eventLoopIdle(display); + } + +} diff --git a/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchApplication.java b/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchApplication.java index cc0cc024e..8b0431f38 100644 --- a/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchApplication.java +++ b/bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchApplication.java @@ -1,627 +1,626 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.workbench.internal; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Map; -import java.util.Properties; - -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.core.runtime.IExecutableExtension; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.app.IApplication; -import org.eclipse.equinox.app.IApplicationContext; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.osgi.service.datalocation.Location; -import org.eclipse.osgi.util.NLS; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.MessageBox; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.application.WorkbenchAdvisor; -import org.eclipse.ui.internal.WorkbenchPlugin; -import org.eclipse.ui.internal.ide.ChooseWorkspaceData; -import org.eclipse.ui.internal.ide.ChooseWorkspaceDialog; -import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; -import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; -import org.eclipse.ui.internal.ide.StatusUtil; -import org.simantics.application.arguments.ApplicationUtils; -import org.simantics.application.arguments.Arguments; -import org.simantics.application.arguments.IArgumentFactory; -import org.simantics.application.arguments.IArguments; -import org.simantics.application.arguments.SimanticsArguments; -import org.simantics.db.management.ISessionContextProvider; -import org.simantics.db.management.ISessionContextProviderSource; -import org.simantics.db.management.SessionContextProvider; -import org.simantics.db.management.SingleSessionContextProviderSource; -import org.simantics.ui.SimanticsUI; -import org.simantics.ui.WorkbenchWindowSessionContextProviderSource; -import org.simantics.utils.ui.BundleUtils; - - -/** - * The "main program" for the Eclipse IDE. - * - * @since 3.0 - */ -public class SimanticsWorkbenchApplication implements IApplication, IExecutableExtension { - - /** - * The name of the folder containing metadata information for the workspace. - */ - public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$ - - private static final String VERSION_FILENAME = "version.ini"; //$NON-NLS-1$ - - private static final String WORKSPACE_VERSION_KEY = "org.eclipse.core.runtime"; //$NON-NLS-1$ - - private static final String WORKSPACE_VERSION_VALUE = "1"; //$NON-NLS-1$ - - private static final String PROP_EXIT_CODE = "eclipse.exitcode"; //$NON-NLS-1$ - - /** - * A special return code that will be recognized by the launcher and used to - * restart the workbench. - */ - private static final Integer EXIT_RELAUNCH = new Integer(24); - - /** - * A special return code that will be recognized by the PDE launcher and used to - * show an error dialog if the workspace is locked. - */ - private static final Integer EXIT_WORKSPACE_LOCKED = new Integer(15); - - /** - * Creates a new IDE application. - */ - public SimanticsWorkbenchApplication() { - // There is nothing to do for WorkbenchApplication - } - - public WorkbenchAdvisor createWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) { - return new SimanticsWorkbenchAdvisor(args, processor); - } - - /* (non-Javadoc) - * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext context) - */ - @Override - public Object start(IApplicationContext appContext) throws Exception { - ApplicationUtils.loadSystemProperties(BundleUtils.find(Activator.PLUGIN_ID, "system.properties")); - IArguments args = parseArguments((String[]) appContext.getArguments().get(IApplicationContext.APPLICATION_ARGS)); - - Display display = createDisplay(); - // processor must be created before we start event loop - DelayedEventsProcessor processor = new DelayedEventsProcessor(display); - - try { - Object argCheck = verifyArguments(args); - if (argCheck != null) - return argCheck; - - // look and see if there's a splash shell we can parent off of - Shell shell = WorkbenchPlugin.getSplashShell(display); - if (shell != null) { - // should should set the icon and message for this shell to be the - // same as the chooser dialog - this will be the guy that lives in - // the task bar and without these calls you'd have the default icon - // with no message. - shell.setText(ChooseWorkspaceDialog.getWindowTitle()); - shell.setImages(Dialog.getDefaultImages()); - } - - Object instanceLocationCheck = checkInstanceLocation(shell, appContext.getArguments(), args); - if (instanceLocationCheck != null) { - WorkbenchPlugin.unsetSplashShell(display); - Platform.endSplash(); - return instanceLocationCheck; - } - - final ISessionContextProvider provider = new SessionContextProvider(null); - final ISessionContextProviderSource contextProviderSource = new SingleSessionContextProviderSource(provider); - //final ISessionContextProviderSource contextProviderSource = new WorkbenchWindowSessionContextProviderSource(PlatformUI.getWorkbench()); - SimanticsUI.setSessionContextProviderSource(contextProviderSource); - org.simantics.db.layer0.internal.SimanticsInternal.setSessionContextProviderSource(contextProviderSource); - org.simantics.Simantics.setSessionContextProviderSource(contextProviderSource); - - // create the workbench with this advisor and run it until it exits - // N.B. createWorkbench remembers the advisor, and also registers - // the workbench globally so that all UI plug-ins can find it using - // PlatformUI.getWorkbench() or AbstractUIPlugin.getWorkbench() - int returnCode = PlatformUI.createAndRunWorkbench(display, - createWorkbenchAdvisor(args, processor)); - - // the workbench doesn't support relaunch yet (bug 61809) so - // for now restart is used, and exit data properties are checked - // here to substitute in the relaunch return code if needed - if (returnCode != PlatformUI.RETURN_RESTART) { - return EXIT_OK; - } - - // if the exit code property has been set to the relaunch code, then - // return that code now, otherwise this is a normal restart - return EXIT_RELAUNCH.equals(Integer.getInteger(PROP_EXIT_CODE)) ? EXIT_RELAUNCH - : EXIT_RESTART; - } finally { - if (display != null) { - display.dispose(); - } - Location instanceLoc = Platform.getInstanceLocation(); - if (instanceLoc != null) - instanceLoc.release(); - } - } - - /*************************************************************************/ - - private IArguments parseArguments(String[] args) { - IArgumentFactory[] accepted = { - SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS, - SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL, - SimanticsArguments.DEFAULT_WORKSPACE_LOCATION, - SimanticsArguments.WORKSPACE_CHOOSER, - SimanticsArguments.WORKSPACE_NO_REMEMBER, - SimanticsArguments.PERSPECTIVE, - SimanticsArguments.SERVER, - SimanticsArguments.NEW_MODEL, - SimanticsArguments.EXPERIMENT, - SimanticsArguments.DISABLE_INDEX, - SimanticsArguments.DATABASE_ID, - }; - IArguments result = Arguments.parse(args, accepted); - return result; - } - - private Object verifyArguments(IArguments args) { - StringBuilder report = new StringBuilder(); - -// if (args.contains(SimanticsArguments.NEW_PROJECT)) { -// if (args.contains(SimanticsArguments.PROJECT)) { -// exclusiveArguments(report, SimanticsArguments.PROJECT, SimanticsArguments.NEW_PROJECT); -// } -// // Must have a server to checkout from when creating a new -// // project right from the beginning. -// if (!args.contains(SimanticsArguments.SERVER)) { -// missingArgument(report, SimanticsArguments.SERVER); -// } -// } else if (args.contains(SimanticsArguments.PROJECT)) { -// // To load a project, a server must be defined to checkout from -// if (!args.contains(SimanticsArguments.SERVER)) { -// missingArgument(report, SimanticsArguments.SERVER); -// } -// } - - // NEW_MODEL and MODEL arguments are optional - // EXPERIMENT argument is optional - - String result = report.toString(); - boolean valid = result.length() == 0; - - if (!valid) { - String msg = NLS.bind(Messages.Application_1, result); - MessageDialog.openInformation(null, Messages.Application_2, msg); - } - return valid ? null : EXIT_OK; - } - -// private void exclusiveArguments(StringBuilder sb, IArgumentFactory arg1, IArgumentFactory arg2) { -// sb.append(NLS.bind(Messages.Application_3, arg1.getArgument(), arg2.getArgument())); -// sb.append('\n'); -// } -// -// private void missingArgument(StringBuilder sb, IArgumentFactory arg) { -// sb.append(NLS.bind(Messages.Application_0, arg.getArgument())); -// sb.append('\n'); -// } - - /*************************************************************************/ - - /** - * Creates the display used by the application. - * - * @return the display used by the application - */ - protected Display createDisplay() { - return PlatformUI.createDisplay(); - } - - /* (non-Javadoc) - * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) - */ - @Override - public void setInitializationData(IConfigurationElement config, - String propertyName, Object data) { - // There is nothing to do for ProConfApplication - } - - /** - * Return true if a valid workspace path has been set and false otherwise. - * Prompt for and set the path if possible and required. - * @param applicationArguments - * - * @return true if a valid instance location has been set and false - * otherwise - */ - private Object checkInstanceLocation(Shell shell, Map applicationArguments, IArguments args) { - // -data @none was specified but an ide requires workspace - Location instanceLoc = Platform.getInstanceLocation(); - if (instanceLoc == null) { - MessageDialog - .openError( - shell, - IDEWorkbenchMessages.IDEApplication_workspaceMandatoryTitle, - IDEWorkbenchMessages.IDEApplication_workspaceMandatoryMessage); - return EXIT_OK; - } - - // -data "/valid/path", workspace already set - // This information is stored in configuration/.settings/org.eclipse.ui.ide.prefs - if (instanceLoc.isSet()) { - // make sure the meta data version is compatible (or the user has - // chosen to overwrite it). - if (!checkValidWorkspace(shell, instanceLoc.getURL())) { - return EXIT_OK; - } - - // at this point its valid, so try to lock it and update the - // metadata version information if successful - try { - if (instanceLoc.lock()) { - writeWorkspaceVersion(); - return null; - } - - // we failed to create the directory. - // Two possibilities: - // 1. directory is already in use - // 2. directory could not be created - File workspaceDirectory = new File(instanceLoc.getURL().getFile()); - if (workspaceDirectory.exists()) { - if (isDevLaunchMode(applicationArguments)) { - return EXIT_WORKSPACE_LOCKED; - } - MessageDialog.openError( - shell, - IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle, - IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage); - } else { - MessageDialog.openError( - shell, - IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle, - IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage); - } - } catch (IOException e) { - IDEWorkbenchPlugin.log("Could not obtain lock for workspace location", //$NON-NLS-1$ - e); - MessageDialog - .openError( - shell, - IDEWorkbenchMessages.InternalError, - e.getMessage()); - } - return EXIT_OK; - } - - // -data @noDefault or -data not specified, prompt and set - ChooseWorkspaceData launchData = null; - if (args.contains(SimanticsArguments.DEFAULT_WORKSPACE_LOCATION)) { - launchData = new ChooseWorkspaceData(args.get(SimanticsArguments.DEFAULT_WORKSPACE_LOCATION)); - } else { - launchData = new ChooseWorkspaceData(instanceLoc.getDefault()); - } - - boolean force = args.contains(SimanticsArguments.WORKSPACE_CHOOSER); - boolean suppressAskAgain = args.contains(SimanticsArguments.WORKSPACE_NO_REMEMBER); - - while (true) { - URL workspaceUrl = promptForWorkspace(shell, launchData, force, suppressAskAgain); - if (workspaceUrl == null) { - return EXIT_OK; - } - - // if there is an error with the first selection, then force the - // dialog to open to give the user a chance to correct - force = true; - - try { - // the operation will fail if the url is not a valid - // instance data area, so other checking is unneeded - if (instanceLoc.setURL(workspaceUrl, true)) { - launchData.writePersistedData(); - writeWorkspaceVersion(); - return null; - } - } catch (IllegalStateException e) { - MessageDialog - .openError( - shell, - IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle, - IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage); - return EXIT_OK; - } - - // by this point it has been determined that the workspace is - // already in use -- force the user to choose again - MessageDialog.openError(shell, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle, - IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage); - } - } - - private static boolean isDevLaunchMode(Map args) { - // see org.eclipse.pde.internal.core.PluginPathFinder.isDevLaunchMode() - if (Boolean.getBoolean("eclipse.pde.launch")) //$NON-NLS-1$ - return true; - return args.containsKey("-pdelaunch"); //$NON-NLS-1$ - } - - /** - * Open a workspace selection dialog on the argument shell, populating the - * argument data with the user's selection. Perform first level validation - * on the selection by comparing the version information. This method does - * not examine the runtime state (e.g., is the workspace already locked?). - * - * @param shell - * @param launchData - * @param force - * setting to true makes the dialog open regardless of the - * showDialog value - * @return An URL storing the selected workspace or null if the user has - * canceled the launch operation. - */ - private URL promptForWorkspace(Shell shell, ChooseWorkspaceData launchData, - boolean force, boolean suppressAskAgain) { - URL url = null; - do { - // okay to use the shell now - this is the splash shell - new ChooseWorkspaceDialog(shell, launchData, suppressAskAgain, true).prompt(force); - String instancePath = launchData.getSelection(); - if (instancePath == null) { - return null; - } - - // the dialog is not forced on the first iteration, but is on every - // subsequent one -- if there was an error then the user needs to be - // allowed to fix it - force = true; - - // 70576: don't accept empty input - if (instancePath.length() <= 0) { - MessageDialog - .openError( - shell, - IDEWorkbenchMessages.IDEApplication_workspaceEmptyTitle, - IDEWorkbenchMessages.IDEApplication_workspaceEmptyMessage); - continue; - } - - // create the workspace if it does not already exist - File workspace = new File(instancePath); - if (!workspace.exists()) { - workspace.mkdir(); - } - - try { - // Don't use File.toURL() since it adds a leading slash that Platform does not - // handle properly. See bug 54081 for more details. - String path = workspace.getAbsolutePath().replace( - File.separatorChar, '/'); - url = new URL("file", null, path); //$NON-NLS-1$ - } catch (MalformedURLException e) { - MessageDialog - .openError( - shell, - IDEWorkbenchMessages.IDEApplication_workspaceInvalidTitle, - IDEWorkbenchMessages.IDEApplication_workspaceInvalidMessage); - continue; - } - } while (!checkValidWorkspace(shell, url)); - - return url; - } - - /** - * Return true if the argument directory is ok to use as a workspace and - * false otherwise. A version check will be performed, and a confirmation - * box may be displayed on the argument shell if an older version is - * detected. - * - * @return true if the argument URL is ok to use as a workspace and false - * otherwise. - */ - private boolean checkValidWorkspace(Shell shell, URL url) { - // a null url is not a valid workspace - if (url == null) { - return false; - } - - String version = readWorkspaceVersion(url); - - // if the version could not be read, then there is not any existing - // workspace data to trample, e.g., perhaps its a new directory that - // is just starting to be used as a workspace - if (version == null) { - return true; - } - - final int ide_version = Integer.parseInt(WORKSPACE_VERSION_VALUE); - int workspace_version = Integer.parseInt(version); - - // equality test is required since any version difference (newer - // or older) may result in data being trampled - if (workspace_version == ide_version) { - return true; - } - - // At this point workspace has been detected to be from a version - // other than the current ide version -- find out if the user wants - // to use it anyhow. - int severity; - String title; - String message; - if (workspace_version < ide_version) { - // Workspace < IDE. Update must be possible without issues, - // so only inform user about it. - severity = MessageDialog.INFORMATION; - title = IDEWorkbenchMessages.IDEApplication_versionTitle_olderWorkspace; - message = NLS.bind(IDEWorkbenchMessages.IDEApplication_versionMessage_olderWorkspace, url.getFile()); - } else { - // Workspace > IDE. It must have been opened with a newer IDE version. - // Downgrade might be problematic, so warn user about it. - severity = MessageDialog.WARNING; - title = IDEWorkbenchMessages.IDEApplication_versionTitle_newerWorkspace; - message = NLS.bind(IDEWorkbenchMessages.IDEApplication_versionMessage_newerWorkspace, url.getFile()); - } - - MessageBox mbox = new MessageBox(shell, SWT.OK | SWT.CANCEL - | SWT.ICON_WARNING | SWT.APPLICATION_MODAL); - mbox.setText(title); - mbox.setMessage(message); - return mbox.open() == SWT.OK; - } - - /** - * Look at the argument URL for the workspace's version information. Return - * that version if found and null otherwise. - */ - private static String readWorkspaceVersion(URL workspace) { - File versionFile = getVersionFile(workspace, false); - if (versionFile == null || !versionFile.exists()) { - return null; - } - - try { - // Although the version file is not spec'ed to be a Java properties - // file, it happens to follow the same format currently, so using - // Properties to read it is convenient. - Properties props = new Properties(); - FileInputStream is = new FileInputStream(versionFile); - try { - props.load(is); - } finally { - is.close(); - } - - return props.getProperty(WORKSPACE_VERSION_KEY); - } catch (IOException e) { - IDEWorkbenchPlugin.log("Could not read version file", new Status( //$NON-NLS-1$ - IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, - IStatus.ERROR, - e.getMessage() == null ? "" : e.getMessage(), //$NON-NLS-1$, - e)); - return null; - } - } - - /** - * Write the version of the metadata into a known file overwriting any - * existing file contents. Writing the version file isn't really crucial, - * so the function is silent about failure - */ - private static void writeWorkspaceVersion() { - Location instanceLoc = Platform.getInstanceLocation(); - if (instanceLoc == null || instanceLoc.isReadOnly()) { - return; - } - - File versionFile = getVersionFile(instanceLoc.getURL(), true); - if (versionFile == null) { - return; - } - - OutputStream output = null; - try { - String versionLine = WORKSPACE_VERSION_KEY + '=' - + WORKSPACE_VERSION_VALUE; - - output = new FileOutputStream(versionFile); - output.write(versionLine.getBytes("UTF-8")); //$NON-NLS-1$ - } catch (IOException e) { - IDEWorkbenchPlugin.log("Could not write version file", //$NON-NLS-1$ - StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e)); - } finally { - try { - if (output != null) { - output.close(); - } - } catch (IOException e) { - // do nothing - } - } - } - - /** - * The version file is stored in the metadata area of the workspace. This - * method returns an URL to the file or null if the directory or file does - * not exist (and the create parameter is false). - * - * @param create - * If the directory and file does not exist this parameter - * controls whether it will be created. - * @return An url to the file or null if the version file does not exist or - * could not be created. - */ - private static File getVersionFile(URL workspaceUrl, boolean create) { - if (workspaceUrl == null) { - return null; - } - - try { - // make sure the directory exists - File metaDir = new File(workspaceUrl.getPath(), METADATA_FOLDER); - if (!metaDir.exists() && (!create || !metaDir.mkdir())) { - return null; - } - - // make sure the file exists - File versionFile = new File(metaDir, VERSION_FILENAME); - if (!versionFile.exists() - && (!create || !versionFile.createNewFile())) { - return null; - } - - return versionFile; - } catch (IOException e) { - // cannot log because instance area has not been set - return null; - } - } - - /* (non-Javadoc) - * @see org.eclipse.equinox.app.IApplication#stop() - */ - @Override - public void stop() { - final IWorkbench workbench = PlatformUI.getWorkbench(); - if (workbench == null) - return; - final Display display = workbench.getDisplay(); - display.syncExec(new Runnable() { - @Override - public void run() { - if (!display.isDisposed()) - workbench.close(); - } - }); - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.workbench.internal; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; +import java.util.Properties; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExecutableExtension; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.application.WorkbenchAdvisor; +import org.eclipse.ui.internal.WorkbenchPlugin; +import org.eclipse.ui.internal.ide.ChooseWorkspaceData; +import org.eclipse.ui.internal.ide.ChooseWorkspaceDialog; +import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; +import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; +import org.eclipse.ui.internal.ide.StatusUtil; +import org.simantics.application.arguments.ApplicationUtils; +import org.simantics.application.arguments.Arguments; +import org.simantics.application.arguments.IArgumentFactory; +import org.simantics.application.arguments.IArguments; +import org.simantics.application.arguments.SimanticsArguments; +import org.simantics.db.management.ISessionContextProvider; +import org.simantics.db.management.ISessionContextProviderSource; +import org.simantics.db.management.SessionContextProvider; +import org.simantics.db.management.SingleSessionContextProviderSource; +import org.simantics.ui.SimanticsUI; +import org.simantics.utils.ui.BundleUtils; + + +/** + * The "main program" for the Eclipse IDE. + * + * @since 3.0 + */ +public class SimanticsWorkbenchApplication implements IApplication, IExecutableExtension { + + /** + * The name of the folder containing metadata information for the workspace. + */ + public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$ + + private static final String VERSION_FILENAME = "version.ini"; //$NON-NLS-1$ + + private static final String WORKSPACE_VERSION_KEY = "org.eclipse.core.runtime"; //$NON-NLS-1$ + + private static final String WORKSPACE_VERSION_VALUE = "1"; //$NON-NLS-1$ + + private static final String PROP_EXIT_CODE = "eclipse.exitcode"; //$NON-NLS-1$ + + /** + * A special return code that will be recognized by the launcher and used to + * restart the workbench. + */ + private static final Integer EXIT_RELAUNCH = new Integer(24); + + /** + * A special return code that will be recognized by the PDE launcher and used to + * show an error dialog if the workspace is locked. + */ + private static final Integer EXIT_WORKSPACE_LOCKED = new Integer(15); + + /** + * Creates a new IDE application. + */ + public SimanticsWorkbenchApplication() { + // There is nothing to do for WorkbenchApplication + } + + public WorkbenchAdvisor createWorkbenchAdvisor(IArguments args, DelayedEventsProcessor processor) { + return new SimanticsWorkbenchAdvisor(args, processor); + } + + /* (non-Javadoc) + * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext context) + */ + @Override + public Object start(IApplicationContext appContext) throws Exception { + ApplicationUtils.loadSystemProperties(BundleUtils.find(Activator.PLUGIN_ID, "system.properties")); + IArguments args = parseArguments((String[]) appContext.getArguments().get(IApplicationContext.APPLICATION_ARGS)); + + Display display = createDisplay(); + // processor must be created before we start event loop + DelayedEventsProcessor processor = new DelayedEventsProcessor(display); + + try { + Object argCheck = verifyArguments(args); + if (argCheck != null) + return argCheck; + + // look and see if there's a splash shell we can parent off of + Shell shell = WorkbenchPlugin.getSplashShell(display); + if (shell != null) { + // should should set the icon and message for this shell to be the + // same as the chooser dialog - this will be the guy that lives in + // the task bar and without these calls you'd have the default icon + // with no message. + shell.setText(ChooseWorkspaceDialog.getWindowTitle()); + shell.setImages(Dialog.getDefaultImages()); + } + + Object instanceLocationCheck = checkInstanceLocation(shell, appContext.getArguments(), args); + if (instanceLocationCheck != null) { + WorkbenchPlugin.unsetSplashShell(display); + Platform.endSplash(); + return instanceLocationCheck; + } + + final ISessionContextProvider provider = new SessionContextProvider(null); + final ISessionContextProviderSource contextProviderSource = new SingleSessionContextProviderSource(provider); + //final ISessionContextProviderSource contextProviderSource = new WorkbenchWindowSessionContextProviderSource(PlatformUI.getWorkbench()); + SimanticsUI.setSessionContextProviderSource(contextProviderSource); + org.simantics.db.layer0.internal.SimanticsInternal.setSessionContextProviderSource(contextProviderSource); + org.simantics.Simantics.setSessionContextProviderSource(contextProviderSource); + + // create the workbench with this advisor and run it until it exits + // N.B. createWorkbench remembers the advisor, and also registers + // the workbench globally so that all UI plug-ins can find it using + // PlatformUI.getWorkbench() or AbstractUIPlugin.getWorkbench() + int returnCode = PlatformUI.createAndRunWorkbench(display, + createWorkbenchAdvisor(args, processor)); + + // the workbench doesn't support relaunch yet (bug 61809) so + // for now restart is used, and exit data properties are checked + // here to substitute in the relaunch return code if needed + if (returnCode != PlatformUI.RETURN_RESTART) { + return EXIT_OK; + } + + // if the exit code property has been set to the relaunch code, then + // return that code now, otherwise this is a normal restart + return EXIT_RELAUNCH.equals(Integer.getInteger(PROP_EXIT_CODE)) ? EXIT_RELAUNCH + : EXIT_RESTART; + } finally { + if (display != null) { + display.dispose(); + } + Location instanceLoc = Platform.getInstanceLocation(); + if (instanceLoc != null) + instanceLoc.release(); + } + } + + /*************************************************************************/ + + private IArguments parseArguments(String[] args) { + IArgumentFactory[] accepted = { + SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS, + SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL, + SimanticsArguments.DEFAULT_WORKSPACE_LOCATION, + SimanticsArguments.WORKSPACE_CHOOSER, + SimanticsArguments.WORKSPACE_NO_REMEMBER, + SimanticsArguments.PERSPECTIVE, + SimanticsArguments.SERVER, + SimanticsArguments.NEW_MODEL, + SimanticsArguments.EXPERIMENT, + SimanticsArguments.DISABLE_INDEX, + SimanticsArguments.DATABASE_ID, + }; + IArguments result = Arguments.parse(args, accepted); + return result; + } + + private Object verifyArguments(IArguments args) { + StringBuilder report = new StringBuilder(); + +// if (args.contains(SimanticsArguments.NEW_PROJECT)) { +// if (args.contains(SimanticsArguments.PROJECT)) { +// exclusiveArguments(report, SimanticsArguments.PROJECT, SimanticsArguments.NEW_PROJECT); +// } +// // Must have a server to checkout from when creating a new +// // project right from the beginning. +// if (!args.contains(SimanticsArguments.SERVER)) { +// missingArgument(report, SimanticsArguments.SERVER); +// } +// } else if (args.contains(SimanticsArguments.PROJECT)) { +// // To load a project, a server must be defined to checkout from +// if (!args.contains(SimanticsArguments.SERVER)) { +// missingArgument(report, SimanticsArguments.SERVER); +// } +// } + + // NEW_MODEL and MODEL arguments are optional + // EXPERIMENT argument is optional + + String result = report.toString(); + boolean valid = result.length() == 0; + + if (!valid) { + String msg = NLS.bind(Messages.Application_1, result); + MessageDialog.openInformation(null, Messages.Application_2, msg); + } + return valid ? null : EXIT_OK; + } + +// private void exclusiveArguments(StringBuilder sb, IArgumentFactory arg1, IArgumentFactory arg2) { +// sb.append(NLS.bind(Messages.Application_3, arg1.getArgument(), arg2.getArgument())); +// sb.append('\n'); +// } +// +// private void missingArgument(StringBuilder sb, IArgumentFactory arg) { +// sb.append(NLS.bind(Messages.Application_0, arg.getArgument())); +// sb.append('\n'); +// } + + /*************************************************************************/ + + /** + * Creates the display used by the application. + * + * @return the display used by the application + */ + protected Display createDisplay() { + return PlatformUI.createDisplay(); + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void setInitializationData(IConfigurationElement config, + String propertyName, Object data) { + // There is nothing to do for ProConfApplication + } + + /** + * Return true if a valid workspace path has been set and false otherwise. + * Prompt for and set the path if possible and required. + * @param applicationArguments + * + * @return true if a valid instance location has been set and false + * otherwise + */ + private Object checkInstanceLocation(Shell shell, Map applicationArguments, IArguments args) { + // -data @none was specified but an ide requires workspace + Location instanceLoc = Platform.getInstanceLocation(); + if (instanceLoc == null) { + MessageDialog + .openError( + shell, + IDEWorkbenchMessages.IDEApplication_workspaceMandatoryTitle, + IDEWorkbenchMessages.IDEApplication_workspaceMandatoryMessage); + return EXIT_OK; + } + + // -data "/valid/path", workspace already set + // This information is stored in configuration/.settings/org.eclipse.ui.ide.prefs + if (instanceLoc.isSet()) { + // make sure the meta data version is compatible (or the user has + // chosen to overwrite it). + if (!checkValidWorkspace(shell, instanceLoc.getURL())) { + return EXIT_OK; + } + + // at this point its valid, so try to lock it and update the + // metadata version information if successful + try { + if (instanceLoc.lock()) { + writeWorkspaceVersion(); + return null; + } + + // we failed to create the directory. + // Two possibilities: + // 1. directory is already in use + // 2. directory could not be created + File workspaceDirectory = new File(instanceLoc.getURL().getFile()); + if (workspaceDirectory.exists()) { + if (isDevLaunchMode(applicationArguments)) { + return EXIT_WORKSPACE_LOCKED; + } + MessageDialog.openError( + shell, + IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle, + IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage); + } else { + MessageDialog.openError( + shell, + IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle, + IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage); + } + } catch (IOException e) { + IDEWorkbenchPlugin.log("Could not obtain lock for workspace location", //$NON-NLS-1$ + e); + MessageDialog + .openError( + shell, + IDEWorkbenchMessages.InternalError, + e.getMessage()); + } + return EXIT_OK; + } + + // -data @noDefault or -data not specified, prompt and set + ChooseWorkspaceData launchData = null; + if (args.contains(SimanticsArguments.DEFAULT_WORKSPACE_LOCATION)) { + launchData = new ChooseWorkspaceData(args.get(SimanticsArguments.DEFAULT_WORKSPACE_LOCATION)); + } else { + launchData = new ChooseWorkspaceData(instanceLoc.getDefault()); + } + + boolean force = args.contains(SimanticsArguments.WORKSPACE_CHOOSER); + boolean suppressAskAgain = args.contains(SimanticsArguments.WORKSPACE_NO_REMEMBER); + + while (true) { + URL workspaceUrl = promptForWorkspace(shell, launchData, force, suppressAskAgain); + if (workspaceUrl == null) { + return EXIT_OK; + } + + // if there is an error with the first selection, then force the + // dialog to open to give the user a chance to correct + force = true; + + try { + // the operation will fail if the url is not a valid + // instance data area, so other checking is unneeded + if (instanceLoc.setURL(workspaceUrl, true)) { + launchData.writePersistedData(); + writeWorkspaceVersion(); + return null; + } + } catch (IllegalStateException e) { + MessageDialog + .openError( + shell, + IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle, + IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage); + return EXIT_OK; + } + + // by this point it has been determined that the workspace is + // already in use -- force the user to choose again + MessageDialog.openError(shell, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle, + IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage); + } + } + + private static boolean isDevLaunchMode(Map args) { + // see org.eclipse.pde.internal.core.PluginPathFinder.isDevLaunchMode() + if (Boolean.getBoolean("eclipse.pde.launch")) //$NON-NLS-1$ + return true; + return args.containsKey("-pdelaunch"); //$NON-NLS-1$ + } + + /** + * Open a workspace selection dialog on the argument shell, populating the + * argument data with the user's selection. Perform first level validation + * on the selection by comparing the version information. This method does + * not examine the runtime state (e.g., is the workspace already locked?). + * + * @param shell + * @param launchData + * @param force + * setting to true makes the dialog open regardless of the + * showDialog value + * @return An URL storing the selected workspace or null if the user has + * canceled the launch operation. + */ + private URL promptForWorkspace(Shell shell, ChooseWorkspaceData launchData, + boolean force, boolean suppressAskAgain) { + URL url = null; + do { + // okay to use the shell now - this is the splash shell + new ChooseWorkspaceDialog(shell, launchData, suppressAskAgain, true).prompt(force); + String instancePath = launchData.getSelection(); + if (instancePath == null) { + return null; + } + + // the dialog is not forced on the first iteration, but is on every + // subsequent one -- if there was an error then the user needs to be + // allowed to fix it + force = true; + + // 70576: don't accept empty input + if (instancePath.length() <= 0) { + MessageDialog + .openError( + shell, + IDEWorkbenchMessages.IDEApplication_workspaceEmptyTitle, + IDEWorkbenchMessages.IDEApplication_workspaceEmptyMessage); + continue; + } + + // create the workspace if it does not already exist + File workspace = new File(instancePath); + if (!workspace.exists()) { + workspace.mkdir(); + } + + try { + // Don't use File.toURL() since it adds a leading slash that Platform does not + // handle properly. See bug 54081 for more details. + String path = workspace.getAbsolutePath().replace( + File.separatorChar, '/'); + url = new URL("file", null, path); //$NON-NLS-1$ + } catch (MalformedURLException e) { + MessageDialog + .openError( + shell, + IDEWorkbenchMessages.IDEApplication_workspaceInvalidTitle, + IDEWorkbenchMessages.IDEApplication_workspaceInvalidMessage); + continue; + } + } while (!checkValidWorkspace(shell, url)); + + return url; + } + + /** + * Return true if the argument directory is ok to use as a workspace and + * false otherwise. A version check will be performed, and a confirmation + * box may be displayed on the argument shell if an older version is + * detected. + * + * @return true if the argument URL is ok to use as a workspace and false + * otherwise. + */ + private boolean checkValidWorkspace(Shell shell, URL url) { + // a null url is not a valid workspace + if (url == null) { + return false; + } + + String version = readWorkspaceVersion(url); + + // if the version could not be read, then there is not any existing + // workspace data to trample, e.g., perhaps its a new directory that + // is just starting to be used as a workspace + if (version == null) { + return true; + } + + final int ide_version = Integer.parseInt(WORKSPACE_VERSION_VALUE); + int workspace_version = Integer.parseInt(version); + + // equality test is required since any version difference (newer + // or older) may result in data being trampled + if (workspace_version == ide_version) { + return true; + } + + // At this point workspace has been detected to be from a version + // other than the current ide version -- find out if the user wants + // to use it anyhow. + int severity; + String title; + String message; + if (workspace_version < ide_version) { + // Workspace < IDE. Update must be possible without issues, + // so only inform user about it. + severity = MessageDialog.INFORMATION; + title = IDEWorkbenchMessages.IDEApplication_versionTitle_olderWorkspace; + message = NLS.bind(IDEWorkbenchMessages.IDEApplication_versionMessage_olderWorkspace, url.getFile()); + } else { + // Workspace > IDE. It must have been opened with a newer IDE version. + // Downgrade might be problematic, so warn user about it. + severity = MessageDialog.WARNING; + title = IDEWorkbenchMessages.IDEApplication_versionTitle_newerWorkspace; + message = NLS.bind(IDEWorkbenchMessages.IDEApplication_versionMessage_newerWorkspace, url.getFile()); + } + + MessageBox mbox = new MessageBox(shell, SWT.OK | SWT.CANCEL + | SWT.ICON_WARNING | SWT.APPLICATION_MODAL); + mbox.setText(title); + mbox.setMessage(message); + return mbox.open() == SWT.OK; + } + + /** + * Look at the argument URL for the workspace's version information. Return + * that version if found and null otherwise. + */ + private static String readWorkspaceVersion(URL workspace) { + File versionFile = getVersionFile(workspace, false); + if (versionFile == null || !versionFile.exists()) { + return null; + } + + try { + // Although the version file is not spec'ed to be a Java properties + // file, it happens to follow the same format currently, so using + // Properties to read it is convenient. + Properties props = new Properties(); + FileInputStream is = new FileInputStream(versionFile); + try { + props.load(is); + } finally { + is.close(); + } + + return props.getProperty(WORKSPACE_VERSION_KEY); + } catch (IOException e) { + IDEWorkbenchPlugin.log("Could not read version file", new Status( //$NON-NLS-1$ + IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, + IStatus.ERROR, + e.getMessage() == null ? "" : e.getMessage(), //$NON-NLS-1$, + e)); + return null; + } + } + + /** + * Write the version of the metadata into a known file overwriting any + * existing file contents. Writing the version file isn't really crucial, + * so the function is silent about failure + */ + private static void writeWorkspaceVersion() { + Location instanceLoc = Platform.getInstanceLocation(); + if (instanceLoc == null || instanceLoc.isReadOnly()) { + return; + } + + File versionFile = getVersionFile(instanceLoc.getURL(), true); + if (versionFile == null) { + return; + } + + OutputStream output = null; + try { + String versionLine = WORKSPACE_VERSION_KEY + '=' + + WORKSPACE_VERSION_VALUE; + + output = new FileOutputStream(versionFile); + output.write(versionLine.getBytes("UTF-8")); //$NON-NLS-1$ + } catch (IOException e) { + IDEWorkbenchPlugin.log("Could not write version file", //$NON-NLS-1$ + StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e)); + } finally { + try { + if (output != null) { + output.close(); + } + } catch (IOException e) { + // do nothing + } + } + } + + /** + * The version file is stored in the metadata area of the workspace. This + * method returns an URL to the file or null if the directory or file does + * not exist (and the create parameter is false). + * + * @param create + * If the directory and file does not exist this parameter + * controls whether it will be created. + * @return An url to the file or null if the version file does not exist or + * could not be created. + */ + private static File getVersionFile(URL workspaceUrl, boolean create) { + if (workspaceUrl == null) { + return null; + } + + try { + // make sure the directory exists + File metaDir = new File(workspaceUrl.getPath(), METADATA_FOLDER); + if (!metaDir.exists() && (!create || !metaDir.mkdir())) { + return null; + } + + // make sure the file exists + File versionFile = new File(metaDir, VERSION_FILENAME); + if (!versionFile.exists() + && (!create || !versionFile.createNewFile())) { + return null; + } + + return versionFile; + } catch (IOException e) { + // cannot log because instance area has not been set + return null; + } + } + + /* (non-Javadoc) + * @see org.eclipse.equinox.app.IApplication#stop() + */ + @Override + public void stop() { + final IWorkbench workbench = PlatformUI.getWorkbench(); + if (workbench == null) + return; + final Display display = workbench.getDisplay(); + display.syncExec(new Runnable() { + @Override + public void run() { + if (!display.isDisposed()) + workbench.close(); + } + }); + } + +} diff --git a/bundles/org.simantics/META-INF/MANIFEST.MF b/bundles/org.simantics/META-INF/MANIFEST.MF index 5cd86db54..d5f1ee27a 100644 --- a/bundles/org.simantics/META-INF/MANIFEST.MF +++ b/bundles/org.simantics/META-INF/MANIFEST.MF @@ -19,7 +19,10 @@ Require-Bundle: org.eclipse.core.runtime;visibility:=reexport, org.simantics.scl.osgi;bundle-version="1.0.4", org.simantics.scl.compiler;bundle-version="0.4.0", org.simantics.platform.ui.ontology;bundle-version="1.0.0", - org.simantics.db.procore;bundle-version="1.1.0" + org.simantics.db.procore;bundle-version="1.1.0", + org.slf4j.api, + ch.qos.logback.classic, + ch.qos.logback.core Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Export-Package: org.simantics, diff --git a/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java b/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java index 1754b0071..d59fff9c2 100644 --- a/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java +++ b/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java @@ -1,1031 +1,1036 @@ -/******************************************************************************* - * 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: - *

- * - * @author Toni Kalajainen - */ -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"); - - // 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, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics; + +import static org.simantics.db.common.utils.Transaction.commit; +import static org.simantics.db.common.utils.Transaction.endTransaction; +import static org.simantics.db.common.utils.Transaction.readGraph; +import static org.simantics.db.common.utils.Transaction.startTransaction; +import static org.simantics.db.common.utils.Transaction.writeGraph; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; + +import org.eclipse.core.runtime.ILog; +import org.eclipse.core.runtime.IProduct; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.osgi.service.resolver.BundleDescription; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.Databoard; +import org.simantics.datatypes.literal.Font; +import org.simantics.datatypes.literal.RGB; +import org.simantics.db.Driver; +import org.simantics.db.Driver.Management; +import org.simantics.db.Manager; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.SessionModel; +import org.simantics.db.UndoContext; +import org.simantics.db.VirtualGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.request.Queries; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.request.WriteResultRequest; +import org.simantics.db.common.utils.Transaction; +import org.simantics.db.exception.ClusterSetExistException; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.indexing.DatabaseIndexing; +import org.simantics.db.layer0.genericrelation.DependenciesRelation; +import org.simantics.db.layer0.util.SimanticsClipboardImpl; +import org.simantics.db.layer0.util.SimanticsKeys; +import org.simantics.db.layer0.util.TGTransferableGraphSource; +import org.simantics.db.layer0.variable.VariableRepository; +import org.simantics.db.management.SessionContext; +import org.simantics.db.request.Read; +import org.simantics.db.service.LifecycleSupport.LifecycleListener; +import org.simantics.db.service.LifecycleSupport.LifecycleState; +import org.simantics.db.service.QueryControl; +import org.simantics.db.service.UndoRedoSupport; +import org.simantics.db.service.VirtualGraphSupport; +import org.simantics.db.service.XSupport; +import org.simantics.graph.db.GraphDependencyAnalyzer; +import org.simantics.graph.db.GraphDependencyAnalyzer.IU; +import org.simantics.graph.db.GraphDependencyAnalyzer.IdentityNode; +import org.simantics.graph.db.IImportAdvisor; +import org.simantics.graph.db.TransferableGraphs; +import org.simantics.graph.diff.Diff; +import org.simantics.graph.diff.TransferableGraphDelta1; +import org.simantics.internal.Activator; +import org.simantics.internal.startup.StartupExtensions; +import org.simantics.layer0.Layer0; +import org.simantics.operation.Layer0X; +import org.simantics.project.IProject; +import org.simantics.project.ProjectFeatures; +import org.simantics.project.ProjectKeys; +import org.simantics.project.Projects; +import org.simantics.project.exception.ProjectException; +import org.simantics.project.features.registry.GroupReference; +import org.simantics.project.management.DatabaseManagement; +import org.simantics.project.management.GraphBundle; +import org.simantics.project.management.GraphBundleEx; +import org.simantics.project.management.GraphBundleRef; +import org.simantics.project.management.PlatformUtil; +import org.simantics.project.management.ServerManager; +import org.simantics.project.management.ServerManagerFactory; +import org.simantics.project.management.WorkspaceUtil; +import org.simantics.utils.FileUtils; +import org.simantics.utils.datastructures.Pair; +import org.simantics.utils.logging.TimeLogger; +import org.slf4j.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 org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SimanticsPlatform.class); + + /** + * The policy is relevant when developing Simantics from Eclipse IDE. + * It is applied when the ontology in the database of a workspace doesn't match + * a newer ontology in the Eclipse workspace. + */ + public static enum OntologyRecoveryPolicy { ThrowError, Merge, ReinstallDatabase } + + /** + * This policy dictates how the Simantics platform startup should react if + * the started workspace is not set up properly. The alternatives are to + * just throw an error and fail or to attempt all possible measures to fix + * the encountered problems. + */ + public static enum RecoveryPolicy { ThrowError, FixError } + + /** Singleton instance, started in SimanticsWorkbenchAdvisor */ + public static final SimanticsPlatform INSTANCE = new SimanticsPlatform(); + + /** Set to true when the Simantics Platform is in good-and-go condition */ + public boolean running; + + /** Database Session */ + public Session session; + private Management databasebManagement; + + /** Database session context */ + public SessionContext sessionContext; + + /** Project identifier in Database */ + public String projectURI; + + /** Project name */ + public String projectName; + + /** Project resource */ + public Resource projectResource; + + /** Session specific bindings */ + public SimanticsBindings simanticsBindings; + public SimanticsBindings simanticsBindings2; + + public Thread mainThread; + + /** + * The {@link IProject} activated by + * {@link #startUp(IProgressMonitor, RecoveryPolicy, OntologyRecoveryPolicy, ServerAddress, PlatformUserAgent)} + */ + private IProject project; + + protected ILog log; + + /** + * Create a new simantics plaform manager in uninitialized state and + * with default policies.

+ */ + 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"); + + LOGGER.info("Beginning of SimanticsPlatform.startUp"); + + if (progressMonitor == null) progressMonitor = new NullProgressMonitor(); + + // For debugging on what kind of platform automatic tests are running in + // case there are problems. + if ("true".equals(System.getProperty("org.simantics.dumpBundleState"))) + dumpPlatformBundleState(); + + // 0. Consult all startup extensions before doing anything with the workspace. + StartupExtensions.consultStartupExtensions(); + TimeLogger.log("Consulted platform pre-startup extensions"); + + // 0.1. Clear all temporary files + Simantics.clearTemporaryDirectory(); + TimeLogger.log("Cleared temporary directory"); + + // 0.2 Clear VariableRepository.repository static map which holds references to SessionImplDb + VariableRepository.clear(); + + // 1. Assert there is a database at /db + session = setupDatabase(databaseDriverId, progressMonitor, workspacePolicy, userAgent); + TimeLogger.log("Database setup complete"); + + // 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()); + } + } + +} + diff --git a/bundles/pom.xml b/bundles/pom.xml index 54ab690db..0b2a85da4 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -1,209 +1,210 @@ - - - 4.0.0 - org.simantics - org.simantics.root.bundles - 1.0.0-SNAPSHOT - pom - - - org.simantics - org.simantics.root - 1.0.0-SNAPSHOT - - - - - - org.eclipse.tycho - tycho-compiler-plugin - ${tycho.version} - - -err:-forbidden - - - - org.eclipse.tycho - tycho-source-plugin - ${tycho.version} - - - plugin-source - - plugin-source - - - - - - - - - com.famfamfam.silk - org.simantics - org.simantics.action.ontology - org.simantics.acorn - org.simantics.annotation.ontology - org.simantics.annotation.ui - org.simantics.application - org.simantics.backup - org.simantics.backup.db - org.simantics.backup.ontology - org.simantics.basicexpression - org.simantics.browsing.ui - org.simantics.browsing.ui.common - org.simantics.browsing.ui.graph - org.simantics.browsing.ui.graph.impl - org.simantics.browsing.ui.model - org.simantics.browsing.ui.ontology - org.simantics.browsing.ui.platform - org.simantics.browsing.ui.swt - org.simantics.charts - org.simantics.charts.ontology - org.simantics.color.ontology - org.simantics.common - org.simantics.compressions - org.simantics.databoard - org.simantics.datatypes - org.simantics.datatypes.ontology - org.simantics.db - org.simantics.db.common - org.simantics.db.impl - org.simantics.db.indexing - org.simantics.db.layer0 - org.simantics.db.management - org.simantics.db.procore - org.simantics.db.procore.server.environment - org.simantics.db.procore.ui - org.simantics.db.server - org.simantics.db.services - org.simantics.debug.browser - org.simantics.debug.browser.ui - org.simantics.debug.graphical - org.simantics.debug.ui - org.simantics.diagram - org.simantics.diagram.connection - org.simantics.diagram.ontology - org.simantics.diagram.profile - org.simantics.document - org.simantics.document.base.ontology - org.simantics.document.linking.ontology - org.simantics.document.linking.ui - org.simantics.document.ontology - org.simantics.document.server - org.simantics.document.server.io - org.simantics.document.swt.core - org.simantics.document.swt.ontology - org.simantics.document.ui - org.simantics.document.ui.ontology - org.simantics.dublincore.ontology - org.simantics.editors - org.simantics.editors.win32 - org.simantics.equation - org.simantics.event - org.simantics.event.ontology - org.simantics.excel - org.simantics.export.core - org.simantics.export.ui - org.simantics.fastlz - org.simantics.fileimport - org.simantics.fileimport.ui - org.simantics.g2d - org.simantics.g2d.ontology - org.simantics.graph - org.simantics.graph.compiler - org.simantics.graph.db - org.simantics.graphfile - org.simantics.graphfile.ontology - org.simantics.graphviz - org.simantics.graphviz.ui - org.simantics.history - org.simantics.image.ontology - org.simantics.image.ui - org.simantics.image2.ontology - org.simantics.issues - org.simantics.issues.common - org.simantics.issues.ontology - org.simantics.issues.ui - org.simantics.issues.ui.ontology - org.simantics.layer0 - org.simantics.layer0.utils - org.simantics.layer0x.ontology - org.simantics.ltk - org.simantics.ltk.antlr - org.simantics.lz4 - org.simantics.mapping - org.simantics.message - org.simantics.message.ui - org.simantics.migration.ui - org.simantics.modeling - org.simantics.modeling.ontology - org.simantics.modeling.template2d.ontology - org.simantics.modeling.template2d.ui - org.simantics.modeling.ui - org.simantics.nativemem - org.simantics.objmap2 - org.simantics.platform.ui.ontology - org.simantics.project - org.simantics.project.ontology - org.simantics.scenegraph - org.simantics.scenegraph.loader - org.simantics.scenegraph.ontology - org.simantics.scenegraph.profile - org.simantics.scenegraph.swing - org.simantics.scenegraph.ui - org.simantics.scl.commands - org.simantics.scl.compiler - org.simantics.scl.compiler.dummy - org.simantics.scl.data - org.simantics.scl.db - org.simantics.scl.expressions - org.simantics.scl.osgi - org.simantics.scl.reflection - org.simantics.scl.runtime - org.simantics.scl.ui - org.simantics.scl.ui.editor - org.simantics.selectionview - org.simantics.selectionview.ontology - org.simantics.selectionview.ui.ontology - org.simantics.silk.ontology - org.simantics.simulation - org.simantics.simulation.ontology - org.simantics.simulation.sequences - org.simantics.simulation.ui - org.simantics.simulator.variable - org.simantics.softwareconfiguration.ontology - org.simantics.spreadsheet - org.simantics.spreadsheet.common - org.simantics.spreadsheet.graph - org.simantics.spreadsheet.ontology - org.simantics.spreadsheet.ui - org.simantics.structural.ontology - org.simantics.structural.synchronization - org.simantics.structural.synchronization.client - org.simantics.structural.ui - org.simantics.structural2 - org.simantics.team.ui - org.simantics.threadlog - org.simantics.trend - org.simantics.ui - org.simantics.user.ontology - org.simantics.utils - org.simantics.utils.datastructures - org.simantics.utils.thread - org.simantics.utils.thread.swt - org.simantics.utils.ui - org.simantics.utils.ui.workbench - org.simantics.viewpoint.ontology - org.simantics.views - org.simantics.views.ontology - org.simantics.views.swt - org.simantics.views.swt.client - org.simantics.wiki.ui - org.simantics.workbench - org.simantics.workbench.ontology - org.simantics.workbench.search - winterwell.markdown - - + + + 4.0.0 + org.simantics + org.simantics.root.bundles + 1.0.0-SNAPSHOT + pom + + + org.simantics + org.simantics.root + 1.0.0-SNAPSHOT + + + + + + org.eclipse.tycho + tycho-compiler-plugin + ${tycho.version} + + -err:-forbidden + + + + org.eclipse.tycho + tycho-source-plugin + ${tycho.version} + + + plugin-source + + plugin-source + + + + + + + + + com.famfamfam.silk + org.simantics + org.simantics.action.ontology + org.simantics.acorn + org.simantics.annotation.ontology + org.simantics.annotation.ui + org.simantics.application + org.simantics.backup + org.simantics.backup.db + org.simantics.backup.ontology + org.simantics.basicexpression + org.simantics.browsing.ui + org.simantics.browsing.ui.common + org.simantics.browsing.ui.graph + org.simantics.browsing.ui.graph.impl + org.simantics.browsing.ui.model + org.simantics.browsing.ui.ontology + org.simantics.browsing.ui.platform + org.simantics.browsing.ui.swt + org.simantics.charts + org.simantics.charts.ontology + org.simantics.color.ontology + org.simantics.common + org.simantics.compressions + org.simantics.databoard + org.simantics.datatypes + org.simantics.datatypes.ontology + org.simantics.db + org.simantics.db.common + org.simantics.db.impl + org.simantics.db.indexing + org.simantics.db.layer0 + org.simantics.db.management + org.simantics.db.procore + org.simantics.db.procore.server.environment + org.simantics.db.procore.ui + org.simantics.db.server + org.simantics.db.services + org.simantics.debug.browser + org.simantics.debug.browser.ui + org.simantics.debug.graphical + org.simantics.debug.ui + org.simantics.diagram + org.simantics.diagram.connection + org.simantics.diagram.ontology + org.simantics.diagram.profile + org.simantics.document + org.simantics.document.base.ontology + org.simantics.document.linking.ontology + org.simantics.document.linking.ui + org.simantics.document.ontology + org.simantics.document.server + org.simantics.document.server.io + org.simantics.document.swt.core + org.simantics.document.swt.ontology + org.simantics.document.ui + org.simantics.document.ui.ontology + org.simantics.dublincore.ontology + org.simantics.editors + org.simantics.editors.win32 + org.simantics.equation + org.simantics.event + org.simantics.event.ontology + org.simantics.excel + org.simantics.export.core + org.simantics.export.ui + org.simantics.fastlz + org.simantics.fileimport + org.simantics.fileimport.ui + org.simantics.g2d + org.simantics.g2d.ontology + org.simantics.graph + org.simantics.graph.compiler + org.simantics.graph.db + org.simantics.graphfile + org.simantics.graphfile.ontology + org.simantics.graphviz + org.simantics.graphviz.ui + org.simantics.history + org.simantics.image.ontology + org.simantics.image.ui + org.simantics.image2.ontology + org.simantics.issues + org.simantics.issues.common + org.simantics.issues.ontology + org.simantics.issues.ui + org.simantics.issues.ui.ontology + org.simantics.layer0 + org.simantics.layer0.utils + org.simantics.layer0x.ontology + org.simantics.logback.configuration + org.simantics.ltk + org.simantics.ltk.antlr + org.simantics.lz4 + org.simantics.mapping + org.simantics.message + org.simantics.message.ui + org.simantics.migration.ui + org.simantics.modeling + org.simantics.modeling.ontology + org.simantics.modeling.template2d.ontology + org.simantics.modeling.template2d.ui + org.simantics.modeling.ui + org.simantics.nativemem + org.simantics.objmap2 + org.simantics.platform.ui.ontology + org.simantics.project + org.simantics.project.ontology + org.simantics.scenegraph + org.simantics.scenegraph.loader + org.simantics.scenegraph.ontology + org.simantics.scenegraph.profile + org.simantics.scenegraph.swing + org.simantics.scenegraph.ui + org.simantics.scl.commands + org.simantics.scl.compiler + org.simantics.scl.compiler.dummy + org.simantics.scl.data + org.simantics.scl.db + org.simantics.scl.expressions + org.simantics.scl.osgi + org.simantics.scl.reflection + org.simantics.scl.runtime + org.simantics.scl.ui + org.simantics.scl.ui.editor + org.simantics.selectionview + org.simantics.selectionview.ontology + org.simantics.selectionview.ui.ontology + org.simantics.silk.ontology + org.simantics.simulation + org.simantics.simulation.ontology + org.simantics.simulation.sequences + org.simantics.simulation.ui + org.simantics.simulator.variable + org.simantics.softwareconfiguration.ontology + org.simantics.spreadsheet + org.simantics.spreadsheet.common + org.simantics.spreadsheet.graph + org.simantics.spreadsheet.ontology + org.simantics.spreadsheet.ui + org.simantics.structural.ontology + org.simantics.structural.synchronization + org.simantics.structural.synchronization.client + org.simantics.structural.ui + org.simantics.structural2 + org.simantics.team.ui + org.simantics.threadlog + org.simantics.trend + org.simantics.ui + org.simantics.user.ontology + org.simantics.utils + org.simantics.utils.datastructures + org.simantics.utils.thread + org.simantics.utils.thread.swt + org.simantics.utils.ui + org.simantics.utils.ui.workbench + org.simantics.viewpoint.ontology + org.simantics.views + org.simantics.views.ontology + org.simantics.views.swt + org.simantics.views.swt.client + org.simantics.wiki.ui + org.simantics.workbench + org.simantics.workbench.ontology + org.simantics.workbench.search + winterwell.markdown + + diff --git a/features/org.simantics.rcp.feature/feature.xml b/features/org.simantics.rcp.feature/feature.xml index d11d8aa0b..c1610fdc6 100644 --- a/features/org.simantics.rcp.feature/feature.xml +++ b/features/org.simantics.rcp.feature/feature.xml @@ -690,4 +690,11 @@ This Agreement is governed by the laws of the State of New York and the intellec version="0.0.0" unpack="false"/> + + -- 2.47.1