]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.project/src/org/simantics/project/impl/Project.java
Replace e.printStackTrace() with LOGGER in o.s.p.impl.Project.java
[simantics/platform.git] / bundles / org.simantics.project / src / org / simantics / project / impl / Project.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 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.project.impl;
13
14 import java.lang.reflect.Method;
15 import java.util.Arrays;
16 import java.util.LinkedList;
17 import java.util.concurrent.atomic.AtomicBoolean;
18 import java.util.concurrent.locks.Lock;
19 import java.util.concurrent.locks.ReentrantLock;
20
21 import org.simantics.db.RequestProcessor;
22 import org.simantics.db.Resource;
23 import org.simantics.db.Session;
24 import org.simantics.db.WriteOnlyGraph;
25 import org.simantics.db.common.processor.MergingGraphRequestProcessor;
26 import org.simantics.db.common.request.WriteOnlyRequest;
27 import org.simantics.db.exception.CancelTransactionException;
28 import org.simantics.db.exception.DatabaseException;
29 import org.simantics.project.IProject;
30 import org.simantics.project.exception.ProjectException;
31 import org.simantics.project.features.IProjectFeature;
32 import org.simantics.utils.datastructures.disposable.DisposeState;
33 import org.simantics.utils.datastructures.disposable.IDisposeListener;
34 import org.simantics.utils.datastructures.hints.HintContext;
35 import org.simantics.utils.threads.IThreadWorkQueue;
36 import org.simantics.utils.threads.SyncListenerList;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
41 /**
42  * @author Tuukka Lehtonen
43  */
44 public class Project extends HintContext implements IProject {
45
46     private static final Logger LOGGER = LoggerFactory.getLogger(Project.class);
47
48     private static IProjectFeature[]          NONE         = {};
49
50     //private static final String               TAG_PROJECTS = "projects";
51
52     private IProjectFeature[]                 features         = NONE;
53     private final LinkedList<IProjectFeature> featureSet       = new LinkedList<IProjectFeature>();
54     private final LinkedList<IProjectFeature> inactiveFeatures = new LinkedList<IProjectFeature>();
55     private final LinkedList<IProjectFeature> activeFeatures   = new LinkedList<IProjectFeature>();
56
57     private final Lock                        lock             = new ReentrantLock();
58     private final AtomicBoolean               active           = new AtomicBoolean(false);
59
60     protected Session                         session;
61     protected Resource                        resource;
62
63     public Project(Session session, Resource resource) {
64         if (session == null)
65             throw new NullPointerException("null session");
66         if (resource == null)
67             throw new NullPointerException("null resource");
68
69         this.session = session;
70         this.resource = resource;
71         //System.out.println("NEW PROJECT [" + resource.getResourceId() + "] (" + System.identityHashCode(this) + ")");
72     }
73
74     public void doDispose() {
75         //System.out.println("DISPOSE: " + this + " (" + System.identityHashCode(this) + ")");
76         lock.lock();
77         try {
78             deactivate();
79
80             featureSet.clear();
81             features = NONE;
82         } catch (ProjectException e) {
83             LOGGER.error("Could not dispose Project {}", this, e);
84         } finally {
85             lock.unlock();
86         }
87     }
88
89     @Override
90     public IProjectFeature[] getFeatures() {
91         assertNotDisposed();
92
93         // Defensive copy.
94         IProjectFeature[] features = this.features;
95         return Arrays.copyOf(features, features.length);
96     }
97
98     public void addFeature(IProjectFeature feature) {
99         assertNotDisposed();
100         lock.lock();
101         try {
102             if (!featureSet.contains(feature)) {
103                 featureSet.add(feature);
104                 inactiveFeatures.add(feature);
105                 features = featureSet.toArray(new IProjectFeature[featureSet.size()]);
106             }
107         } finally {
108             lock.unlock();
109         }
110     }
111
112     @Override
113     public void activate() throws ProjectException {
114         if (isDisposed())
115             throw new IllegalStateException("project is disposed, cannot activate " + this + " (" + System.identityHashCode(this) + ")");
116
117         lock.lock();
118         try {
119             if (active.get() == true)
120                 return;
121
122             while (!inactiveFeatures.isEmpty()) {
123                 IProjectFeature feature = inactiveFeatures.getFirst();
124                 boolean success = false;
125                 try {
126                     LOGGER.info("Configuring project feature {}", feature);
127                     feature.setProjectElement(this);
128                     feature.configure();
129
130                     inactiveFeatures.removeFirst();
131                     activeFeatures.addLast(feature);
132
133                     success = true;
134                 } finally {
135                     if (!success)
136                         feature.setProjectElement(null);
137                 }
138             }
139
140             try {
141                 transactionBarrier();
142             } finally {
143                 active.set(true);
144             }
145         } finally {
146             lock.unlock();
147         }
148     }
149
150     @Override
151     public void deactivate() throws ProjectException {
152         if (isDisposed())
153             throw new IllegalStateException("project is disposed, cannot deactivate " + this + " (" + System.identityHashCode(this) + ")");
154
155         lock.lock();
156         try {
157             if (active.get() == false)
158                 return;
159
160             while (!activeFeatures.isEmpty()) {
161                 IProjectFeature feature = activeFeatures.getLast();
162                 boolean success = false;
163                 try {
164                     feature.deconfigure();
165
166                     activeFeatures.removeLast();
167                     inactiveFeatures.addFirst(feature);
168
169                     success = true;
170                 } finally {
171                     if (success)
172                         feature.setProjectElement(null);
173                 }
174             }
175
176             try {
177                 transactionBarrier();
178             } finally {
179                 active.set(false);
180             }
181         } finally {
182             lock.unlock();
183         }
184     }
185
186     private void transactionBarrier() throws ProjectException {
187         // IMPORTANT: ensure that all database requests have been
188         // completed before returning from deactivation.
189         try {
190             session.syncRequest(new WriteOnlyRequest() {
191                 @Override
192                 public void perform(WriteOnlyGraph graph) throws DatabaseException {
193                     throw new CancelTransactionException("barrier");
194                 }
195             });
196         } catch (CancelTransactionException e) {
197         } catch (DatabaseException e) {
198             throw new ProjectException(e);
199         }
200     }
201
202     @Override
203     public String toString() {
204         return getClass().getSimpleName() + " [resource=" + get().getResourceId() + "]";
205     }
206
207     @Override
208     public int hashCode() {
209         return get().hashCode();
210     }
211
212     @Override
213     public boolean equals(Object obj) {
214         if (this == obj)
215             return true;
216         if (!(obj instanceof Project))
217             return false;
218         final Project other = (Project) obj;
219
220         // Need to make sure that the resources are from the same session.
221         if (!session.equals(other.session))
222             return false;
223
224         Resource r1 = get();
225         Resource r2 = other.get();
226         if (r1 == null) {
227             if (r2 != null)
228                 return false;
229         } else if (!r1.equals(r2))
230             return false;
231
232         return true;
233     }
234
235     @Override
236     public Session getSession() {
237         return session;
238     }
239
240     @Override
241     public Resource get() {
242         return resource;
243     }
244
245     public RequestProcessor getGraphRequestProcessor() {
246         MergingGraphRequestProcessor mgrp = session.peekService(MergingGraphRequestProcessor.class);
247         return mgrp != null ? mgrp : session;
248     }
249
250     // IDisposable implementation (copied from AbstractDisposable)
251
252     SyncListenerList<IDisposeListener> disposeListeners = null;
253
254     private volatile DisposeState disposeStatus = DisposeState.Alive;
255
256     protected void assertNotDisposed() {
257         if (isDisposed())
258             throw new IllegalStateException(this + " is disposed");
259     }
260
261     @Override
262     public DisposeState getDisposeState() {
263         return disposeStatus;
264     }
265
266     @Override
267     public boolean isDisposed() {
268         return disposeStatus == DisposeState.Disposed;
269     }
270
271     public boolean isAlive() {
272         return disposeStatus == DisposeState.Alive;
273     }
274
275     @Override
276     public void dispose() {
277         try {
278             lock.lock();
279             try {
280                 if (disposeStatus == DisposeState.Disposing)
281                     return;
282                 assertNotDisposed();
283                 disposeStatus = DisposeState.Disposing;
284             } finally {
285                 lock.unlock();
286             }
287
288             try {
289                 fireDisposed();
290             } finally {
291                 doDispose();
292             }
293         } finally {
294             disposeStatus = DisposeState.Disposed;
295         }
296     }
297
298     /**
299      * Disposes if not disposed
300      */
301     @Override
302     public void safeDispose() {
303         try {
304             lock.lock();
305             try {
306                 if (disposeStatus != DisposeState.Alive)
307                     return;
308                 disposeStatus = DisposeState.Disposing;
309             } finally {
310                 lock.unlock();
311             }
312
313             try {
314                 fireDisposed();
315             } finally {
316                 doDispose();
317             }
318         } finally {
319             disposeStatus = DisposeState.Disposed;
320         }
321     }
322
323     protected boolean hasDisposeListeners() {
324         return disposeListeners!=null && !disposeListeners.isEmpty();
325     }
326
327     private final static Method onDisposed = SyncListenerList.getMethod(IDisposeListener.class, "onDisposed");
328
329     private void fireDisposed() {
330         if (disposeListeners==null) return;
331         disposeListeners.fireEventSync(onDisposed, this);
332     }
333
334     @SuppressWarnings("unused")
335     private void fireDisposedAsync() {
336         if (disposeListeners==null) return;
337         disposeListeners.fireEventAsync(onDisposed, this);
338     }
339
340     @Override
341     public void addDisposeListener(IDisposeListener listener) {
342         lazyGetListenerList().add(listener);
343     }
344
345     @Override
346     public void addDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
347         lazyGetListenerList().add(thread, listener);
348     }
349
350     @Override
351     public void removeDisposeListener(IDisposeListener listener) {
352         if (disposeListeners==null) return;
353         disposeListeners.remove(listener);
354     }
355
356     @Override
357     public void removeDisposeListener(IDisposeListener listener, IThreadWorkQueue thread) {
358         if (disposeListeners==null) return;
359         disposeListeners.remove(thread, listener);
360     }
361
362     private synchronized SyncListenerList<IDisposeListener> lazyGetListenerList() {
363         if (disposeListeners==null)
364             disposeListeners = new SyncListenerList<IDisposeListener>(IDisposeListener.class);
365         return disposeListeners;
366     }
367
368 }