--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2011 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.db.management;\r
+\r
+import java.io.IOException;\r
+import java.lang.reflect.Method;\r
+import java.util.Arrays;\r
+import java.util.UUID;\r
+import java.util.concurrent.TimeoutException;\r
+\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.simantics.db.Disposable;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.ServerReference;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.SessionManager;\r
+import org.simantics.db.SessionReference;\r
+import org.simantics.db.VirtualGraph;\r
+import org.simantics.db.authentication.UserAuthenticationAgent;\r
+import org.simantics.db.common.processor.MergingDelayedWriteProcessor;\r
+import org.simantics.db.common.processor.MergingGraphRequestProcessor;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.InternalException;\r
+import org.simantics.db.management.internal.Activator;\r
+import org.simantics.db.service.LifecycleSupport;\r
+import org.simantics.db.service.VirtualGraphSupport;\r
+import org.simantics.db.services.GlobalServiceInitializer;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.utils.datastructures.disposable.DisposeState;\r
+import org.simantics.utils.datastructures.disposable.IDisposable;\r
+import org.simantics.utils.datastructures.disposable.IDisposeListener;\r
+import org.simantics.utils.datastructures.hints.HintContext;\r
+import org.simantics.utils.threads.IThreadWorkQueue;\r
+import org.simantics.utils.threads.SyncListenerList;\r
+\r
+import fi.vtt.simantics.procore.ProCoreServerReference;\r
+import fi.vtt.simantics.procore.ProCoreSessionReference;\r
+import fi.vtt.simantics.procore.SessionManagerSource;\r
+\r
+/**\r
+ * Holds all information that is needed to create and manage a single database\r
+ * session in the Simantics workbench UI.\r
+ *\r
+ * @see org.simantics.ui.SimanticsUI\r
+ * @see org.simantics.db.layer0.util.Simantics\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class SessionContext extends HintContext implements ISessionContext, Disposable {\r
+ private static final boolean SESSION_DEBUG = false;\r
+\r
+// private final IServerAddress address;\r
+\r
+ private Session session;\r
+\r
+ private UserAuthenticationAgent authenticator;\r
+\r
+ private boolean servicesRegistered = false;\r
+\r
+ private IStatus servicesRegisteredStatus = null;\r
+\r
+ public static SessionContext create(Session session, boolean initialize) throws DatabaseException {\r
+ return new SessionContext(session, initialize);\r
+ }\r
+\r
+// public static SessionContext openSession(IServerAddress info, UserAuthenticationAgent auth) throws IOException, DatabaseException {\r
+// return new SessionContext(info, auth, false);\r
+// }\r
+//\r
+// public static SessionContext openAndInitializeSession(IServerAddress info, UserAuthenticationAgent auth) throws IOException, DatabaseException {\r
+// return new SessionContext(info, auth, true);\r
+// }\r
+\r
+ private static SessionReference createSessionReference(/*IServerAddress address,*/ long sessionId) throws InternalException {\r
+ ProCoreServerReference server = new ProCoreServerReference();\r
+ ProCoreSessionReference ref = new ProCoreSessionReference(server, sessionId);\r
+ return ref;\r
+ }\r
+\r
+// private SessionContext(IServerAddress addr, UserAuthenticationAgent auth, boolean initialize) throws IOException, DatabaseException {\r
+// if (addr == null)\r
+// throw new IllegalArgumentException("null address");\r
+//// this.address = addr;\r
+// this.authenticator = auth;\r
+//\r
+// SessionManager sessionManager = SessionManagerProvider.getInstance().getSessionManager();\r
+//\r
+// if (initialize) {\r
+// initializeSession(sessionManager);\r
+// if (SESSION_DEBUG) {\r
+// System.err.println("Initialized session: " + addr);\r
+// System.err.flush();\r
+// }\r
+// } else {\r
+// SessionReference ref = createSessionReference(SessionManagerSource.NullSessionId);\r
+// this.session = sessionManager.createSession(ref, auth);\r
+// if (SESSION_DEBUG) {\r
+// System.err.println("Opened session: " + addr);\r
+// System.err.flush();\r
+// }\r
+// }\r
+//\r
+// }\r
+\r
+ private SessionContext(Session session, boolean initialize) throws DatabaseException {\r
+ if (initialize)\r
+ initializeSession(session);\r
+ ServerReference ref = session.getService( LifecycleSupport.class ).getSessionReference().getServerReference();\r
+// this.address = ref.serverAddress();\r
+ this.session = session;\r
+ }\r
+\r
+ private void initializeSession(SessionManager sessionManager) throws DatabaseException, IOException {\r
+ Session s = null;\r
+ boolean success = false;\r
+ try {\r
+ SessionReference ref = createSessionReference(SessionManagerSource.NullSessionId);\r
+ s = sessionManager.createSession(ref, authenticator);\r
+ initializeSession(s);\r
+ this.session = s;\r
+ success = true;\r
+ } finally {\r
+ if (!success) {\r
+ if (s != null) {\r
+ LifecycleSupport support = s.getService(LifecycleSupport.class);\r
+ support.close();\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ private void initializeSession(Session s) throws DatabaseException {\r
+ s.registerService(MergingGraphRequestProcessor.class, new MergingGraphRequestProcessor("SessionService", s, 20));\r
+ s.registerService(MergingDelayedWriteProcessor.class, new MergingDelayedWriteProcessor(s, 20));\r
+ s.registerService(VirtualGraph.class, s.getService(VirtualGraphSupport.class).getMemoryPersistent(UUID.randomUUID().toString()));\r
+\r
+ // Builtins needs to be initialized for the new session before\r
+ // anything useful can be done with it.\r
+ s.syncRequest(new ReadRequest() {\r
+ @Override\r
+ public void run(ReadGraph g) {\r
+ // Registers Builtins with the ServiceLocator of the Graph's session.\r
+ Layer0.getInstance(g);\r
+ }\r
+ });\r
+ }\r
+\r
+ public void registerServices() {\r
+ if (servicesRegistered)\r
+ return;\r
+\r
+ // Register any services available for the SessionLocator of the new\r
+ // Session.\r
+ servicesRegisteredStatus = new GlobalServiceInitializer().initialize(session);\r
+ if (!servicesRegisteredStatus.isOK()) {\r
+ Activator.getDefault().getLog().log(servicesRegisteredStatus);\r
+ }\r
+\r
+ servicesRegistered = true;\r
+ }\r
+\r
+// @Override\r
+// public IServerAddress getAddress() {\r
+// return address;\r
+// }\r
+\r
+ @Override\r
+ public Session getSession() {\r
+ if (session == null)\r
+ throw new IllegalStateException("SessionContext is disposed");\r
+ return session;\r
+ }\r
+\r
+ @Override\r
+ public Session peekSession() {\r
+ return session;\r
+ }\r
+\r
+ /**\r
+ * Do dispose procedures. This method is invoked at most once.\r
+ */\r
+ protected void doDispose() {\r
+ try {\r
+ doClose();\r
+ } catch (Exception e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void close() throws IllegalStateException, InterruptedException, TimeoutException {\r
+ try {\r
+ dispose();\r
+ } catch (RuntimeException e) {\r
+ Throwable t = e.getCause();\r
+ if (t instanceof RuntimeException) {\r
+ throw (RuntimeException) t;\r
+ } else if (t instanceof Error) {\r
+ throw (Error) t;\r
+ } else if (t instanceof InterruptedException) {\r
+ throw (InterruptedException) t;\r
+ } else if (t instanceof TimeoutException) {\r
+ throw (TimeoutException) t;\r
+ }\r
+ throw e;\r
+ }\r
+ }\r
+\r
+ private void doClose() throws DatabaseException {\r
+ for (Key k : getHints().keySet()) {\r
+ if (k != null) {\r
+ Object o = removeHint(k);\r
+ if (o instanceof IDisposable) {\r
+ ((IDisposable) o).safeDispose();\r
+ }\r
+ }\r
+ }\r
+\r
+ if (session != null) {\r
+ if (SESSION_DEBUG) {\r
+ System.err.println("Closing session: " + session/*address*/);\r
+ System.err.flush();\r
+ }\r
+ LifecycleSupport support = session.getService(LifecycleSupport.class);\r
+ support.close(0, true);\r
+ session = null;\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public int hashCode() {\r
+ if (session == null) return 0;\r
+ return session.hashCode();\r
+ }\r
+\r
+ @Override\r
+ public boolean equals(Object obj) {\r
+ if (this == obj)\r
+ return true;\r
+ if (obj == null || getClass() != obj.getClass())\r
+ return false;\r
+ final SessionContext other = (SessionContext) obj;\r
+// if (!address.equals(other.address))\r
+// return false;\r
+ return session.equals(other.session);\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ StringBuilder s = new StringBuilder();\r
+ s.append("SessionContext [info=" + session + ", hints=");\r
+ s.append(Arrays.toString(getHints().values().toArray()));\r
+ s.append("]");\r
+ return s.toString();\r
+ }\r
+\r
+\r
+ // IDisposable implementation (AbstractDisposable)\r
+\r
+ SyncListenerList<IDisposeListener> disposeListeners = null;\r
+\r
+ private DisposeState disposeStatus = DisposeState.Alive;\r
+\r
+ protected void assertNotDisposed() {\r
+ if (isDisposed())\r
+ throw new AssertionError(this + " is disposed.");\r
+ }\r
+\r
+ @Override\r
+ public DisposeState getDisposeState() {\r
+ return disposeStatus;\r
+ }\r
+\r
+ @Override\r
+ public boolean isDisposed() {\r
+ return disposeStatus == DisposeState.Disposed;\r
+ }\r
+\r
+ public boolean isAlive() {\r
+ return disposeStatus == DisposeState.Alive;\r
+ }\r
+\r
+ @Override\r
+ public void dispose() {\r
+ try {\r
+ synchronized (this) {\r
+ if (disposeStatus == DisposeState.Disposing)\r
+ return;\r
+ assertNotDisposed();\r
+ disposeStatus = DisposeState.Disposing;\r
+ }\r
+ try {\r
+ fireDisposed();\r
+ } finally {\r
+ doDispose();\r
+ }\r
+ } finally {\r
+ synchronized(this) {\r
+ disposeStatus = DisposeState.Disposed;\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Disposes if not disposed\r
+ */\r
+ @Override\r
+ public void safeDispose() {\r
+ try {\r
+ synchronized (this) {\r
+ if (disposeStatus != DisposeState.Alive)\r
+ return;\r
+ disposeStatus = DisposeState.Disposing;\r
+ }\r
+ try {\r
+ fireDisposed();\r
+ } finally {\r
+ doDispose();\r
+ }\r
+ } finally {\r
+ synchronized(this) {\r
+ disposeStatus = DisposeState.Disposed;\r
+ }\r
+ }\r
+ }\r
+\r
+ protected boolean hasDisposeListeners() {\r
+ return disposeListeners!=null && !disposeListeners.isEmpty();\r
+ }\r
+\r
+ private final static Method onDisposed = SyncListenerList.getMethod(IDisposeListener.class, "onDisposed");\r
+\r
+ private void fireDisposed() {\r
+ if (disposeListeners==null) return;\r
+ disposeListeners.fireEventSync(onDisposed, this);\r
+ }\r
+\r
+ @SuppressWarnings("unused")\r
+ private void fireDisposedAsync() {\r
+ if (disposeListeners==null) return;\r
+ disposeListeners.fireEventAsync(onDisposed, this);\r
+ }\r
+\r
+ @Override\r
+ public void addDisposeListener(IDisposeListener listener) {\r
+ lazyGetListenerList().add(listener);\r
+ }\r
+\r
+ @Override\r
+ public void addDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {\r
+ lazyGetListenerList().add(thread, listener);\r
+ }\r
+\r
+ @Override\r
+ public void removeDisposeListener(IDisposeListener listener) {\r
+ if (disposeListeners==null) return;\r
+ disposeListeners.remove(listener);\r
+ }\r
+\r
+ @Override\r
+ public void removeDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {\r
+ if (disposeListeners==null) return;\r
+ disposeListeners.remove(thread, listener);\r
+ }\r
+\r
+ private synchronized SyncListenerList<IDisposeListener> lazyGetListenerList()\r
+ {\r
+ if (disposeListeners==null)\r
+ disposeListeners = new SyncListenerList<IDisposeListener>(IDisposeListener.class);\r
+ return disposeListeners;\r
+ }\r
+\r
+ @Override\r
+ protected void finalize() throws Throwable {\r
+ try {\r
+ safeDispose();\r
+ } finally {\r
+ super.finalize();\r
+ }\r
+ }\r
+\r
+}\r