From: Tuukka Lehtonen Date: Tue, 27 Sep 2016 22:54:05 +0000 (+0300) Subject: Merge commit 'ffdf837' X-Git-Tag: v1.25.0~84 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=5930811a7911090a0c4984380c3b45ed81a93cde Merge commit 'ffdf837' Resolved conflicts from: bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/GraphSessionVirtual.java bundles/org.simantics.db.server/src/org/simantics/db/server/internal/SessionI.java bundles/org.simantics.db/src/org/simantics/db/Database.java bundles/org.simantics.db/src/org/simantics/db/service/ClusterSetsSupport.java bundles/org.simantics.modeling/src/org/simantics/modeling/SCL.java bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java bundles/org.simantics/src/org/simantics/SimanticsPlatform.java --- 5930811a7911090a0c4984380c3b45ed81a93cde diff --cc bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ClusterSetsSupportImpl2.java index ed1689ea4,db28af306..33950652c --- a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ClusterSetsSupportImpl2.java +++ b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ClusterSetsSupportImpl2.java @@@ -77,10 -77,10 +77,15 @@@ public class ClusterSetsSupportImpl2 im clusterSets.touch(); } } + + @Override + public void setReadDirectory(Path read) { + this.readDirectory = read; + } + @Override + public void setReadDirectory(Path read) { + this.readDirectory = read; + } + } diff --cc bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/GraphSessionVirtual.java index d1e006424,1dc1b015a..f6eba7eb8 --- a/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/GraphSessionVirtual.java +++ b/bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/GraphSessionVirtual.java @@@ -215,4 -214,4 +214,4 @@@ class GraphSessionVirtual extends Graph id = virtualGraphServerSupport.createVirtual(); return id; } --} ++} diff --cc bundles/org.simantics.modeling/src/org/simantics/modeling/SCL.java index bfa42b40e,52909e018..24e50c0f7 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/SCL.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/SCL.java @@@ -23,12 -23,9 +22,13 @@@ import org.simantics.db.layer0.request. import org.simantics.db.layer0.util.RemoverUtil; import org.simantics.db.layer0.util.SimanticsClipboard; import org.simantics.db.service.DebugSupport; + import org.simantics.db.service.ServiceActivityMonitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class SCL { + private static final Logger LOGGER = LoggerFactory.getLogger(SCL.class); + public static void killPlatformWrite(WriteGraph graph) throws DatabaseException { // Currently not supported. // Would be relatively easy to support the desired functionality. diff --cc bundles/org.simantics.workbench/src/org/simantics/workbench/internal/SimanticsWorkbenchAdvisor.java index 0bce2a568,d75f1e476..bce220c9c --- 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,1233 -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.getCause()); - } 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); ++ Activator.logError(getClass().getSimpleName() + ".openWindows failed", e.getCause()); + } 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 --cc bundles/org.simantics/src/org/simantics/SimanticsPlatform.java index 09d632a3e,7e6bd9dd9..11013eaf7 --- a/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java +++ b/bundles/org.simantics/src/org/simantics/SimanticsPlatform.java @@@ -1,1037 -1,1041 +1,1047 @@@ -/******************************************************************************* - * 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"); - - // 1.1 - XSupport support = session.getService(XSupport.class); - if (support.rolledback()) { - try { - DatabaseIndexing.deleteAllIndexes(); - } catch (IOException e) { - throw new PlatformException(e); - } - } - - // 2. Assert all graphs, and correct versions, are installed to the database - synchronizeOntologies(progressMonitor, ontologyPolicy, requireSynchronize); - TimeLogger.log("Synchronized ontologies"); - - // 4. Assert simantics.cfg exists - boolean installProject = assertConfiguration(progressMonitor,workspacePolicy); - - // 5. Assert Project Resource is installed in the database - installProject = assertProject(progressMonitor, workspacePolicy, installProject); - - // 6. Install all features into project, if in debug mode - updateInstalledGroups(progressMonitor, installProject); - TimeLogger.log("Installed all features into project"); - - // 7. Assert L0.Session in database for this session - assertSessionModel(progressMonitor); - - session.getService(XSupport.class).setServiceMode(false, false); - - try { - session.sync(new WriteRequest() { - - @Override - public void perform(WriteGraph graph) throws DatabaseException { - QueryControl qc = graph.getService(QueryControl.class); - qc.flush(graph); - } - - }); - TimeLogger.log("Flushed queries"); - } catch (DatabaseException e) { - Logger.defaultLogError(e); - } - boolean loadProject = true; - try { - - sessionContext = SimanticsPlatform.INSTANCE.createSessionContext(true); - // This must be before setSessionContext since some listeners might query this - sessionContext.setHint(SimanticsKeys.KEY_PROJECT, SimanticsPlatform.INSTANCE.projectResource); - - Simantics.setSessionContext(sessionContext); - - // 1. Put ResourceBinding that throws an exception to General Bindings - simanticsBindings = new SimanticsBindings( null ); - Bindings.classBindingFactory.addFactory( simanticsBindings ); - - - // 2. Create session-specific second Binding context (Databoard) and - // put that to Session as a service - Session session = sessionContext.getSession(); - Databoard sessionDataboard = new Databoard(); - session.registerService(Databoard.class, sessionDataboard); - simanticsBindings2 = new SimanticsBindings( session ); - sessionDataboard.classBindingFactory.addFactory( simanticsBindings2 ); - - // Register datatype bindings - Bindings.defaultBindingFactory.getRepository().put(RGB.Integer.BINDING.type(), RGB.Integer.BINDING); - Bindings.defaultBindingFactory.getRepository().put(Font.BINDING.type(), Font.BINDING); - - if(loadProject) { - - TimeLogger.log("Load projects"); - project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource); - - sessionContext.setHint(ProjectKeys.KEY_PROJECT, project); - TimeLogger.log("Loading projects complete"); - - project.activate(); - TimeLogger.log("Project activated"); - } - - } catch (DatabaseException e) { - Logger.defaultLogError(e); - throw new PlatformException(e); - } catch (ProjectException e) { - boolean hasStackTrace = e.getStackTrace().length > 0; - if (!hasStackTrace) - throw new PlatformException(e.getMessage(), hasStackTrace); - throw new PlatformException(e, hasStackTrace); - } - - running = true; - - return sessionContext; - - } - - public SessionContext createSessionContext(boolean init) throws PlatformException { - try { - // Construct and initialize SessionContext from Session. - SessionContext sessionContext = SessionContext.create(session, init); - if (init) - sessionContext.registerServices(); - return sessionContext; - } catch (DatabaseException e) { - throw new PlatformException(e); - } - } - -// private static File getIgnorePrerequisitesFile(URL workspaceUrl) { -// if (workspaceUrl == null) -// return null; -// return new File(workspaceUrl.getPath(), ".ignorePrerequisites"); -// } -// -// private void ensurePrerequisites(IProgressMonitor progressMonitor, PlatformUserAgent userAgent) throws PlatformException { -// Location loc = Platform.getInstanceLocation(); -// File ignorePrerequisites = getIgnorePrerequisitesFile(loc.getURL()); -// if (loc.isSet() && ignorePrerequisites != null) { -// if (ignorePrerequisites.exists() || ignorePrerequisites.isFile()) -// return; -// } -// -// try { -// ServerEnvironment.ensureServerDependenciesMet(); -// } catch (ExecutionEnvironmentException e) { -// // Not installed properly, ask user whether to try installation. -// try { -// StringBuilder msg = new StringBuilder(); -// msg.append("Your system seems to be missing the following prerequisites for running this application:\n\n"); -// for (Product product : e.requiredProducts) -// msg.append("\t" + product.getDescription() + "\n"); -// msg.append("\nYou can either install the missing components now or ignore and attempt to start the application without them. Ignore Always will ignore this question for this workspace."); -// msg.append("\n\nSelecting Cancel will close the application."); -// -// int selection = 0; -// if (userAgent != null) { -// selection = userAgent.showPrompt("Missing Prerequisites", msg.toString(), new String[] { -// "Install Pre-requisites", -// "Ignore Now", -// "Ignore Always", -// "Cancel" -// }, selection); -// } -// boolean tryInstall = false; -// switch (selection) { -// case 0: -// tryInstall = true; -// break; -// case 2: -// ignorePrerequisites.createNewFile(); -// case 1: -// break; -// case 3: -// case -1: -// throw new CancelStartupException(); -// } -// -// if (tryInstall) { -// // Try to install it and check for success afterwards. -// ServerEnvironment.tryInstallDependencies(progressMonitor); -// ServerEnvironment.ensureServerDependenciesMet(); -// } -// } catch (InstallException ie) { -// throw new PlatformException(ie); -// } catch (ExecutionEnvironmentException eee) { -// throw new PlatformException(eee); -// } catch (IOException ie) { -// throw new PlatformException(ie); -// } -// } -// } - - /** - * Shutdown Simantics Platform. - * - * In SWB this is handled in SimanticsWorkbenchAdvisor#disconnectFromWorkspace. - * - * @param progressMonitor optional progress monitor - * @throws PlatformException - */ - public void shutdown(IProgressMonitor progressMonitor) throws PlatformException - { - SubMonitor progress = SubMonitor.convert(progressMonitor, 100); - PlatformException platformException = null; - try { - progress.subTask("Close Project"); - if (project != null) { - project.safeDispose(); - } - progress.worked(10); - - running = false; - progress.subTask("Close Database Session"); - Databoard databoard = null; - if (sessionContext != null) { - Session s = sessionContext.peekSession(); - if (s != null) { - databoard = s.peekService(Databoard.class); - - progress.subTask("Flushing Index Caches"); - try { - Simantics.flushIndexCaches(progress.newChild(20), s); - } catch (Throwable t) { - Logger.defaultLogError(t); - } - } - - progress.subTask("Close Database Session"); - sessionContext.safeDispose(); - sessionContext = null; - Simantics.setSessionContext(null); - } - if (simanticsBindings != null) { - Bindings.classBindingFactory.removeFactory( simanticsBindings ); - simanticsBindings = null; - } - if (databoard != null) { - if (simanticsBindings2 != null) { - databoard.classBindingFactory.removeFactory( simanticsBindings2 ); - simanticsBindings2 = null; - } - databoard.clear(); - } - - // Make sure Simantics clipboard doesn't store unwanted session data references. - Simantics.setClipboard(new SimanticsClipboardImpl()); - - progress.worked(30); - - session = null; - projectResource = null; - - DependenciesRelation.assertFinishedTracking(); - - } catch (Exception e) { - platformException = new PlatformException("Failed to shutdown Simantics Platform", e); - } - - progress.worked(10); - progress.subTask("Shutting down database"); - try { - if (null != databasebManagement) - databasebManagement.shutdown(); - } catch (Throwable t) { - Logger.defaultLogError(t); - } - progress.worked(10); - - progress.subTask("Clearing Workspace Temporary Directory"); - try { - Simantics.clearTemporaryDirectory(); - } catch (Throwable t) { - Logger.defaultLogError(t); - } - progress.worked(10); - if (null != platformException) - throw platformException; - } - - // TODO: consider removing this in the future ?? - @Override - public void stateChanged(LifecycleState newState) { - if(newState == LifecycleState.CLOSED) { - if(running) { - if(Platform.isRunning()) { - mainThread.interrupt(); - } - } - } - } - - /** - * @return true if discard was successful, false - * if there was no session, {@link UndoRedoSupport} or - * {@link UndoContext} to discard through - */ - public boolean discardSessionUndoHistory() { - Session s = session; - if (s != null) { - UndoRedoSupport urs = s.peekService(UndoRedoSupport.class); - if (urs != null) { - UndoContext uc = urs.getUndoContext(s); - if (uc != null) { - uc.clear(); - return true; - } - } - } - return false; - } - - public void reconnect(String databaseDriverId) throws Exception { - // Starts database server. - SimanticsPlatform.INSTANCE.startUp(databaseDriverId, null, RecoveryPolicy.ThrowError, OntologyRecoveryPolicy.ThrowError, true, null); - } - - private void dumpPlatformBundleState() { - BundleDescription[] bs = Platform.getPlatformAdmin().getState().getBundles(); - System.out.println("Total bundles: " + bs.length); - for (BundleDescription b : bs) { - System.out.format("%-80s @ %s\n", b.toString(), b.getLocation()); - } - } - -} - +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics; + +import static org.simantics.db.common.utils.Transaction.commit; +import static org.simantics.db.common.utils.Transaction.endTransaction; +import static org.simantics.db.common.utils.Transaction.readGraph; +import static org.simantics.db.common.utils.Transaction.startTransaction; +import static org.simantics.db.common.utils.Transaction.writeGraph; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; + +import org.eclipse.core.runtime.ILog; +import org.eclipse.core.runtime.IProduct; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.osgi.service.resolver.BundleDescription; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.Databoard; +import org.simantics.datatypes.literal.Font; +import org.simantics.datatypes.literal.RGB; +import org.simantics.db.Driver; +import org.simantics.db.Driver.Management; +import org.simantics.db.Manager; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.SessionModel; +import org.simantics.db.UndoContext; +import org.simantics.db.VirtualGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.request.Queries; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.request.WriteResultRequest; +import org.simantics.db.common.utils.Transaction; +import org.simantics.db.exception.ClusterSetExistException; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.indexing.DatabaseIndexing; +import org.simantics.db.layer0.genericrelation.DependenciesRelation; +import org.simantics.db.layer0.util.SimanticsClipboardImpl; +import org.simantics.db.layer0.util.SimanticsKeys; +import org.simantics.db.layer0.util.TGTransferableGraphSource; +import org.simantics.db.layer0.variable.VariableRepository; +import org.simantics.db.management.SessionContext; +import org.simantics.db.request.Read; +import org.simantics.db.service.LifecycleSupport.LifecycleListener; +import org.simantics.db.service.LifecycleSupport.LifecycleState; +import org.simantics.db.service.QueryControl; +import org.simantics.db.service.UndoRedoSupport; +import org.simantics.db.service.VirtualGraphSupport; +import org.simantics.db.service.XSupport; +import org.simantics.graph.db.GraphDependencyAnalyzer; +import org.simantics.graph.db.GraphDependencyAnalyzer.IU; +import org.simantics.graph.db.GraphDependencyAnalyzer.IdentityNode; +import org.simantics.graph.db.IImportAdvisor; +import org.simantics.graph.db.TransferableGraphs; +import org.simantics.graph.diff.Diff; +import org.simantics.graph.diff.TransferableGraphDelta1; +import org.simantics.internal.Activator; +import org.simantics.internal.startup.StartupExtensions; +import org.simantics.layer0.Layer0; +import org.simantics.operation.Layer0X; +import org.simantics.project.IProject; +import org.simantics.project.ProjectFeatures; +import org.simantics.project.ProjectKeys; +import org.simantics.project.Projects; +import org.simantics.project.exception.ProjectException; +import org.simantics.project.features.registry.GroupReference; +import org.simantics.project.management.DatabaseManagement; +import org.simantics.project.management.GraphBundle; +import org.simantics.project.management.GraphBundleEx; +import org.simantics.project.management.GraphBundleRef; +import org.simantics.project.management.PlatformUtil; +import org.simantics.project.management.ServerManager; +import org.simantics.project.management.ServerManagerFactory; +import org.simantics.project.management.WorkspaceUtil; +import org.simantics.utils.FileUtils; +import org.simantics.utils.datastructures.Pair; +import org.simantics.utils.logging.TimeLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * SimanticsPlatform performs procedures required in order to get simantics + * workbench into operational state. This consists of the following steps: + *

    + *
  • Asserting there is Database + *
  • + *
  • Starting Database process + *
  • + *
  • Opening a session to Database process + *
  • + *
  • Asserting required ontologies or other transferable graphs are installed in the database + *
  • + *
  • Asserting required project is installed in the database + *
  • + *
  • Asserting Simantics Features are installed in the database + *
  • + *
  • Asserting Simantics Features are installed to the project + *
  • + *
  • Shutdown: Save Session, Close session, Kill Database process + *
  • + *
+ * + * @author Toni Kalajainen + */ +public class SimanticsPlatform implements LifecycleListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimanticsPlatform.class); + + /** + * The policy is relevant when developing Simantics from Eclipse IDE. + * It is applied when the ontology in the database of a workspace doesn't match + * a newer ontology in the Eclipse workspace. + */ + public static enum OntologyRecoveryPolicy { ThrowError, Merge, ReinstallDatabase } + + /** + * 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"); - ++ ++ // 1.1 ++ XSupport support = session.getService(XSupport.class); ++ if (support.rolledback()) { ++ try { ++ DatabaseIndexing.deleteAllIndexes(); ++ } catch (IOException e) { ++ throw new PlatformException(e); ++ } ++ } ++ + // 2. Assert all graphs, and correct versions, are installed to the database + synchronizeOntologies(progressMonitor, ontologyPolicy, requireSynchronize); + TimeLogger.log("Synchronized ontologies"); + + // 4. Assert simantics.cfg exists + boolean installProject = assertConfiguration(progressMonitor,workspacePolicy); + + // 5. Assert Project Resource is installed in the database + installProject = assertProject(progressMonitor, workspacePolicy, installProject); + + // 6. Install all features into project, if in debug mode + updateInstalledGroups(progressMonitor, installProject); + TimeLogger.log("Installed all features into project"); + + // 7. Assert L0.Session in database for this session + assertSessionModel(progressMonitor); + + session.getService(XSupport.class).setServiceMode(false, false); + + try { + session.sync(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + QueryControl qc = graph.getService(QueryControl.class); + qc.flush(graph); + } + + }); + TimeLogger.log("Flushed queries"); + } catch (DatabaseException e) { + LOGGER.error("Flushing queries failed.", e); + } + boolean loadProject = true; + try { + + sessionContext = SimanticsPlatform.INSTANCE.createSessionContext(true); + // This must be before setSessionContext since some listeners might query this + sessionContext.setHint(SimanticsKeys.KEY_PROJECT, SimanticsPlatform.INSTANCE.projectResource); + + Simantics.setSessionContext(sessionContext); + + // 1. Put ResourceBinding that throws an exception to General Bindings + simanticsBindings = new SimanticsBindings( null ); + Bindings.classBindingFactory.addFactory( simanticsBindings ); + + + // 2. Create session-specific second Binding context (Databoard) and + // put that to Session as a service + Session session = sessionContext.getSession(); + Databoard sessionDataboard = new Databoard(); + session.registerService(Databoard.class, sessionDataboard); + simanticsBindings2 = new SimanticsBindings( session ); + sessionDataboard.classBindingFactory.addFactory( simanticsBindings2 ); + + // Register datatype bindings + Bindings.defaultBindingFactory.getRepository().put(RGB.Integer.BINDING.type(), RGB.Integer.BINDING); + Bindings.defaultBindingFactory.getRepository().put(Font.BINDING.type(), Font.BINDING); + + if(loadProject) { + + TimeLogger.log("Load projects"); + project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource); + + sessionContext.setHint(ProjectKeys.KEY_PROJECT, project); + TimeLogger.log("Loading projects complete"); + + project.activate(); + TimeLogger.log("Project activated"); + } + + } catch (DatabaseException e) { + LOGGER.error("Platform startup failed.", e); + throw new PlatformException(e); + } catch (ProjectException e) { + boolean hasStackTrace = e.getStackTrace().length > 0; + if (!hasStackTrace) + throw new PlatformException(e.getMessage(), hasStackTrace); + throw new PlatformException(e, hasStackTrace); + } + + running = true; + + return sessionContext; + + } + + public SessionContext createSessionContext(boolean init) throws PlatformException { + try { + // Construct and initialize SessionContext from Session. + SessionContext sessionContext = SessionContext.create(session, init); + if (init) + sessionContext.registerServices(); + return sessionContext; + } catch (DatabaseException e) { + throw new PlatformException(e); + } + } + +// private static File getIgnorePrerequisitesFile(URL workspaceUrl) { +// if (workspaceUrl == null) +// return null; +// return new File(workspaceUrl.getPath(), ".ignorePrerequisites"); +// } +// +// private void ensurePrerequisites(IProgressMonitor progressMonitor, PlatformUserAgent userAgent) throws PlatformException { +// Location loc = Platform.getInstanceLocation(); +// File ignorePrerequisites = getIgnorePrerequisitesFile(loc.getURL()); +// if (loc.isSet() && ignorePrerequisites != null) { +// if (ignorePrerequisites.exists() || ignorePrerequisites.isFile()) +// return; +// } +// +// try { +// ServerEnvironment.ensureServerDependenciesMet(); +// } catch (ExecutionEnvironmentException e) { +// // Not installed properly, ask user whether to try installation. +// try { +// StringBuilder msg = new StringBuilder(); +// msg.append("Your system seems to be missing the following prerequisites for running this application:\n\n"); +// for (Product product : e.requiredProducts) +// msg.append("\t" + product.getDescription() + "\n"); +// msg.append("\nYou can either install the missing components now or ignore and attempt to start the application without them. Ignore Always will ignore this question for this workspace."); +// msg.append("\n\nSelecting Cancel will close the application."); +// +// int selection = 0; +// if (userAgent != null) { +// selection = userAgent.showPrompt("Missing Prerequisites", msg.toString(), new String[] { +// "Install Pre-requisites", +// "Ignore Now", +// "Ignore Always", +// "Cancel" +// }, selection); +// } +// boolean tryInstall = false; +// switch (selection) { +// case 0: +// tryInstall = true; +// break; +// case 2: +// ignorePrerequisites.createNewFile(); +// case 1: +// break; +// case 3: +// case -1: +// throw new CancelStartupException(); +// } +// +// if (tryInstall) { +// // Try to install it and check for success afterwards. +// ServerEnvironment.tryInstallDependencies(progressMonitor); +// ServerEnvironment.ensureServerDependenciesMet(); +// } +// } catch (InstallException ie) { +// throw new PlatformException(ie); +// } catch (ExecutionEnvironmentException eee) { +// throw new PlatformException(eee); +// } catch (IOException ie) { +// throw new PlatformException(ie); +// } +// } +// } + + /** + * Shutdown Simantics Platform. + * + * In SWB this is handled in SimanticsWorkbenchAdvisor#disconnectFromWorkspace. + * + * @param progressMonitor optional progress monitor + * @throws PlatformException + */ + public void shutdown(IProgressMonitor progressMonitor) throws PlatformException + { + SubMonitor progress = SubMonitor.convert(progressMonitor, 100); + PlatformException platformException = null; + try { + progress.subTask("Close Project"); + if (project != null) { + project.safeDispose(); + } + progress.worked(10); + + running = false; + progress.subTask("Close Database Session"); + Databoard databoard = null; + if (sessionContext != null) { + Session s = sessionContext.peekSession(); + if (s != null) { + databoard = s.peekService(Databoard.class); + + progress.subTask("Flushing Index Caches"); + try { + Simantics.flushIndexCaches(progress.newChild(20), s); + } catch (Throwable t) { + LOGGER.error("Failed to flush index caches.", t); + } + } + + progress.subTask("Close Database Session"); + sessionContext.safeDispose(); + sessionContext = null; + Simantics.setSessionContext(null); + } + if (simanticsBindings != null) { + Bindings.classBindingFactory.removeFactory( simanticsBindings ); + simanticsBindings = null; + } + if (databoard != null) { + if (simanticsBindings2 != null) { + databoard.classBindingFactory.removeFactory( simanticsBindings2 ); + simanticsBindings2 = null; + } + databoard.clear(); + } + + // Make sure Simantics clipboard doesn't store unwanted session data references. + Simantics.setClipboard(new SimanticsClipboardImpl()); + + progress.worked(30); + + session = null; + projectResource = null; + + DependenciesRelation.assertFinishedTracking(); + + } catch (Exception e) { + platformException = new PlatformException("Failed to shutdown Simantics Platform", e); + } + + progress.worked(10); + progress.subTask("Shutting down database"); + try { + if (null != databasebManagement) + databasebManagement.shutdown(); + } catch (Throwable t) { + LOGGER.error("Database shutdown failed.", t); + } + progress.worked(10); + + progress.subTask("Clearing Workspace Temporary Directory"); + try { + Simantics.clearTemporaryDirectory(); + } catch (Throwable t) { + LOGGER.error("Failed to clear the temporary directory.", t); + } + progress.worked(10); + if (null != platformException) + throw platformException; + } + + // TODO: consider removing this in the future ?? + @Override + public void stateChanged(LifecycleState newState) { + if(newState == LifecycleState.CLOSED) { + if(running) { + if(Platform.isRunning()) { + mainThread.interrupt(); + } + } + } + } + + /** + * @return 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()); + } + } + +} +