/*******************************************************************************
* 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 java.io.File;
import java.util.UUID;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
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.ReadGraph;
import org.simantics.db.RequestProcessor;
import org.simantics.db.Resource;
import org.simantics.db.Session;
import org.simantics.db.WriteGraph;
import org.simantics.db.common.Indexing;
import org.simantics.db.common.procedure.adapter.ProcedureAdapter;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.exception.RuntimeDatabaseException;
import org.simantics.db.indexing.IndexUtils;
import org.simantics.db.layer0.util.SimanticsClipboard;
import org.simantics.db.layer0.util.SimanticsKeys;
import org.simantics.db.layer0.variable.Variable;
import org.simantics.db.layer0.variable.Variables;
import org.simantics.db.management.ISessionContext;
import org.simantics.db.management.ISessionContextProvider;
import org.simantics.db.management.ISessionContextProviderSource;
import org.simantics.db.management.SessionContextProvider;
import org.simantics.db.management.SingleSessionContextProviderSource;
import org.simantics.db.request.ReadInterface;
import org.simantics.db.request.WriteInterface;
import org.simantics.internal.FileServiceImpl;
import org.simantics.layer0.Layer0;
import org.simantics.project.IProject;
import org.simantics.project.ProjectKeys;
import org.simantics.scl.compiler.top.ValueNotFound;
import org.simantics.scl.osgi.SCLOsgi;
import org.simantics.scl.runtime.SCLContext;
import org.simantics.scl.runtime.function.Function;
import org.simantics.scl.runtime.function.Function1;
import org.simantics.scl.runtime.function.Function2;
import org.simantics.utils.FileService;
import org.simantics.utils.FileUtils;
import org.simantics.utils.TempFiles;
import org.simantics.utils.threads.ThreadUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A facade for accessing basic Simantics platform services. Usable without a
* graphical UI, i.e. in headless contexts.
*
* TODO: in time, move headless functionality of SimanticsUI into this class but
* originals as delegates in SimanticsUI.
*
* TODO: duplicate of org.simantics.db.layer0.util.Simantics, do something about this!!
*/
public class Simantics {
private static final Logger LOGGER = LoggerFactory.getLogger(Simantics.class);
/**
* Default database driver ID
*/
private static final String DEFAULT_DATABASE_DRIVER_ID = "acorn";
private static String defaultDatabaseDriverId = DEFAULT_DATABASE_DRIVER_ID;
private static ISessionContextProviderSource providerSource = null;
private static volatile FileServiceImpl fileService = null;
/**
* Sets the database driver to be used by the platform. To have any effect,
* this must be set before platform startup.
*
* @param id driver id
*/
public static void setDefaultDatabaseDriver(String id) {
defaultDatabaseDriverId = id;
}
/**
* Returns currently set default database driver id.
*/
public static String getDefaultDatabaseDriver() {
return defaultDatabaseDriverId;
}
/**
* @param args
* @param progress
* @return
* @throws PlatformException
*/
public static ISessionContext startUpHeadless(IArguments args, IProgressMonitor progress) throws PlatformException {
if (SimanticsPlatform.INSTANCE.sessionContext != null) {
throw new RuntimeDatabaseException("Simantics is already up and running.");
}
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;
}
if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) {
ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase;
}
if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) {
ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase;
}
if (args.contains(SimanticsArguments.DISABLE_INDEX)) {
Indexing.setDefaultDependenciesIndexingEnabled(false);
}
String databaseDriverId = defaultDatabaseDriverId;
if (args.contains(SimanticsArguments.DATABASE_ID)) {
databaseDriverId = args.get(SimanticsArguments.DATABASE_ID);
Simantics.setDefaultDatabaseDriver(databaseDriverId);
}
int localPort = 0;
if (args.contains(SimanticsArguments.LOCAL_SERVER_PORT)) {
try {
localPort = args.get(SimanticsArguments.LOCAL_SERVER_PORT);
} catch (IllegalArgumentException e) {
throw new PlatformException("Failed to open database session", e);
}
}
// ServerAddress remoteDatabase = null;
// if (args.contains(SimanticsArguments.SERVER)) {
// String serverAddress = args.get(SimanticsArguments.SERVER);
// try {
// remoteDatabase = new ServerAddress(serverAddress);
// } catch (IllegalArgumentException e) {
// throw new PlatformException("Failed to open database session", e);
// }
// }
return startUpHeadless(progress, workspacePolicy, ontologyPolicy, localPort, databaseDriverId /*, remoteDatabase*/);
}
/**
* @param progress
* @param workspacePolicy
* @param ontologyPolicy
* @param localPort
* @param remoteDatabase
* @return
* @throws PlatformException
*/
public static ISessionContext startUpHeadless(IProgressMonitor progress, RecoveryPolicy workspacePolicy, OntologyRecoveryPolicy ontologyPolicy, int localPort, String databaseDriverId) throws PlatformException {
if (SimanticsPlatform.INSTANCE.sessionContext != null) {
throw new RuntimeDatabaseException("Simantics is already up and running.");
}
// Set session context provider.
final ISessionContextProvider provider = new SessionContextProvider(null);
ISessionContextProviderSource source = new SingleSessionContextProviderSource(provider);
setSessionContextProviderSource(source);
org.simantics.db.layer0.internal.SimanticsInternal.setSessionContextProviderSource(source);
if (progress == null)
progress = new NullProgressMonitor();
return SimanticsPlatform.INSTANCE.startUp(databaseDriverId, progress, workspacePolicy, ontologyPolicy, true, new ConsoleUserAgent());
}
/**
* @param progress
* @throws PlatformException
*/
public static void shutdown(IProgressMonitor progress) throws PlatformException {
SimanticsPlatform.INSTANCE.shutdown(progress);
}
/**
* Queue execution of a runnable.
*
* @param runnable
*/
public static void async(Runnable runnable) {
ThreadUtils.getBlockingWorkExecutor().execute(runnable);
}
public static void async(Runnable runnable, int delay, TimeUnit unit) {
ThreadUtils.getTimer().schedule(runnable, delay, unit);
}
public static ScheduledFuture> scheduleAtFixedRate(Runnable runnable, int initialDelay, int period, TimeUnit unit) {
return ThreadUtils.getTimer().scheduleAtFixedRate(runnable, initialDelay, period, unit);
}
/**
* Queue execution of a non-blocking runnable. Use this method with caution.
* A non-blocking runnable nevers locks anything, No Locks, No semaphores,
* No Object.wait(), No synchronized() {} blocks.
*
* @param runnable a non-blocking runnable
*/
public static void asyncNonblocking(Runnable runnable) {
ThreadUtils.getNonBlockingWorkExecutor().execute(runnable);
}
/**
* Schedule execution of a non-blocking runnable. Use this method with caution.
* A non-blocking runnable never locks anything, No Locks, No semaphores,
* No Object,wait(), No synchronized() {} blocks.
*
* @param runnable a non-blocking runnable
* @param initialDelay
* @param period
*/
public static void asyncNonblocking(Runnable runnable, int initialDelay, int period) {
ThreadUtils.getNonBlockingWorkExecutor().scheduleAtFixedRate(runnable, initialDelay, period, TimeUnit.MILLISECONDS);
}
public static synchronized ISessionContext setSessionContext(ISessionContext ctx) {
return getSessionContextProvider().setSessionContext(ctx);
}
public static void setSessionContextProviderSource(ISessionContextProviderSource source) {
if (source == null)
throw new IllegalArgumentException("null provider source");
providerSource = source;
}
public static ISessionContextProviderSource getProviderSource() {
if (providerSource == null)
throw new IllegalStateException(
"providerSource must be initialized by the application before using class Simantics");
return providerSource;
}
public static ISessionContextProvider getSessionContextProvider() {
return getProviderSource().getActive();
}
/**
* Returns the database session context associated with the currently active
* context. This method should be used to retrieve session contexts only
* when the client is sure that the correct context is active.
*
* @return the session context associated with the currently active context
* or null
if the context has no session context
*/
public static ISessionContext getSessionContext() {
ISessionContextProvider provider = getSessionContextProvider();
return provider != null ? provider.getSessionContext() : null;
}
/**
* Returns the database Session bound to the currently active context.
*
*
* The method always returns a non-null Session or produces an * IllegalStateException if a Session was not attainable. *
* * @return the Session bound to the currently active workbench window * @throws IllegalStateException if no Session was available */ public static Session getSession() { ISessionContext ctx = getSessionContext(); if (ctx == null) throw new IllegalStateException("Session unavailable, no database session open"); return ctx.getSession(); } public static RequestProcessor getAvailableRequestProcessor() { Object graph = SCLContext.getCurrent().get("graph"); if(graph instanceof ReadGraph) return (RequestProcessor)graph; else return Simantics.getSession(); } /** * Returns the database Session bound to the currently active context. * Differently from {@link #getSession()}, this method returns *null
if there is no current Session available.
*
* @see #getSession()
* @return the Session bound to the currently active context or
* null
*/
public static Session peekSession() {
ISessionContext ctx = getSessionContext();
return ctx == null ? null : ctx.peekSession();
}
/**
* @return the currently open and active project as a Resource
* @throws IllegalStateException if there is no currently active database
* session, which also means there is no active project at the
* moment
*/
public static Resource getProjectResource() {
ISessionContext ctx = getSessionContext();
if (ctx == null)
throw new IllegalStateException("No current database session");
Resource project = ctx.getHint(SimanticsKeys.KEY_PROJECT);
if (project == null)
throw new IllegalStateException("No current project resource in session context " + ctx);
return project;
}
/**
* @return the currently open and active project as a {@link Resource}
*/
public static Resource peekProjectResource() {
ISessionContext ctx = getSessionContext();
return ctx != null ? ctx.null
if there is no active session or project
*/
public static IProject peekProject() {
ISessionContext ctx = getSessionContext();
return ctx == null ? null : ctx.