Some fixes for resource cleaning spreadsheets in simupedia
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / StandardSessionManager.java
1 package org.simantics.db.layer0;
2
3 import java.util.Collection;
4 import java.util.concurrent.ConcurrentHashMap;
5
6 import org.simantics.db.ReadGraph;
7 import org.simantics.db.WriteGraph;
8 import org.simantics.db.common.request.ParametrizedPrimitiveRead;
9 import org.simantics.db.exception.DatabaseException;
10 import org.simantics.db.layer0.variable.NodeSupport;
11 import org.simantics.db.procedure.Listener;
12
13 abstract public class StandardSessionManager<Node, Engine extends StandardEngine<Node>> {
14
15     private ConcurrentHashMap<String, Listener<StandardRealm<Node,Engine>>> realmListeners = new ConcurrentHashMap<>();
16     private ConcurrentHashMap<String, StandardRealm<Node,Engine>> REALMS = new ConcurrentHashMap<String, StandardRealm<Node,Engine>>(); 
17     private ConcurrentHashMap<String, NodeSupport<Node>> SUPPORTS = new ConcurrentHashMap<String, NodeSupport<Node>>(); 
18
19     // Accessing Realms should be done over ParametrizedPrimitveRead for the
20     // case if a realm is destroyed and new one is created with the same id than
21     // the previously deleted one for the listeners to get discarded and new
22     // registered
23     private class RealmRequest extends ParametrizedPrimitiveRead<String, StandardRealm<Node, Engine>> {
24
25         public RealmRequest(String parameter) {
26             super(parameter);
27         }
28
29         @Override
30         public void register(ReadGraph graph, Listener<StandardRealm<Node, Engine>> procedure) {
31
32             StandardRealm<Node, Engine> realm = REALMS.get(parameter);
33             if (realm == null) {
34                 try {
35                     realm = createRealmInner(graph, parameter);
36                 } catch (DatabaseException e) {
37                     e.printStackTrace();
38                 }
39             }
40             
41             if(procedure.isDisposed()) {
42                 procedure.execute(realm);
43                 return;
44             }
45             
46             Listener<StandardRealm<Node,Engine>> existing = getOrDisposeListener(parameter);
47             assert(existing == null);
48             realmListeners.put(parameter, procedure);
49             procedure.execute(realm);
50         }
51
52         private StandardRealm<Node,Engine> createRealmInner(ReadGraph graph, String id) throws DatabaseException {
53             Engine engine = createEngine(graph, id);
54             StandardRealm<Node,Engine> realm = createRealm(engine, id);
55             modifyRealms(id, realm);
56             return realm;
57         }
58     }
59     
60     protected StandardSessionManager() {
61     }
62     
63     private Listener<StandardRealm<Node,Engine>> getOrDisposeListener(String key) {
64         Listener<StandardRealm<Node,Engine>> listener = realmListeners.get(key);
65         if(listener != null) {
66             if(listener.isDisposed()) {
67                 realmListeners.remove(key);
68             } else {
69                 return listener;
70             }
71         }
72         return null;
73     }
74     
75     private void modifyRealms(String key, StandardRealm<Node,Engine> realm) {
76         if(realm != null) {
77             REALMS.put(key, realm);
78         } else {
79             StandardRealm<Node, Engine> removedRealm = REALMS.remove(key);
80             if (removedRealm != null)
81                 removedRealm.close();
82         }
83         Listener<StandardRealm<Node,Engine>> listener = getOrDisposeListener(key);
84         if(listener != null) {
85             listener.execute(realm);
86         }
87     }
88
89     public NodeSupport<Node> getOrCreateNodeSupport(ReadGraph graph, String id) throws DatabaseException {
90         synchronized(SUPPORTS) {
91                 NodeSupport<Node> result = SUPPORTS.get(id);
92                 if(result == null) {
93                         StandardRealm<Node,Engine> realm = getOrCreateRealm(graph, id);
94                         result = new NodeSupport<Node>(realm.getNodeManager());
95                         SUPPORTS.put(id, result);
96                 }
97                 return result;
98         }
99     }
100     
101     public StandardRealm<Node,Engine> getOrCreateRealm(ReadGraph graph, String id) throws DatabaseException {
102         synchronized(REALMS) {
103             return graph.syncRequest(new RealmRequest(id));
104         }
105     }
106     
107     protected abstract Engine createEngine(ReadGraph graph, String id) throws DatabaseException;
108     protected abstract StandardRealm<Node,Engine> createRealm(Engine engine, String id);
109     
110     public void removeRealm(WriteGraph graph, String id) throws DatabaseException {
111         modifyRealms(id, null);
112         // remove listeners from this realm
113         realmListeners.remove(id);
114         // if node support has been created remove it as well
115         NodeSupport<Node> support = SUPPORTS.remove(id);
116         if (support != null)
117             support.dispose();
118     }
119     
120     public Collection<String> getRealms() {
121         return REALMS.keySet();
122     }
123 }