]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.management/src/org/simantics/db/management/SessionContext.java
DB and Layer0 modifications for related issues
[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.lang.reflect.Method;
15 import java.util.Arrays;
16 import java.util.UUID;
17 import java.util.concurrent.TimeoutException;
18
19 import org.simantics.db.Disposable;
20 import org.simantics.db.ReadGraph;
21 import org.simantics.db.Session;
22 import org.simantics.db.VirtualGraph;
23 import org.simantics.db.exception.DatabaseException;
24 import org.simantics.db.request.Read;
25 import org.simantics.db.service.LifecycleSupport;
26 import org.simantics.db.service.VirtualGraphSupport;
27 import org.simantics.layer0.Layer0;
28 import org.simantics.utils.datastructures.disposable.DisposeState;
29 import org.simantics.utils.datastructures.disposable.IDisposable;
30 import org.simantics.utils.datastructures.disposable.IDisposeListener;
31 import org.simantics.utils.datastructures.hints.HintContext;
32 import org.simantics.utils.threads.IThreadWorkQueue;
33 import org.simantics.utils.threads.SyncListenerList;
34
35 /**
36  * Holds all information that is needed to create and manage a single database
37  * session in the Simantics workbench UI.
38  *
39  * @see org.simantics.ui.SimanticsUI
40  * @see org.simantics.db.layer0.util.Simantics
41  * @author Tuukka Lehtonen
42  */
43 public class SessionContext extends HintContext implements ISessionContext, Disposable {
44
45         private static final boolean    SESSION_DEBUG            = false;
46
47     private Session                 session;
48
49     public static SessionContext create(Session session, boolean initialize) throws DatabaseException {
50         return new SessionContext(session, initialize);
51     }
52
53     private SessionContext(Session session, boolean initialize) throws DatabaseException {
54         if (initialize)
55             initializeSession(session);
56         this.session = session;
57     }
58
59     private void initializeSession(Session s) throws DatabaseException {
60         s.registerService(VirtualGraph.class, s.getService(VirtualGraphSupport.class).getMemoryPersistent(UUID.randomUUID().toString()));
61
62         // Builtins needs to be initialized for the new session before
63         // anything useful can be done with it.
64         s.syncRequest(new Read<Object>() {
65             @Override
66             public Object perform(ReadGraph g) {
67                 // Registers Builtins with the ServiceLocator of the Graph's session.
68                 Layer0.getInstance(g);
69                 return null;
70             }
71         });
72         
73     }
74
75     @Override
76     public Session getSession() {
77         if (session == null)
78             throw new IllegalStateException("SessionContext is disposed");
79         return session;
80     }
81
82     @Override
83     public Session peekSession() {
84         return session;
85     }
86
87     /**
88      * Do dispose procedures. This method is invoked at most once.
89      */
90     protected void doDispose() {
91         try {
92             doClose();
93         } catch (Exception e) {
94             throw new RuntimeException(e);
95         }
96     }
97
98     @Override
99     public void close() throws IllegalStateException, InterruptedException, TimeoutException {
100         try {
101             dispose();
102         } catch (RuntimeException e) {
103             Throwable t = e.getCause();
104             if (t instanceof RuntimeException) {
105                 throw (RuntimeException) t;
106             } else if (t instanceof Error) {
107                 throw (Error) t;
108             } else if (t instanceof InterruptedException) {
109                 throw (InterruptedException) t;
110             } else if (t instanceof TimeoutException) {
111                 throw (TimeoutException) t;
112             }
113             throw e;
114         }
115     }
116
117     private void doClose() throws DatabaseException {
118         for (Key k : getHints().keySet()) {
119             if (k != null) {
120                 Object o = removeHint(k);
121                 if (o instanceof IDisposable) {
122                     ((IDisposable) o).safeDispose();
123                 }
124             }
125         }
126
127         if (session != null) {
128             if (SESSION_DEBUG) {
129                 System.err.println("Closing session: " + session/*address*/);
130                 System.err.flush();
131             }
132             LifecycleSupport support = session.getService(LifecycleSupport.class);
133             support.close(0, true);
134             session = null;
135         }
136     }
137
138     @Override
139     public int hashCode() {
140         if (session == null) return 0;
141         return session.hashCode();
142     }
143
144     @Override
145     public boolean equals(Object obj) {
146         if (this == obj)
147             return true;
148         if (obj == null || getClass() != obj.getClass())
149             return false;
150         final SessionContext other = (SessionContext) obj;
151 //        if (!address.equals(other.address))
152 //            return false;
153         return session.equals(other.session);
154     }
155
156     @Override
157     public String toString() {
158         StringBuilder s = new StringBuilder();
159         s.append("SessionContext [info=" + session + ", hints=");
160         s.append(Arrays.toString(getHints().values().toArray()));
161         s.append("]");
162         return s.toString();
163     }
164
165
166     // IDisposable implementation (AbstractDisposable)
167
168     SyncListenerList<IDisposeListener> disposeListeners = null;
169
170     private DisposeState disposeStatus = DisposeState.Alive;
171
172     protected void assertNotDisposed() {
173         if (isDisposed())
174             throw new AssertionError(this + " is disposed.");
175     }
176
177     @Override
178     public DisposeState getDisposeState() {
179         return disposeStatus;
180     }
181
182     @Override
183     public boolean isDisposed() {
184         return disposeStatus == DisposeState.Disposed;
185     }
186
187     public boolean isAlive() {
188         return disposeStatus == DisposeState.Alive;
189     }
190
191     @Override
192     public void dispose() {
193         try {
194             synchronized (this) {
195                 if (disposeStatus == DisposeState.Disposing)
196                     return;
197                 assertNotDisposed();
198                 disposeStatus = DisposeState.Disposing;
199             }
200             try {
201                 fireDisposed();
202             } finally {
203                 doDispose();
204             }
205         } finally {
206             synchronized(this) {
207                 disposeStatus = DisposeState.Disposed;
208             }
209         }
210     }
211
212     /**
213      * Disposes if not disposed
214      */
215     @Override
216     public void safeDispose() {
217         try {
218             synchronized (this) {
219                 if (disposeStatus != DisposeState.Alive)
220                     return;
221                 disposeStatus = DisposeState.Disposing;
222             }
223             try {
224                 fireDisposed();
225             } finally {
226                 doDispose();
227             }
228         } finally {
229             synchronized(this) {
230                 disposeStatus = DisposeState.Disposed;
231             }
232         }
233     }
234
235     protected boolean hasDisposeListeners() {
236         return disposeListeners!=null && !disposeListeners.isEmpty();
237     }
238
239     private final static Method onDisposed = SyncListenerList.getMethod(IDisposeListener.class, "onDisposed");
240
241     private void fireDisposed() {
242         if (disposeListeners==null) return;
243         disposeListeners.fireEventSync(onDisposed, this);
244     }
245
246     @SuppressWarnings("unused")
247     private void fireDisposedAsync() {
248         if (disposeListeners==null) return;
249         disposeListeners.fireEventAsync(onDisposed, this);
250     }
251
252     @Override
253     public void addDisposeListener(IDisposeListener listener) {
254         lazyGetListenerList().add(listener);
255     }
256
257     @Override
258     public void addDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
259         lazyGetListenerList().add(thread, listener);
260     }
261
262     @Override
263     public void removeDisposeListener(IDisposeListener listener) {
264         if (disposeListeners==null) return;
265         disposeListeners.remove(listener);
266     }
267
268     @Override
269     public void removeDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
270         if (disposeListeners==null) return;
271         disposeListeners.remove(thread, listener);
272     }
273
274     private synchronized SyncListenerList<IDisposeListener> lazyGetListenerList()
275     {
276         if (disposeListeners==null)
277             disposeListeners = new SyncListenerList<IDisposeListener>(IDisposeListener.class);
278         return disposeListeners;
279     }
280
281     @Override
282     protected void finalize() throws Throwable {
283         try {
284             safeDispose();
285         } finally {
286             super.finalize();
287         }
288     }
289
290 }