]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.management/src/org/simantics/db/management/SessionContext.java
ef5f270531021b890888c3016ae2f08e8ed096f9
[simantics/platform.git] / bundles / org.simantics.db.management / src / org / simantics / db / management / SessionContext.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.management;
13
14 import java.io.IOException;
15 import java.lang.reflect.Method;
16 import java.util.Arrays;
17 import java.util.UUID;
18 import java.util.concurrent.TimeoutException;
19
20 import org.eclipse.core.runtime.IStatus;
21 import org.simantics.db.Disposable;
22 import org.simantics.db.ReadGraph;
23 import org.simantics.db.ServerReference;
24 import org.simantics.db.Session;
25 import org.simantics.db.SessionManager;
26 import org.simantics.db.SessionReference;
27 import org.simantics.db.VirtualGraph;
28 import org.simantics.db.authentication.UserAuthenticationAgent;
29 import org.simantics.db.common.processor.MergingDelayedWriteProcessor;
30 import org.simantics.db.common.processor.MergingGraphRequestProcessor;
31 import org.simantics.db.common.request.ReadRequest;
32 import org.simantics.db.exception.DatabaseException;
33 import org.simantics.db.exception.InternalException;
34 import org.simantics.db.management.internal.Activator;
35 import org.simantics.db.service.LifecycleSupport;
36 import org.simantics.db.service.VirtualGraphSupport;
37 import org.simantics.db.services.GlobalServiceInitializer;
38 import org.simantics.layer0.Layer0;
39 import org.simantics.utils.datastructures.disposable.DisposeState;
40 import org.simantics.utils.datastructures.disposable.IDisposable;
41 import org.simantics.utils.datastructures.disposable.IDisposeListener;
42 import org.simantics.utils.datastructures.hints.HintContext;
43 import org.simantics.utils.threads.IThreadWorkQueue;
44 import org.simantics.utils.threads.SyncListenerList;
45
46 import fi.vtt.simantics.procore.ProCoreServerReference;
47 import fi.vtt.simantics.procore.ProCoreSessionReference;
48 import fi.vtt.simantics.procore.SessionManagerSource;
49
50 /**
51  * Holds all information that is needed to create and manage a single database
52  * session in the Simantics workbench UI.
53  *
54  * @see org.simantics.ui.SimanticsUI
55  * @see org.simantics.db.layer0.util.Simantics
56  * @author Tuukka Lehtonen
57  */
58 public class SessionContext extends HintContext implements ISessionContext, Disposable {
59     private static final boolean    SESSION_DEBUG            = false;
60
61 //    private final IServerAddress        address;
62
63     private Session                 session;
64
65     private UserAuthenticationAgent authenticator;
66
67     private boolean                 servicesRegistered       = false;
68
69     private IStatus                 servicesRegisteredStatus = null;
70
71     public static SessionContext create(Session session, boolean initialize) throws DatabaseException {
72         return new SessionContext(session, initialize);
73     }
74
75 //    public static SessionContext openSession(IServerAddress info, UserAuthenticationAgent auth) throws IOException, DatabaseException {
76 //        return new SessionContext(info, auth, false);
77 //    }
78 //
79 //    public static SessionContext openAndInitializeSession(IServerAddress info, UserAuthenticationAgent auth) throws IOException, DatabaseException {
80 //        return new SessionContext(info, auth, true);
81 //    }
82
83     private static SessionReference createSessionReference(/*IServerAddress address,*/ long sessionId) throws InternalException {
84         ProCoreServerReference server = new ProCoreServerReference();
85         ProCoreSessionReference ref = new ProCoreSessionReference(server, sessionId);
86         return ref;
87     }
88
89 //    private SessionContext(IServerAddress addr, UserAuthenticationAgent auth, boolean initialize) throws IOException, DatabaseException {
90 //        if (addr == null)
91 //            throw new IllegalArgumentException("null address");
92 ////        this.address = addr;
93 //        this.authenticator = auth;
94 //
95 //        SessionManager sessionManager = SessionManagerProvider.getInstance().getSessionManager();
96 //
97 //        if (initialize) {
98 //            initializeSession(sessionManager);
99 //            if (SESSION_DEBUG) {
100 //                System.err.println("Initialized session: " + addr);
101 //                System.err.flush();
102 //            }
103 //        } else {
104 //            SessionReference ref = createSessionReference(SessionManagerSource.NullSessionId);
105 //            this.session = sessionManager.createSession(ref, auth);
106 //            if (SESSION_DEBUG) {
107 //                System.err.println("Opened session: " + addr);
108 //                System.err.flush();
109 //            }
110 //        }
111 //
112 //    }
113
114     private SessionContext(Session session, boolean initialize) throws DatabaseException {
115         if (initialize)
116             initializeSession(session);
117         ServerReference ref = session.getService( LifecycleSupport.class ).getSessionReference().getServerReference();
118 //        this.address = ref.serverAddress();
119         this.session = session;
120     }
121
122     private void initializeSession(SessionManager sessionManager) throws DatabaseException, IOException {
123         Session s = null;
124         boolean success = false;
125         try {
126             SessionReference ref = createSessionReference(SessionManagerSource.NullSessionId);
127             s = sessionManager.createSession(ref, authenticator);
128             initializeSession(s);
129             this.session = s;
130             success = true;
131         } finally {
132             if (!success) {
133                 if (s != null) {
134                     LifecycleSupport support = s.getService(LifecycleSupport.class);
135                     support.close();
136                 }
137             }
138         }
139     }
140
141     private void initializeSession(Session s) throws DatabaseException {
142         s.registerService(MergingGraphRequestProcessor.class, new MergingGraphRequestProcessor("SessionService", s, 20));
143         s.registerService(MergingDelayedWriteProcessor.class, new MergingDelayedWriteProcessor(s, 20));
144         s.registerService(VirtualGraph.class, s.getService(VirtualGraphSupport.class).getMemoryPersistent(UUID.randomUUID().toString()));
145
146         // Builtins needs to be initialized for the new session before
147         // anything useful can be done with it.
148         s.syncRequest(new ReadRequest() {
149             @Override
150             public void run(ReadGraph g) {
151                 // Registers Builtins with the ServiceLocator of the Graph's session.
152                 Layer0.getInstance(g);
153             }
154         });
155     }
156
157     public void registerServices() {
158         if (servicesRegistered)
159             return;
160
161         // Register any services available for the SessionLocator of the new
162         // Session.
163         servicesRegisteredStatus = new GlobalServiceInitializer().initialize(session);
164         if (!servicesRegisteredStatus.isOK()) {
165             Activator.getDefault().getLog().log(servicesRegisteredStatus);
166         }
167
168         servicesRegistered = true;
169     }
170
171 //    @Override
172 //    public IServerAddress getAddress() {
173 //        return address;
174 //    }
175
176     @Override
177     public Session getSession() {
178         if (session == null)
179             throw new IllegalStateException("SessionContext is disposed");
180         return session;
181     }
182
183     @Override
184     public Session peekSession() {
185         return session;
186     }
187
188     /**
189      * Do dispose procedures. This method is invoked at most once.
190      */
191     protected void doDispose() {
192         try {
193             doClose();
194         } catch (Exception e) {
195             throw new RuntimeException(e);
196         }
197     }
198
199     @Override
200     public void close() throws IllegalStateException, InterruptedException, TimeoutException {
201         try {
202             dispose();
203         } catch (RuntimeException e) {
204             Throwable t = e.getCause();
205             if (t instanceof RuntimeException) {
206                 throw (RuntimeException) t;
207             } else if (t instanceof Error) {
208                 throw (Error) t;
209             } else if (t instanceof InterruptedException) {
210                 throw (InterruptedException) t;
211             } else if (t instanceof TimeoutException) {
212                 throw (TimeoutException) t;
213             }
214             throw e;
215         }
216     }
217
218     private void doClose() throws DatabaseException {
219         for (Key k : getHints().keySet()) {
220             if (k != null) {
221                 Object o = removeHint(k);
222                 if (o instanceof IDisposable) {
223                     ((IDisposable) o).safeDispose();
224                 }
225             }
226         }
227
228         if (session != null) {
229             if (SESSION_DEBUG) {
230                 System.err.println("Closing session: " + session/*address*/);
231                 System.err.flush();
232             }
233             LifecycleSupport support = session.getService(LifecycleSupport.class);
234             support.close(0, true);
235             session = null;
236         }
237     }
238
239     @Override
240     public int hashCode() {
241         if (session == null) return 0;
242         return session.hashCode();
243     }
244
245     @Override
246     public boolean equals(Object obj) {
247         if (this == obj)
248             return true;
249         if (obj == null || getClass() != obj.getClass())
250             return false;
251         final SessionContext other = (SessionContext) obj;
252 //        if (!address.equals(other.address))
253 //            return false;
254         return session.equals(other.session);
255     }
256
257     @Override
258     public String toString() {
259         StringBuilder s = new StringBuilder();
260         s.append("SessionContext [info=" + session + ", hints=");
261         s.append(Arrays.toString(getHints().values().toArray()));
262         s.append("]");
263         return s.toString();
264     }
265
266
267     // IDisposable implementation (AbstractDisposable)
268
269     SyncListenerList<IDisposeListener> disposeListeners = null;
270
271     private DisposeState disposeStatus = DisposeState.Alive;
272
273     protected void assertNotDisposed() {
274         if (isDisposed())
275             throw new AssertionError(this + " is disposed.");
276     }
277
278     @Override
279     public DisposeState getDisposeState() {
280         return disposeStatus;
281     }
282
283     @Override
284     public boolean isDisposed() {
285         return disposeStatus == DisposeState.Disposed;
286     }
287
288     public boolean isAlive() {
289         return disposeStatus == DisposeState.Alive;
290     }
291
292     @Override
293     public void dispose() {
294         try {
295             synchronized (this) {
296                 if (disposeStatus == DisposeState.Disposing)
297                     return;
298                 assertNotDisposed();
299                 disposeStatus = DisposeState.Disposing;
300             }
301             try {
302                 fireDisposed();
303             } finally {
304                 doDispose();
305             }
306         } finally {
307             synchronized(this) {
308                 disposeStatus = DisposeState.Disposed;
309             }
310         }
311     }
312
313     /**
314      * Disposes if not disposed
315      */
316     @Override
317     public void safeDispose() {
318         try {
319             synchronized (this) {
320                 if (disposeStatus != DisposeState.Alive)
321                     return;
322                 disposeStatus = DisposeState.Disposing;
323             }
324             try {
325                 fireDisposed();
326             } finally {
327                 doDispose();
328             }
329         } finally {
330             synchronized(this) {
331                 disposeStatus = DisposeState.Disposed;
332             }
333         }
334     }
335
336     protected boolean hasDisposeListeners() {
337         return disposeListeners!=null && !disposeListeners.isEmpty();
338     }
339
340     private final static Method onDisposed = SyncListenerList.getMethod(IDisposeListener.class, "onDisposed");
341
342     private void fireDisposed() {
343         if (disposeListeners==null) return;
344         disposeListeners.fireEventSync(onDisposed, this);
345     }
346
347     @SuppressWarnings("unused")
348     private void fireDisposedAsync() {
349         if (disposeListeners==null) return;
350         disposeListeners.fireEventAsync(onDisposed, this);
351     }
352
353     @Override
354     public void addDisposeListener(IDisposeListener listener) {
355         lazyGetListenerList().add(listener);
356     }
357
358     @Override
359     public void addDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
360         lazyGetListenerList().add(thread, listener);
361     }
362
363     @Override
364     public void removeDisposeListener(IDisposeListener listener) {
365         if (disposeListeners==null) return;
366         disposeListeners.remove(listener);
367     }
368
369     @Override
370     public void removeDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
371         if (disposeListeners==null) return;
372         disposeListeners.remove(thread, listener);
373     }
374
375     private synchronized SyncListenerList<IDisposeListener> lazyGetListenerList()
376     {
377         if (disposeListeners==null)
378             disposeListeners = new SyncListenerList<IDisposeListener>(IDisposeListener.class);
379         return disposeListeners;
380     }
381
382     @Override
383     protected void finalize() throws Throwable {
384         try {
385             safeDispose();
386         } finally {
387             super.finalize();
388         }
389     }
390
391 }