-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics;\r
-\r
-import java.io.File;\r
-import java.util.UUID;\r
-import java.util.concurrent.ScheduledFuture;\r
-import java.util.concurrent.TimeUnit;\r
-\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.core.runtime.NullProgressMonitor;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.simantics.SimanticsPlatform.OntologyRecoveryPolicy;\r
-import org.simantics.SimanticsPlatform.RecoveryPolicy;\r
-import org.simantics.application.arguments.IArguments;\r
-import org.simantics.application.arguments.SimanticsArguments;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.procedure.adapter.ProcedureAdapter;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.RuntimeDatabaseException;\r
-import org.simantics.db.indexing.IndexUtils;\r
-import org.simantics.db.layer0.util.SimanticsClipboard;\r
-import org.simantics.db.layer0.util.SimanticsKeys;\r
-import org.simantics.db.layer0.variable.Variable;\r
-import org.simantics.db.layer0.variable.Variables;\r
-import org.simantics.db.management.ISessionContext;\r
-import org.simantics.db.management.ISessionContextProvider;\r
-import org.simantics.db.management.ISessionContextProviderSource;\r
-import org.simantics.db.management.SessionContextProvider;\r
-import org.simantics.db.management.SingleSessionContextProviderSource;\r
-import org.simantics.db.request.ReadInterface;\r
-import org.simantics.db.request.WriteInterface;\r
-import org.simantics.internal.FileServiceImpl;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.project.IProject;\r
-import org.simantics.project.ProjectKeys;\r
-import org.simantics.scl.compiler.top.ValueNotFound;\r
-import org.simantics.scl.osgi.SCLOsgi;\r
-import org.simantics.scl.runtime.SCLContext;\r
-import org.simantics.scl.runtime.function.Function;\r
-import org.simantics.scl.runtime.function.Function1;\r
-import org.simantics.scl.runtime.function.Function2;\r
-import org.simantics.utils.FileService;\r
-import org.simantics.utils.FileUtils;\r
-import org.simantics.utils.TempFiles;\r
-import org.simantics.utils.threads.ThreadUtils;\r
-\r
-/**\r
- * A facade for accessing basic Simantics platform services. Usable without a\r
- * graphical UI, i.e. in headless contexts.\r
- *\r
- * TODO: in time, move headless functionality of SimanticsUI into this class but\r
- * originals as delegates in SimanticsUI.\r
- *\r
- * TODO: duplicate of org.simantics.db.layer0.util.Simantics, do something about this!!\r
- */\r
-public class Simantics {\r
-\r
- private static ISessionContextProviderSource providerSource = null;\r
- private static volatile FileServiceImpl fileService = null;\r
-\r
- /**\r
- * @param args\r
- * @param progress\r
- * @return\r
- * @throws PlatformException\r
- */\r
- public static ISessionContext startUpHeadless(IArguments args, IProgressMonitor progress) throws PlatformException {\r
- if (SimanticsPlatform.INSTANCE.sessionContext != null) {\r
- throw new RuntimeDatabaseException("Simantics is already up and running.");\r
- }\r
-\r
- RecoveryPolicy workspacePolicy = Platform.inDevelopmentMode() ? RecoveryPolicy.FixError : RecoveryPolicy.ThrowError;\r
- OntologyRecoveryPolicy ontologyPolicy = Platform.inDevelopmentMode() ? OntologyRecoveryPolicy.Merge : OntologyRecoveryPolicy.ThrowError;\r
-\r
- if (args.contains(SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS)) {\r
- workspacePolicy = RecoveryPolicy.FixError;\r
- ontologyPolicy = OntologyRecoveryPolicy.Merge;\r
- }\r
-\r
- if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) {\r
- ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase;\r
- }\r
-\r
- if (args.contains(SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL)) {\r
- ontologyPolicy = OntologyRecoveryPolicy.ReinstallDatabase;\r
- }\r
-\r
- int localPort = 0;\r
- if (args.contains(SimanticsArguments.LOCAL_SERVER_PORT)) {\r
- try {\r
- localPort = args.get(SimanticsArguments.LOCAL_SERVER_PORT);\r
- } catch (IllegalArgumentException e) {\r
- throw new PlatformException("Failed to open database session", e);\r
- }\r
- }\r
-\r
-// ServerAddress remoteDatabase = null;\r
-// if (args.contains(SimanticsArguments.SERVER)) {\r
-// String serverAddress = args.get(SimanticsArguments.SERVER);\r
-// try {\r
-// remoteDatabase = new ServerAddress(serverAddress);\r
-// } catch (IllegalArgumentException e) {\r
-// throw new PlatformException("Failed to open database session", e);\r
-// }\r
-// }\r
-\r
- return startUpHeadless(progress, workspacePolicy, ontologyPolicy, localPort /*, remoteDatabase*/);\r
- }\r
-\r
- /**\r
- * @param progress\r
- * @param workspacePolicy\r
- * @param ontologyPolicy\r
- * @param localPort\r
- * @param remoteDatabase\r
- * @return\r
- * @throws PlatformException\r
- */\r
- public static ISessionContext startUpHeadless(IProgressMonitor progress, RecoveryPolicy workspacePolicy, OntologyRecoveryPolicy ontologyPolicy, int localPort) throws PlatformException {\r
- if (SimanticsPlatform.INSTANCE.sessionContext != null) {\r
- throw new RuntimeDatabaseException("Simantics is already up and running.");\r
- }\r
-\r
- // Set session context provider.\r
- final ISessionContextProvider provider = new SessionContextProvider(null);\r
- ISessionContextProviderSource source = new SingleSessionContextProviderSource(provider);\r
- setSessionContextProviderSource(source);\r
- org.simantics.db.layer0.internal.SimanticsInternal.setSessionContextProviderSource(source);\r
-\r
- if (progress == null)\r
- progress = new NullProgressMonitor();\r
- return SimanticsPlatform.INSTANCE.startUp(null, progress, workspacePolicy, ontologyPolicy, true, new ConsoleUserAgent());\r
- }\r
-\r
- /**\r
- * @param progress\r
- * @throws PlatformException\r
- */\r
- public static void shutdown(IProgressMonitor progress) throws PlatformException {\r
- SimanticsPlatform.INSTANCE.shutdown(progress);\r
- }\r
-\r
- /**\r
- * Queue execution of a runnable.\r
- *\r
- * @param runnable\r
- */\r
- public static void async(Runnable runnable) {\r
- ThreadUtils.getBlockingWorkExecutor().execute(runnable);\r
- }\r
-\r
- public static void async(Runnable runnable, int delay, TimeUnit unit) {\r
- ThreadUtils.getTimer().schedule(runnable, delay, unit);\r
- }\r
-\r
- public static ScheduledFuture<?> scheduleAtFixedRate(Runnable runnable, int initialDelay, int period, TimeUnit unit) {\r
- return ThreadUtils.getTimer().scheduleAtFixedRate(runnable, initialDelay, period, unit);\r
- }\r
-\r
- /**\r
- * Queue execution of a non-blocking runnable. Use this method with caution.\r
- * A non-blocking runnable nevers locks anything, No Locks, No semaphores,\r
- * No Object.wait(), No synchronized() {} blocks.\r
- *\r
- * @param runnable a non-blocking runnable\r
- */\r
- public static void asyncNonblocking(Runnable runnable) {\r
- ThreadUtils.getNonBlockingWorkExecutor().execute(runnable);\r
- }\r
-\r
- /**\r
- * Schedule execution of a non-blocking runnable. Use this method with caution.\r
- * A non-blocking runnable never locks anything, No Locks, No semaphores,\r
- * No Object,wait(), No synchronized() {} blocks.\r
- *\r
- * @param runnable a non-blocking runnable\r
- * @param initialDelay\r
- * @param period\r
- */\r
- public static void asyncNonblocking(Runnable runnable, int initialDelay, int period) {\r
- ThreadUtils.getNonBlockingWorkExecutor().scheduleAtFixedRate(runnable, initialDelay, period, TimeUnit.MILLISECONDS);\r
- }\r
-\r
- public static synchronized ISessionContext setSessionContext(ISessionContext ctx) {\r
- return getSessionContextProvider().setSessionContext(ctx);\r
- }\r
-\r
- public static void setSessionContextProviderSource(ISessionContextProviderSource source) {\r
- if (source == null)\r
- throw new IllegalArgumentException("null provider source");\r
- providerSource = source;\r
- }\r
-\r
- public static ISessionContextProviderSource getProviderSource() {\r
- if (providerSource == null)\r
- throw new IllegalStateException(\r
- "providerSource must be initialized by the application before using class Simantics");\r
- return providerSource;\r
- }\r
-\r
- public static ISessionContextProvider getSessionContextProvider() {\r
- return getProviderSource().getActive();\r
- }\r
-\r
- /**\r
- * Returns the database session context associated with the currently active\r
- * context. This method should be used to retrieve session contexts only\r
- * when the client is sure that the correct context is active.\r
- *\r
- * @return the session context associated with the currently active context\r
- * or <code>null</code> if the context has no session context\r
- */\r
- public static ISessionContext getSessionContext() {\r
- ISessionContextProvider provider = getSessionContextProvider();\r
- return provider != null ? provider.getSessionContext() : null;\r
- }\r
-\r
- /**\r
- * Returns the database Session bound to the currently active context.\r
- *\r
- * <p>\r
- * The method always returns a non-null Session or produces an\r
- * IllegalStateException if a Session was not attainable.\r
- * </p>\r
- *\r
- * @return the Session bound to the currently active workbench window\r
- * @throws IllegalStateException if no Session was available\r
- */\r
- public static Session getSession() {\r
- ISessionContext ctx = getSessionContext();\r
- if (ctx == null)\r
- throw new IllegalStateException("Session unavailable, no database session open");\r
- return ctx.getSession();\r
- }\r
-\r
- /**\r
- * Returns the database Session bound to the currently active context.\r
- * Differently from {@link #getSession()}, this method returns\r
- * <code>null</code> if there is no current Session available.\r
- *\r
- * @see #getSession()\r
- * @return the Session bound to the currently active context or\r
- * <code>null</code>\r
- */\r
- public static Session peekSession() {\r
- ISessionContext ctx = getSessionContext();\r
- return ctx == null ? null : ctx.peekSession();\r
- }\r
-\r
- /**\r
- * @return the currently open and active project as a Resource\r
- * @throws IllegalStateException if there is no currently active database\r
- * session, which also means there is no active project at the\r
- * moment\r
- */\r
- public static Resource getProjectResource() {\r
- ISessionContext ctx = getSessionContext();\r
- if (ctx == null)\r
- throw new IllegalStateException("No current database session");\r
- Resource project = ctx.getHint(SimanticsKeys.KEY_PROJECT);\r
- if (project == null)\r
- throw new IllegalStateException("No current project resource in session context " + ctx);\r
- return project;\r
- }\r
-\r
- /**\r
- * @return the currently open and active project as a {@link Resource}\r
- */\r
- public static Resource peekProjectResource() {\r
- ISessionContext ctx = getSessionContext();\r
- return ctx != null ? ctx.<Resource>getHint(SimanticsKeys.KEY_PROJECT) : null;\r
- }\r
-\r
- /**\r
- * @return the currently open and active project as an {@link IProject}\r
- * @throws IllegalStateException if there is no currently active database\r
- * session, which also means there is no active project at the\r
- * moment\r
- */\r
- public static IProject getProject() {\r
- ISessionContext ctx = getSessionContext();\r
- if (ctx == null)\r
- throw new IllegalStateException("No current database session");\r
- IProject project = ctx.getHint(ProjectKeys.KEY_PROJECT);\r
- if (project == null)\r
- throw new IllegalStateException("No current project in session context " + ctx);\r
- return project;\r
- }\r
-\r
- /**\r
- * @return the currently open and active project as an {@link IProject} or\r
- * <code>null</code> if there is no active session or project\r
- */\r
- public static IProject peekProject() {\r
- ISessionContext ctx = getSessionContext();\r
- return ctx == null ? null : ctx.<IProject>getHint(ProjectKeys.KEY_PROJECT);\r
- }\r
-\r
- // FIXME: once org.simantics.db.layer0.util.Simantics is gone, re-enable this\r
-// private static SimanticsClipboard clipboard = SimanticsClipboard.EMPTY;\r
-\r
- /**\r
- * @param content\r
- */\r
- public static void setClipboard(SimanticsClipboard content) {\r
- // FIXME: once org.simantics.db.layer0.util.Simantics is gone, re-enable this\r
-// if (content == null)\r
-// throw new NullPointerException("null clipboard content");\r
-// clipboard = content;\r
- org.simantics.db.layer0.internal.SimanticsInternal.setClipboard(content);\r
- }\r
-\r
- public static SimanticsClipboard getClipboard() {\r
- // FIXME: once org.simantics.db.layer0.util.Simantics is gone, re-enable this\r
- //return clipboard;\r
- return org.simantics.db.layer0.internal.SimanticsInternal.getClipboard();\r
- }\r
-\r
- public static Layer0 getLayer0() throws DatabaseException {\r
- return Layer0.getInstance(getSession());\r
- }\r
-\r
- public static <T> T sync(ReadInterface<T> r) throws DatabaseException {\r
- return getSession().sync(r);\r
- }\r
-\r
- public static <T> T sync(WriteInterface<T> r) throws DatabaseException {\r
- return getSession().sync(r);\r
- }\r
-\r
- public static <T> void async(ReadInterface<T> r) {\r
- getSession().async(r, new ProcedureAdapter<T>());\r
- }\r
-\r
- public static <T> void async(WriteInterface<T> r) {\r
- getSession().async(r);\r
- }\r
-\r
- public static void clearTemporaryDirectory() {\r
- FileUtils.deleteDir(getTemporaryDirectory());\r
- }\r
-\r
- public static File getTempfile(String directory, String suffix) {\r
- File dir = getTemporaryDirectory(directory);\r
- return new File(dir, UUID.randomUUID().toString() + "." + suffix);\r
- }\r
-\r
- public static File getTemporaryDirectory(String directory) {\r
- File sub = new File(getTemporaryDirectory(), directory);\r
- sub.mkdirs();\r
- return sub;\r
- }\r
-\r
- public static File getTemporaryDirectory() {\r
- File workspace = Platform.getLocation().toFile();\r
- File temp = new File(workspace, "tempFiles");\r
- temp.mkdirs();\r
- return temp;\r
- }\r
-\r
- public static TempFiles getTempFiles() {\r
- return TEMP_FILES;\r
- }\r
-\r
- private static class TempFilesImpl implements TempFiles {\r
- private final TempFilesImpl parent;\r
- private final String prefix;\r
- private final String fullPrefix;\r
-\r
- private TempFilesImpl(TempFilesImpl parent, String directory) {\r
- this.parent = parent;\r
- this.prefix = directory;\r
- this.fullPrefix = getPrefix(new StringBuilder()).toString();\r
- }\r
-\r
- private StringBuilder getPrefix(StringBuilder sb) {\r
- if (parent != null)\r
- parent.getPrefix(sb);\r
- if (prefix != null && !prefix.isEmpty())\r
- sb.append(prefix).append(File.separatorChar);\r
- return sb;\r
- }\r
-\r
- @Override\r
- public File getRoot() {\r
- return Simantics.getTemporaryDirectory(fullPrefix);\r
- }\r
-\r
- @Override\r
- public File getTempfile(String directory, String suffix) {\r
- return Simantics.getTempfile(fullPrefix.isEmpty() ? directory : fullPrefix + directory, suffix);\r
- }\r
-\r
- @Override\r
- public TempFiles subdirectory(String directory) {\r
- return new TempFilesImpl(this, directory);\r
- }\r
- }\r
-\r
- public static TempFiles TEMP_FILES = new TempFilesImpl(null, null);\r
-\r
- public static void flushIndexCaches(IProgressMonitor progress, Session session) {\r
- try {\r
- IndexUtils.flushIndexCaches(progress, session);\r
- } catch (Exception e) {\r
- Logger.defaultLogError(e);\r
- }\r
- }\r
-\r
-\r
- @SuppressWarnings({ "unchecked", "rawtypes" })\r
- public static <T> T applySCL(String module, String function, ReadGraph graph, Object ... args) throws DatabaseException {\r
- SCLContext sclContext = SCLContext.getCurrent();\r
- Object oldGraph = sclContext.put("graph", graph);\r
- try {\r
- T t = (T)((Function)SCLOsgi.MODULE_REPOSITORY.getValue(module, function)).applyArray(args);\r
- return t;\r
- } catch (ValueNotFound e) {\r
- throw new DatabaseException("SCL Value not found: " + e.name);\r
- } catch (Throwable t) {\r
- throw new DatabaseException(t);\r
- } finally {\r
- sclContext.put("graph", oldGraph);\r
- }\r
-\r
- }\r
-\r
- @SuppressWarnings("unchecked")\r
- public static <T> T applySCLWrite(WriteGraph graph, @SuppressWarnings("rawtypes") Function f, Object ... args) throws DatabaseException {\r
- SCLContext sclContext = SCLContext.getCurrent();\r
- Object oldGraph = sclContext.put("graph", graph);\r
- try {\r
- return (T)f.applyArray(args);\r
- } catch (Throwable t) {\r
- throw new DatabaseException(t);\r
- } finally {\r
- sclContext.put("graph", oldGraph);\r
- }\r
- }\r
-\r
- @SuppressWarnings("unchecked")\r
- public static <T> T applySCLRead(ReadGraph graph, @SuppressWarnings("rawtypes") Function f, Object ... args) throws DatabaseException {\r
- SCLContext sclContext = SCLContext.getCurrent();\r
- Object oldGraph = sclContext.put("graph", graph);\r
- try {\r
- return (T)f.applyArray(args);\r
- } catch (Throwable t) {\r
- throw new DatabaseException(t);\r
- } finally {\r
- sclContext.put("graph", oldGraph);\r
- }\r
- }\r
- \r
- public static <P0,R> R applySCLWrite(WriteGraph graph, Function1<P0,R> function, P0 p0) throws DatabaseException {\r
- SCLContext sclContext = SCLContext.getCurrent();\r
- Object oldGraph = sclContext.put("graph", graph);\r
- try {\r
- return function.apply(p0);\r
- } catch (Throwable t) {\r
- throw new DatabaseException(t);\r
- } finally {\r
- sclContext.put("graph", oldGraph);\r
- }\r
- }\r
-\r
- public static <P0,R> R applySCLRead(ReadGraph graph, Function1<P0,R> function, P0 p0) throws DatabaseException {\r
- SCLContext sclContext = SCLContext.getCurrent();\r
- Object oldGraph = sclContext.put("graph", graph);\r
- try {\r
- return function.apply(p0);\r
- } catch (Throwable t) {\r
- throw new DatabaseException(t);\r
- } finally {\r
- sclContext.put("graph", oldGraph);\r
- }\r
- }\r
-\r
- public static <P0,P1,R> R applySCLRead(ReadGraph graph, Function2<P0,P1,R> function, P0 p0, P1 p1) throws DatabaseException {\r
- SCLContext sclContext = SCLContext.getCurrent();\r
- Object oldGraph = sclContext.put("graph", graph);\r
- try {\r
- return function.apply(p0, p1);\r
- } catch (Throwable t) {\r
- throw new DatabaseException(t);\r
- } finally {\r
- sclContext.put("graph", oldGraph);\r
- }\r
- }\r
-\r
- public static <P0,R> R invokeSCLWrite(WriteGraph graph, Variable property, P0 p0) throws DatabaseException {\r
- Function1<P0,R> fn = property.getPossibleValue(graph);\r
- if(fn == null) throw new DatabaseException("No function for " + property.getURI(graph));\r
- return Simantics.applySCLWrite(graph, fn, p0);\r
- }\r
-\r
- public static <P0,R> R invokeSCL(ReadGraph graph, Variable property, P0 p0) throws DatabaseException {\r
- Function1<P0,R> fn = property.getPossibleValue(graph);\r
- if(fn == null) throw new DatabaseException("No function for " + property.getURI(graph));\r
- return Simantics.applySCLRead(graph, fn, p0);\r
- }\r
-\r
- public static <P0,P1,R> R invokeSCL(ReadGraph graph, Variable property, P0 p0, P1 p1) throws DatabaseException {\r
- Function2<P0,P1,R> fn = property.getPossibleValue(graph);\r
- if(fn == null) throw new DatabaseException("No function for " + property.getURI(graph));\r
- return Simantics.applySCLRead(graph, fn, p0, p1);\r
- }\r
-\r
- public static <P0,R> R invokeSCLWrite(WriteGraph graph, Resource entity, Resource property, P0 p0) throws DatabaseException {\r
- return invokeSCLWrite(graph, getProperty(graph, entity, property), p0);\r
- }\r
-\r
- public static <P0,R> R invokeSCL(ReadGraph graph, Resource entity, Resource property, P0 p0) throws DatabaseException {\r
- return invokeSCL(graph, getProperty(graph, entity, property), p0);\r
- }\r
-\r
- public static <P0,P1,R> R invokeSCL(ReadGraph graph, Resource entity, Resource property, P0 p0, P1 p1) throws DatabaseException {\r
- return invokeSCL(graph, getProperty(graph, entity, property), p0, p1);\r
- }\r
-\r
- public static <P0,R> R tryInvokeSCL(ReadGraph graph, Resource entity, Resource property, P0 p0) throws DatabaseException {\r
- Variable p = Variables.tryGetProperty(graph, entity, property);\r
- if (p == null)\r
- return null;\r
- return invokeSCL(graph, p, p0);\r
- }\r
-\r
- public static <P0,P1,R> R tryInvokeSCL(ReadGraph graph, Resource entity, Resource property, P0 p0, P1 p1) throws DatabaseException {\r
- Variable p = Variables.tryGetProperty(graph, entity, property);\r
- if (p == null)\r
- return null;\r
- return invokeSCL(graph, p, p0, p1);\r
- }\r
-\r
- private static Variable getProperty(ReadGraph graph, Resource entity, Resource property) throws DatabaseException {\r
- return Variables.getVariable(graph, entity).getProperty(graph, property);\r
- }\r
-\r
- public static boolean ensureMemoryBytes(long bytes) {\r
-\r
- Runtime runtime = Runtime.getRuntime();\r
- long consumedMemory = runtime.totalMemory() - runtime.freeMemory();\r
- long available = runtime.maxMemory() - consumedMemory;\r
-\r
- return available > bytes;\r
-\r
- }\r
-\r
- public static long getDiskBytes() {\r
-\r
- File ws = new File(Platform.getInstanceLocation().getURL().getFile());\r
- return ws.getUsableSpace();\r
-\r
- }\r
-\r
- /**\r
- * @return a service for dealing with recurring file system handling cases\r
- */\r
- public static FileService getFileService() {\r
- FileService fs = fileService;\r
- if (fs == null) {\r
- synchronized (Simantics.class) {\r
- fs = fileService;\r
- if (fs == null)\r
- fs = fileService = new FileServiceImpl();\r
- }\r
- }\r
- return fs;\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * 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 <code>null</code> 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.
+ *
+ * <p>
+ * The method always returns a non-null Session or produces an
+ * IllegalStateException if a Session was not attainable.
+ * </p>
+ *
+ * @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
+ * <code>null</code> if there is no current Session available.
+ *
+ * @see #getSession()
+ * @return the Session bound to the currently active context or
+ * <code>null</code>
+ */
+ 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.<Resource>getHint(SimanticsKeys.KEY_PROJECT) : null;
+ }
+
+ /**
+ * @return the currently open and active project as an {@link IProject}
+ * @throws IllegalStateException if there is no currently active database
+ * session, which also means there is no active project at the
+ * moment
+ */
+ public static IProject getProject() {
+ ISessionContext ctx = getSessionContext();
+ if (ctx == null)
+ throw new IllegalStateException("No current database session");
+ IProject project = ctx.getHint(ProjectKeys.KEY_PROJECT);
+ if (project == null)
+ throw new IllegalStateException("No current project in session context " + ctx);
+ return project;
+ }
+
+ /**
+ * @return the currently open and active project as an {@link IProject} or
+ * <code>null</code> if there is no active session or project
+ */
+ public static IProject peekProject() {
+ ISessionContext ctx = getSessionContext();
+ return ctx == null ? null : ctx.<IProject>getHint(ProjectKeys.KEY_PROJECT);
+ }
+
+ // FIXME: once org.simantics.db.layer0.util.Simantics is gone, re-enable this
+// private static SimanticsClipboard clipboard = SimanticsClipboard.EMPTY;
+
+ /**
+ * @param content
+ */
+ public static void setClipboard(SimanticsClipboard content) {
+ // FIXME: once org.simantics.db.layer0.util.Simantics is gone, re-enable this
+// if (content == null)
+// throw new NullPointerException("null clipboard content");
+// clipboard = content;
+ org.simantics.db.layer0.internal.SimanticsInternal.setClipboard(content);
+ }
+
+ public static SimanticsClipboard getClipboard() {
+ // FIXME: once org.simantics.db.layer0.util.Simantics is gone, re-enable this
+ //return clipboard;
+ return org.simantics.db.layer0.internal.SimanticsInternal.getClipboard();
+ }
+
+ public static Layer0 getLayer0() throws DatabaseException {
+ return Layer0.getInstance(getSession());
+ }
+
+ public static <T> T sync(ReadInterface<T> r) throws DatabaseException {
+ return getSession().sync(r);
+ }
+
+ public static <T> T sync(WriteInterface<T> r) throws DatabaseException {
+ return getSession().sync(r);
+ }
+
+ public static <T> void async(ReadInterface<T> r) {
+ getSession().async(r, new ProcedureAdapter<T>());
+ }
+
+ public static <T> void async(WriteInterface<T> r) {
+ getSession().async(r);
+ }
+
+ public static void clearTemporaryDirectory() {
+ FileUtils.deleteDir(getTemporaryDirectory());
+ }
+
+ public static File getTempfile(String directory, String suffix) {
+ File dir = getTemporaryDirectory(directory);
+ return new File(dir, UUID.randomUUID().toString() + "." + suffix);
+ }
+
+ public static File getTemporaryDirectory(String directory) {
+ File sub = new File(getTemporaryDirectory(), directory);
+ sub.mkdirs();
+ return sub;
+ }
+
+ public static File getTemporaryDirectory() {
+ File workspace = Platform.getLocation().toFile();
+ File temp = new File(workspace, "tempFiles");
+ temp.mkdirs();
+ return temp;
+ }
+
+ public static TempFiles getTempFiles() {
+ return TEMP_FILES;
+ }
+
+ private static class TempFilesImpl implements TempFiles {
+ private final TempFilesImpl parent;
+ private final String prefix;
+ private final String fullPrefix;
+
+ private TempFilesImpl(TempFilesImpl parent, String directory) {
+ this.parent = parent;
+ this.prefix = directory;
+ this.fullPrefix = getPrefix(new StringBuilder()).toString();
+ }
+
+ private StringBuilder getPrefix(StringBuilder sb) {
+ if (parent != null)
+ parent.getPrefix(sb);
+ if (prefix != null && !prefix.isEmpty())
+ sb.append(prefix).append(File.separatorChar);
+ return sb;
+ }
+
+ @Override
+ public File getRoot() {
+ return Simantics.getTemporaryDirectory(fullPrefix);
+ }
+
+ @Override
+ public File getTempfile(String directory, String suffix) {
+ return Simantics.getTempfile(fullPrefix.isEmpty() ? directory : fullPrefix + directory, suffix);
+ }
+
+ @Override
+ public TempFiles subdirectory(String directory) {
+ return new TempFilesImpl(this, directory);
+ }
+ }
+
+ public static TempFiles TEMP_FILES = new TempFilesImpl(null, null);
+
+ public static void flushIndexCaches(IProgressMonitor progress, Session session) {
+ try {
+ IndexUtils.flushIndexCaches(progress, session);
+ } catch (Exception e) {
+ LOGGER.error("Flushing index caches failed.", e);
+ }
+ }
+
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public static <T> T applySCL(String module, String function, Object ... args) throws DatabaseException {
+ try {
+ T t = (T)((Function)SCLOsgi.MODULE_REPOSITORY.getValue(module, function)).applyArray(args);
+ return t;
+ } catch (ValueNotFound e) {
+ throw new DatabaseException("SCL Value not found: " + e.name);
+ } catch (Throwable t) {
+ if (t instanceof DatabaseException)
+ throw (DatabaseException) t;
+ throw new DatabaseException(t);
+ }
+ }
+
+ public static <T> T applySCL(String module, String function, ReadGraph graph, Object ... args) throws DatabaseException {
+ SCLContext sclContext = SCLContext.getCurrent();
+ Object oldGraph = sclContext.put("graph", graph);
+ try {
+ return applySCL(module, function, args);
+ } catch (DatabaseException dbe) {
+ throw dbe;
+ } catch (Throwable t) {
+ throw new DatabaseException(t);
+ } finally {
+ sclContext.put("graph", oldGraph);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T applySCLWrite(WriteGraph graph, @SuppressWarnings("rawtypes") Function f, Object ... args) throws DatabaseException {
+ SCLContext sclContext = SCLContext.getCurrent();
+ Object oldGraph = sclContext.put("graph", graph);
+ try {
+ return (T)f.applyArray(args);
+ } catch (Throwable t) {
+ if (t instanceof DatabaseException)
+ throw (DatabaseException) t;
+ throw new DatabaseException(t);
+ } finally {
+ sclContext.put("graph", oldGraph);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T applySCLRead(ReadGraph graph, @SuppressWarnings("rawtypes") Function f, Object ... args) throws DatabaseException {
+ SCLContext sclContext = SCLContext.getCurrent();
+ Object oldGraph = sclContext.put("graph", graph);
+ try {
+ return (T)f.applyArray(args);
+ } catch (Throwable t) {
+ if (t instanceof DatabaseException)
+ throw (DatabaseException) t;
+ throw new DatabaseException(t);
+ } finally {
+ sclContext.put("graph", oldGraph);
+ }
+ }
+
+ public static <P0,R> R applySCLWrite(WriteGraph graph, Function1<P0,R> function, P0 p0) throws DatabaseException {
+ SCLContext sclContext = SCLContext.getCurrent();
+ Object oldGraph = sclContext.put("graph", graph);
+ try {
+ return function.apply(p0);
+ } catch (Throwable t) {
+ if (t instanceof DatabaseException)
+ throw (DatabaseException) t;
+ throw new DatabaseException(t);
+ } finally {
+ sclContext.put("graph", oldGraph);
+ }
+ }
+
+ public static <P0,R> R applySCLRead(ReadGraph graph, Function1<P0,R> function, P0 p0) throws DatabaseException {
+ SCLContext sclContext = SCLContext.getCurrent();
+ Object oldGraph = sclContext.put("graph", graph);
+ try {
+ return function.apply(p0);
+ } catch (Throwable t) {
+ if (t instanceof DatabaseException)
+ throw (DatabaseException) t;
+ throw new DatabaseException(t);
+ } finally {
+ sclContext.put("graph", oldGraph);
+ }
+ }
+
+ public static <P0,P1,R> R applySCLRead(ReadGraph graph, Function2<P0,P1,R> function, P0 p0, P1 p1) throws DatabaseException {
+ SCLContext sclContext = SCLContext.getCurrent();
+ Object oldGraph = sclContext.put("graph", graph);
+ try {
+ return function.apply(p0, p1);
+ } catch (Throwable t) {
+ if (t instanceof DatabaseException)
+ throw (DatabaseException) t;
+ throw new DatabaseException(t);
+ } finally {
+ sclContext.put("graph", oldGraph);
+ }
+ }
+
+ public static <P0,R> R invokeSCLWrite(WriteGraph graph, Variable property, P0 p0) throws DatabaseException {
+ Function1<P0,R> fn = property.getPossibleValue(graph);
+ if(fn == null) throw new DatabaseException("No function for " + property.getURI(graph));
+ return Simantics.applySCLWrite(graph, fn, p0);
+ }
+
+ public static <P0,R> R invokeSCL(ReadGraph graph, Variable property, P0 p0) throws DatabaseException {
+ Function1<P0,R> fn = property.getPossibleValue(graph);
+ if(fn == null) throw new DatabaseException("No function for " + property.getURI(graph));
+ return Simantics.applySCLRead(graph, fn, p0);
+ }
+
+ public static <P0,P1,R> R invokeSCL(ReadGraph graph, Variable property, P0 p0, P1 p1) throws DatabaseException {
+ Function2<P0,P1,R> fn = property.getPossibleValue(graph);
+ if(fn == null) throw new DatabaseException("No function for " + property.getURI(graph));
+ return Simantics.applySCLRead(graph, fn, p0, p1);
+ }
+
+ public static <P0,R> R invokeSCLWrite(WriteGraph graph, Resource entity, Resource property, P0 p0) throws DatabaseException {
+ return invokeSCLWrite(graph, getProperty(graph, entity, property), p0);
+ }
+
+ public static <P0,R> R invokeSCL(ReadGraph graph, Resource entity, Resource property, P0 p0) throws DatabaseException {
+ return invokeSCL(graph, getProperty(graph, entity, property), p0);
+ }
+
+ public static <P0,P1,R> R invokeSCL(ReadGraph graph, Resource entity, Resource property, P0 p0, P1 p1) throws DatabaseException {
+ return invokeSCL(graph, getProperty(graph, entity, property), p0, p1);
+ }
+
+ public static <P0,R> R tryInvokeSCL(ReadGraph graph, Resource entity, Resource property, P0 p0) throws DatabaseException {
+ Variable p = Variables.tryGetProperty(graph, entity, property);
+ if (p == null)
+ return null;
+ return invokeSCL(graph, p, p0);
+ }
+
+ public static <P0,P1,R> R tryInvokeSCL(ReadGraph graph, Resource entity, Resource property, P0 p0, P1 p1) throws DatabaseException {
+ Variable p = Variables.tryGetProperty(graph, entity, property);
+ if (p == null)
+ return null;
+ return invokeSCL(graph, p, p0, p1);
+ }
+
+ private static Variable getProperty(ReadGraph graph, Resource entity, Resource property) throws DatabaseException {
+ return Variables.getVariable(graph, entity).getProperty(graph, property);
+ }
+
+ public static boolean ensureMemoryBytes(long bytes) {
+
+ Runtime runtime = Runtime.getRuntime();
+ long consumedMemory = runtime.totalMemory() - runtime.freeMemory();
+ long available = runtime.maxMemory() - consumedMemory;
+
+ return available > bytes;
+
+ }
+
+ public static long getDiskBytes() {
+
+ File ws = new File(Platform.getInstanceLocation().getURL().getFile());
+ return ws.getUsableSpace();
+
+ }
+
+ /**
+ * @return a service for dealing with recurring file system handling cases
+ */
+ public static FileService getFileService() {
+ FileService fs = fileService;
+ if (fs == null) {
+ synchronized (Simantics.class) {
+ fs = fileService;
+ if (fs == null)
+ fs = fileService = new FileServiceImpl();
+ }
+ }
+ return fs;
+ }
+
+}