1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.db.management;
\r
14 import java.io.IOException;
\r
15 import java.lang.reflect.Method;
\r
16 import java.util.Arrays;
\r
17 import java.util.UUID;
\r
18 import java.util.concurrent.TimeoutException;
\r
20 import org.eclipse.core.runtime.IStatus;
\r
21 import org.simantics.db.Disposable;
\r
22 import org.simantics.db.ReadGraph;
\r
23 import org.simantics.db.ServerReference;
\r
24 import org.simantics.db.Session;
\r
25 import org.simantics.db.SessionManager;
\r
26 import org.simantics.db.SessionReference;
\r
27 import org.simantics.db.VirtualGraph;
\r
28 import org.simantics.db.authentication.UserAuthenticationAgent;
\r
29 import org.simantics.db.common.processor.MergingDelayedWriteProcessor;
\r
30 import org.simantics.db.common.processor.MergingGraphRequestProcessor;
\r
31 import org.simantics.db.common.request.ReadRequest;
\r
32 import org.simantics.db.exception.DatabaseException;
\r
33 import org.simantics.db.exception.InternalException;
\r
34 import org.simantics.db.management.internal.Activator;
\r
35 import org.simantics.db.service.LifecycleSupport;
\r
36 import org.simantics.db.service.VirtualGraphSupport;
\r
37 import org.simantics.db.services.GlobalServiceInitializer;
\r
38 import org.simantics.layer0.Layer0;
\r
39 import org.simantics.utils.datastructures.disposable.DisposeState;
\r
40 import org.simantics.utils.datastructures.disposable.IDisposable;
\r
41 import org.simantics.utils.datastructures.disposable.IDisposeListener;
\r
42 import org.simantics.utils.datastructures.hints.HintContext;
\r
43 import org.simantics.utils.threads.IThreadWorkQueue;
\r
44 import org.simantics.utils.threads.SyncListenerList;
\r
46 import fi.vtt.simantics.procore.ProCoreServerReference;
\r
47 import fi.vtt.simantics.procore.ProCoreSessionReference;
\r
48 import fi.vtt.simantics.procore.SessionManagerSource;
\r
51 * Holds all information that is needed to create and manage a single database
\r
52 * session in the Simantics workbench UI.
\r
54 * @see org.simantics.ui.SimanticsUI
\r
55 * @see org.simantics.db.layer0.util.Simantics
\r
56 * @author Tuukka Lehtonen
\r
58 public class SessionContext extends HintContext implements ISessionContext, Disposable {
\r
59 private static final boolean SESSION_DEBUG = false;
\r
61 // private final IServerAddress address;
\r
63 private Session session;
\r
65 private UserAuthenticationAgent authenticator;
\r
67 private boolean servicesRegistered = false;
\r
69 private IStatus servicesRegisteredStatus = null;
\r
71 public static SessionContext create(Session session, boolean initialize) throws DatabaseException {
\r
72 return new SessionContext(session, initialize);
\r
75 // public static SessionContext openSession(IServerAddress info, UserAuthenticationAgent auth) throws IOException, DatabaseException {
\r
76 // return new SessionContext(info, auth, false);
\r
79 // public static SessionContext openAndInitializeSession(IServerAddress info, UserAuthenticationAgent auth) throws IOException, DatabaseException {
\r
80 // return new SessionContext(info, auth, true);
\r
83 private static SessionReference createSessionReference(/*IServerAddress address,*/ long sessionId) throws InternalException {
\r
84 ProCoreServerReference server = new ProCoreServerReference();
\r
85 ProCoreSessionReference ref = new ProCoreSessionReference(server, sessionId);
\r
89 // private SessionContext(IServerAddress addr, UserAuthenticationAgent auth, boolean initialize) throws IOException, DatabaseException {
\r
90 // if (addr == null)
\r
91 // throw new IllegalArgumentException("null address");
\r
92 //// this.address = addr;
\r
93 // this.authenticator = auth;
\r
95 // SessionManager sessionManager = SessionManagerProvider.getInstance().getSessionManager();
\r
97 // if (initialize) {
\r
98 // initializeSession(sessionManager);
\r
99 // if (SESSION_DEBUG) {
\r
100 // System.err.println("Initialized session: " + addr);
\r
101 // System.err.flush();
\r
104 // SessionReference ref = createSessionReference(SessionManagerSource.NullSessionId);
\r
105 // this.session = sessionManager.createSession(ref, auth);
\r
106 // if (SESSION_DEBUG) {
\r
107 // System.err.println("Opened session: " + addr);
\r
108 // System.err.flush();
\r
114 private SessionContext(Session session, boolean initialize) throws DatabaseException {
\r
116 initializeSession(session);
\r
117 ServerReference ref = session.getService( LifecycleSupport.class ).getSessionReference().getServerReference();
\r
118 // this.address = ref.serverAddress();
\r
119 this.session = session;
\r
122 private void initializeSession(SessionManager sessionManager) throws DatabaseException, IOException {
\r
124 boolean success = false;
\r
126 SessionReference ref = createSessionReference(SessionManagerSource.NullSessionId);
\r
127 s = sessionManager.createSession(ref, authenticator);
\r
128 initializeSession(s);
\r
134 LifecycleSupport support = s.getService(LifecycleSupport.class);
\r
141 private void initializeSession(Session s) throws DatabaseException {
\r
142 s.registerService(MergingGraphRequestProcessor.class, new MergingGraphRequestProcessor("SessionService", s, 20));
\r
143 s.registerService(MergingDelayedWriteProcessor.class, new MergingDelayedWriteProcessor(s, 20));
\r
144 s.registerService(VirtualGraph.class, s.getService(VirtualGraphSupport.class).getMemoryPersistent(UUID.randomUUID().toString()));
\r
146 // Builtins needs to be initialized for the new session before
\r
147 // anything useful can be done with it.
\r
148 s.syncRequest(new ReadRequest() {
\r
150 public void run(ReadGraph g) {
\r
151 // Registers Builtins with the ServiceLocator of the Graph's session.
\r
152 Layer0.getInstance(g);
\r
157 public void registerServices() {
\r
158 if (servicesRegistered)
\r
161 // Register any services available for the SessionLocator of the new
\r
163 servicesRegisteredStatus = new GlobalServiceInitializer().initialize(session);
\r
164 if (!servicesRegisteredStatus.isOK()) {
\r
165 Activator.getDefault().getLog().log(servicesRegisteredStatus);
\r
168 servicesRegistered = true;
\r
172 // public IServerAddress getAddress() {
\r
177 public Session getSession() {
\r
178 if (session == null)
\r
179 throw new IllegalStateException("SessionContext is disposed");
\r
184 public Session peekSession() {
\r
189 * Do dispose procedures. This method is invoked at most once.
\r
191 protected void doDispose() {
\r
194 } catch (Exception e) {
\r
195 throw new RuntimeException(e);
\r
200 public void close() throws IllegalStateException, InterruptedException, TimeoutException {
\r
203 } catch (RuntimeException e) {
\r
204 Throwable t = e.getCause();
\r
205 if (t instanceof RuntimeException) {
\r
206 throw (RuntimeException) t;
\r
207 } else if (t instanceof Error) {
\r
209 } else if (t instanceof InterruptedException) {
\r
210 throw (InterruptedException) t;
\r
211 } else if (t instanceof TimeoutException) {
\r
212 throw (TimeoutException) t;
\r
218 private void doClose() throws DatabaseException {
\r
219 for (Key k : getHints().keySet()) {
\r
221 Object o = removeHint(k);
\r
222 if (o instanceof IDisposable) {
\r
223 ((IDisposable) o).safeDispose();
\r
228 if (session != null) {
\r
229 if (SESSION_DEBUG) {
\r
230 System.err.println("Closing session: " + session/*address*/);
\r
231 System.err.flush();
\r
233 LifecycleSupport support = session.getService(LifecycleSupport.class);
\r
234 support.close(0, true);
\r
240 public int hashCode() {
\r
241 if (session == null) return 0;
\r
242 return session.hashCode();
\r
246 public boolean equals(Object obj) {
\r
249 if (obj == null || getClass() != obj.getClass())
\r
251 final SessionContext other = (SessionContext) obj;
\r
252 // if (!address.equals(other.address))
\r
254 return session.equals(other.session);
\r
258 public String toString() {
\r
259 StringBuilder s = new StringBuilder();
\r
260 s.append("SessionContext [info=" + session + ", hints=");
\r
261 s.append(Arrays.toString(getHints().values().toArray()));
\r
263 return s.toString();
\r
267 // IDisposable implementation (AbstractDisposable)
\r
269 SyncListenerList<IDisposeListener> disposeListeners = null;
\r
271 private DisposeState disposeStatus = DisposeState.Alive;
\r
273 protected void assertNotDisposed() {
\r
275 throw new AssertionError(this + " is disposed.");
\r
279 public DisposeState getDisposeState() {
\r
280 return disposeStatus;
\r
284 public boolean isDisposed() {
\r
285 return disposeStatus == DisposeState.Disposed;
\r
288 public boolean isAlive() {
\r
289 return disposeStatus == DisposeState.Alive;
\r
293 public void dispose() {
\r
295 synchronized (this) {
\r
296 if (disposeStatus == DisposeState.Disposing)
\r
298 assertNotDisposed();
\r
299 disposeStatus = DisposeState.Disposing;
\r
307 synchronized(this) {
\r
308 disposeStatus = DisposeState.Disposed;
\r
314 * Disposes if not disposed
\r
317 public void safeDispose() {
\r
319 synchronized (this) {
\r
320 if (disposeStatus != DisposeState.Alive)
\r
322 disposeStatus = DisposeState.Disposing;
\r
330 synchronized(this) {
\r
331 disposeStatus = DisposeState.Disposed;
\r
336 protected boolean hasDisposeListeners() {
\r
337 return disposeListeners!=null && !disposeListeners.isEmpty();
\r
340 private final static Method onDisposed = SyncListenerList.getMethod(IDisposeListener.class, "onDisposed");
\r
342 private void fireDisposed() {
\r
343 if (disposeListeners==null) return;
\r
344 disposeListeners.fireEventSync(onDisposed, this);
\r
347 @SuppressWarnings("unused")
\r
348 private void fireDisposedAsync() {
\r
349 if (disposeListeners==null) return;
\r
350 disposeListeners.fireEventAsync(onDisposed, this);
\r
354 public void addDisposeListener(IDisposeListener listener) {
\r
355 lazyGetListenerList().add(listener);
\r
359 public void addDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
\r
360 lazyGetListenerList().add(thread, listener);
\r
364 public void removeDisposeListener(IDisposeListener listener) {
\r
365 if (disposeListeners==null) return;
\r
366 disposeListeners.remove(listener);
\r
370 public void removeDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
\r
371 if (disposeListeners==null) return;
\r
372 disposeListeners.remove(thread, listener);
\r
375 private synchronized SyncListenerList<IDisposeListener> lazyGetListenerList()
\r
377 if (disposeListeners==null)
\r
378 disposeListeners = new SyncListenerList<IDisposeListener>(IDisposeListener.class);
\r
379 return disposeListeners;
\r
383 protected void finalize() throws Throwable {
\r