1 /*******************************************************************************
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.management;
14 import java.lang.reflect.Method;
15 import java.util.Arrays;
16 import java.util.UUID;
17 import java.util.concurrent.TimeoutException;
19 import org.eclipse.core.runtime.IStatus;
20 import org.simantics.db.Disposable;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.Session;
23 import org.simantics.db.VirtualGraph;
24 import org.simantics.db.common.processor.MergingDelayedWriteProcessor;
25 import org.simantics.db.common.processor.MergingGraphRequestProcessor;
26 import org.simantics.db.common.request.ReadRequest;
27 import org.simantics.db.exception.DatabaseException;
28 import org.simantics.db.management.internal.Activator;
29 import org.simantics.db.service.LifecycleSupport;
30 import org.simantics.db.service.VirtualGraphSupport;
31 import org.simantics.db.services.GlobalServiceInitializer;
32 import org.simantics.layer0.Layer0;
33 import org.simantics.utils.datastructures.disposable.DisposeState;
34 import org.simantics.utils.datastructures.disposable.IDisposable;
35 import org.simantics.utils.datastructures.disposable.IDisposeListener;
36 import org.simantics.utils.datastructures.hints.HintContext;
37 import org.simantics.utils.threads.IThreadWorkQueue;
38 import org.simantics.utils.threads.SyncListenerList;
41 * Holds all information that is needed to create and manage a single database
42 * session in the Simantics workbench UI.
44 * @see org.simantics.ui.SimanticsUI
45 * @see org.simantics.db.layer0.util.Simantics
46 * @author Tuukka Lehtonen
48 public class SessionContext extends HintContext implements ISessionContext, Disposable {
49 private static final boolean SESSION_DEBUG = false;
51 // private final IServerAddress address;
53 private Session session;
55 private boolean servicesRegistered = false;
57 private IStatus servicesRegisteredStatus = null;
59 public static SessionContext create(Session session, boolean initialize) throws DatabaseException {
60 return new SessionContext(session, initialize);
63 private SessionContext(Session session, boolean initialize) throws DatabaseException {
65 initializeSession(session);
66 this.session = session;
69 private void initializeSession(Session s) throws DatabaseException {
70 s.registerService(MergingGraphRequestProcessor.class, new MergingGraphRequestProcessor("SessionService", s, 20));
71 s.registerService(MergingDelayedWriteProcessor.class, new MergingDelayedWriteProcessor(s, 20));
72 s.registerService(VirtualGraph.class, s.getService(VirtualGraphSupport.class).getMemoryPersistent(UUID.randomUUID().toString()));
74 // Builtins needs to be initialized for the new session before
75 // anything useful can be done with it.
76 s.syncRequest(new ReadRequest() {
78 public void run(ReadGraph g) {
79 // Registers Builtins with the ServiceLocator of the Graph's session.
80 Layer0.getInstance(g);
85 public void registerServices() {
86 if (servicesRegistered)
89 // Register any services available for the SessionLocator of the new
91 servicesRegisteredStatus = new GlobalServiceInitializer().initialize(session);
92 if (!servicesRegisteredStatus.isOK()) {
93 Activator.getDefault().getLog().log(servicesRegisteredStatus);
96 servicesRegistered = true;
100 // public IServerAddress getAddress() {
105 public Session getSession() {
107 throw new IllegalStateException("SessionContext is disposed");
112 public Session peekSession() {
117 * Do dispose procedures. This method is invoked at most once.
119 protected void doDispose() {
122 } catch (Exception e) {
123 throw new RuntimeException(e);
128 public void close() throws IllegalStateException, InterruptedException, TimeoutException {
131 } catch (RuntimeException e) {
132 Throwable t = e.getCause();
133 if (t instanceof RuntimeException) {
134 throw (RuntimeException) t;
135 } else if (t instanceof Error) {
137 } else if (t instanceof InterruptedException) {
138 throw (InterruptedException) t;
139 } else if (t instanceof TimeoutException) {
140 throw (TimeoutException) t;
146 private void doClose() throws DatabaseException {
147 for (Key k : getHints().keySet()) {
149 Object o = removeHint(k);
150 if (o instanceof IDisposable) {
151 ((IDisposable) o).safeDispose();
156 if (session != null) {
158 System.err.println("Closing session: " + session/*address*/);
161 LifecycleSupport support = session.getService(LifecycleSupport.class);
162 support.close(0, true);
168 public int hashCode() {
169 if (session == null) return 0;
170 return session.hashCode();
174 public boolean equals(Object obj) {
177 if (obj == null || getClass() != obj.getClass())
179 final SessionContext other = (SessionContext) obj;
180 // if (!address.equals(other.address))
182 return session.equals(other.session);
186 public String toString() {
187 StringBuilder s = new StringBuilder();
188 s.append("SessionContext [info=" + session + ", hints=");
189 s.append(Arrays.toString(getHints().values().toArray()));
195 // IDisposable implementation (AbstractDisposable)
197 SyncListenerList<IDisposeListener> disposeListeners = null;
199 private DisposeState disposeStatus = DisposeState.Alive;
201 protected void assertNotDisposed() {
203 throw new AssertionError(this + " is disposed.");
207 public DisposeState getDisposeState() {
208 return disposeStatus;
212 public boolean isDisposed() {
213 return disposeStatus == DisposeState.Disposed;
216 public boolean isAlive() {
217 return disposeStatus == DisposeState.Alive;
221 public void dispose() {
223 synchronized (this) {
224 if (disposeStatus == DisposeState.Disposing)
227 disposeStatus = DisposeState.Disposing;
236 disposeStatus = DisposeState.Disposed;
242 * Disposes if not disposed
245 public void safeDispose() {
247 synchronized (this) {
248 if (disposeStatus != DisposeState.Alive)
250 disposeStatus = DisposeState.Disposing;
259 disposeStatus = DisposeState.Disposed;
264 protected boolean hasDisposeListeners() {
265 return disposeListeners!=null && !disposeListeners.isEmpty();
268 private final static Method onDisposed = SyncListenerList.getMethod(IDisposeListener.class, "onDisposed");
270 private void fireDisposed() {
271 if (disposeListeners==null) return;
272 disposeListeners.fireEventSync(onDisposed, this);
275 @SuppressWarnings("unused")
276 private void fireDisposedAsync() {
277 if (disposeListeners==null) return;
278 disposeListeners.fireEventAsync(onDisposed, this);
282 public void addDisposeListener(IDisposeListener listener) {
283 lazyGetListenerList().add(listener);
287 public void addDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
288 lazyGetListenerList().add(thread, listener);
292 public void removeDisposeListener(IDisposeListener listener) {
293 if (disposeListeners==null) return;
294 disposeListeners.remove(listener);
298 public void removeDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
299 if (disposeListeners==null) return;
300 disposeListeners.remove(thread, listener);
303 private synchronized SyncListenerList<IDisposeListener> lazyGetListenerList()
305 if (disposeListeners==null)
306 disposeListeners = new SyncListenerList<IDisposeListener>(IDisposeListener.class);
307 return disposeListeners;
311 protected void finalize() throws Throwable {