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