]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.db/src/org/simantics/scl/db/SCLFunctions.java
(refs #7607) Fixed handling of SCLContext in asynchronous requests
[simantics/platform.git] / bundles / org.simantics.scl.db / src / org / simantics / scl / db / SCLFunctions.java
1 package org.simantics.scl.db;
2
3 import java.io.IOException;
4
5 import org.cojen.classfile.TypeDesc;
6 import org.simantics.Simantics;
7 import org.simantics.db.ReadGraph;
8 import org.simantics.db.Resource;
9 import org.simantics.db.VirtualGraph;
10 import org.simantics.db.WriteGraph;
11 import org.simantics.db.common.procedure.adapter.SyncListenerAdapter;
12 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
13 import org.simantics.db.common.request.BinaryRead;
14 import org.simantics.db.common.request.DelayedWriteRequest;
15 import org.simantics.db.common.request.ReadRequest;
16 import org.simantics.db.common.request.WriteRequest;
17 import org.simantics.db.common.request.WriteResultRequest;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.layer0.util.Layer0Utils;
20 import org.simantics.db.layer0.variable.Variables;
21 import org.simantics.db.request.Read;
22 import org.simantics.db.service.ClusterControl;
23 import org.simantics.db.service.SerialisationSupport;
24 import org.simantics.db.service.VirtualGraphSupport;
25 import org.simantics.layer0.utils.triggers.IActivationManager;
26 import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
27 import org.simantics.scl.compiler.errors.Failable;
28 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
29 import org.simantics.scl.compiler.module.Module;
30 import org.simantics.scl.compiler.module.repository.ImportFailureException;
31 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
32 import org.simantics.scl.compiler.types.Type;
33 import org.simantics.scl.osgi.SCLOsgi;
34 import org.simantics.scl.runtime.SCLContext;
35 import org.simantics.scl.runtime.function.Function;
36 import org.simantics.scl.runtime.function.Function1;
37 import org.simantics.scl.runtime.tuple.Tuple;
38 import org.simantics.scl.runtime.tuple.Tuple0;
39 import org.simantics.utils.DataContainer;
40
41 @SuppressWarnings({"rawtypes", "unchecked"})
42 public class SCLFunctions {
43
44     public static final String GRAPH = "graph";
45
46     public static <T> T safeExec(final Function f) {
47         try {
48             return (T)f.apply(Tuple0.INSTANCE);
49         } catch (Throwable t) {
50             t.printStackTrace();
51             return null;
52         }
53     }
54     
55     public static void asyncRead(final Function f) throws DatabaseException {
56         final SCLContext context = SCLContext.createDerivedContext();
57         Simantics.getSession().asyncRequest(new ReadRequest() {
58             @Override
59             public void run(ReadGraph graph) throws DatabaseException {
60                 SCLContext.push(context);
61                 context.put(GRAPH, graph);
62                 try {
63                     f.apply(Tuple0.INSTANCE);
64                 } finally {
65                     SCLContext.pop();
66                 }
67             }
68         });
69     }
70     
71     public static <T> T syncRead(final Function f) throws DatabaseException {
72         final SCLContext context = SCLContext.getCurrent();
73         Object graph = context.get(GRAPH);
74         if (graph != null) {
75             return (T)f.apply(Tuple0.INSTANCE);
76         } else {
77             return Simantics.getSession().syncRequest(new Read<T>() {
78                 @Override
79                 public T perform(ReadGraph graph) throws DatabaseException {
80                     SCLContext.push(context);
81                     ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
82                     try {
83                         return (T)f.apply(Tuple0.INSTANCE);
84                     } finally {
85                         context.put(GRAPH, oldGraph);
86                         SCLContext.pop();
87                     }
88                 }
89             });
90         }
91     }
92     
93     public static void asyncWrite(final Function f) throws DatabaseException {
94         SCLContext context = SCLContext.createDerivedContext();
95         Simantics.getSession().asyncRequest(new WriteRequest() {
96             @Override
97             public void perform(WriteGraph graph) throws DatabaseException {
98                 SCLContext.push(context);
99                 context.put(GRAPH, graph);
100                 try {
101                     f.apply(Tuple0.INSTANCE);
102                 } finally {
103                     SCLContext.pop();
104                 }
105             }
106         });
107     }
108     
109     public static <T> T syncWrite(final Function f) throws DatabaseException {
110         final SCLContext context = SCLContext.getCurrent();
111         Object graph = context.get(GRAPH);
112         if (graph != null) {
113             return (T)f.apply(Tuple0.INSTANCE);
114         } else {
115             return Simantics.getSession().syncRequest(new WriteResultRequest<T>() {
116                 @Override
117                 public T perform(WriteGraph graph) throws DatabaseException {
118                     SCLContext.push(context);
119                     ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
120                     try {
121                         return (T)f.apply(Tuple0.INSTANCE);
122                     } finally {
123                         context.put(GRAPH, oldGraph);
124                         SCLContext.pop();
125                     }
126                 }
127             });
128         }
129     }
130     
131     public static <T> T delayedSyncWrite(final Function f) throws DatabaseException {
132         final SCLContext context = SCLContext.getCurrent();
133         final DataContainer<T> dc = new DataContainer<T>(null);
134
135         DelayedWriteRequest request = new DelayedWriteRequest() {
136             @Override
137             public void perform(WriteGraph graph) throws DatabaseException {
138                 final SCLContext context = SCLContext.getCurrent();
139                 SCLContext.push(context);
140                 ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
141                 try {
142                     dc.set((T)f.apply(Tuple0.INSTANCE));
143                 } finally {
144                     context.put(GRAPH, oldGraph);
145                     SCLContext.pop();
146                 }
147             }
148         };
149         
150         Object graph = context.get(GRAPH);
151         if (graph != null) {
152             if (graph instanceof WriteGraph) {
153                 ((WriteGraph)graph).syncRequest(request);
154             } else {
155                 throw new DatabaseException("Caller is inside a read transaction.");
156             }
157         } else {
158             Simantics.getSession().syncRequest(request);
159         }
160         return dc.get();
161     }
162
163     public static <T> T virtualSyncWriteMem(WriteGraph graph, String virtualGraphId, final Function f) throws DatabaseException {
164         final SCLContext context = SCLContext.getCurrent();
165         VirtualGraphSupport vgs = graph.getService(VirtualGraphSupport.class);
166         VirtualGraph vg = vgs.getMemoryPersistent(virtualGraphId);
167         return graph.syncRequest(new WriteResultRequest<T>(vg) {
168             @Override
169             public T perform(WriteGraph graph) throws DatabaseException {
170                 SCLContext.push(context);
171                 ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
172                 try {
173                     return (T)f.apply(Tuple0.INSTANCE);
174                 } finally {
175                     context.put(GRAPH, oldGraph);
176                     SCLContext.pop();
177                 }
178             }
179         });
180     }
181     
182     public static <T> T virtualSyncWriteWS(WriteGraph graph, String virtualGraphId, final Function f) throws DatabaseException {
183         final SCLContext context = SCLContext.getCurrent();
184         VirtualGraphSupport vgs = graph.getService(VirtualGraphSupport.class);
185         VirtualGraph vg = vgs.getWorkspacePersistent(virtualGraphId);
186         return graph.syncRequest(new WriteResultRequest<T>(vg) {
187             @Override
188             public T perform(WriteGraph graph) throws DatabaseException {
189                 SCLContext.push(context);
190                 ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
191                 try {
192                     return (T)f.apply(Tuple0.INSTANCE);
193                 } finally {
194                     context.put(GRAPH, oldGraph);
195                     SCLContext.pop();
196                 }
197             }
198         });
199     }
200     
201     public static <T> T readValue(final String uri) throws DatabaseException {
202         return Simantics.getSession().syncRequest(new Read<T>() {
203             @Override
204             public T perform(ReadGraph graph) throws DatabaseException {
205                 return Variables.getVariable(graph, uri).getValue(graph);
206             }            
207         });
208     }
209     
210     public static <T> void writeValue(final String uri, final T value) throws DatabaseException {
211         Simantics.getSession().syncRequest(new WriteRequest() {
212             @Override
213             public void perform(WriteGraph graph) throws DatabaseException {
214                 Variables.getVariable(graph, uri).setValue(graph, value);
215             }            
216         });
217     }
218     
219     public static void activateOnce(Resource r) {
220         Simantics.getSession().getService(IActivationManager.class).activateOnce(r);
221     }
222     
223     public static void syncActivateOnce(WriteGraph graph, Resource r) throws DatabaseException {
224         graph.getService(IActivationManager.class).activateOnce(graph, r);
225     }
226
227     public static Resource resourceFromId(ReadGraph graph, long id) throws DatabaseException, IOException {
228         SerialisationSupport ss = graph.getService(SerialisationSupport.class);
229         return ss.getResource(id);
230     }
231     
232     public static void disableDependencies(WriteGraph graph) {
233         Layer0Utils.setDependenciesIndexingDisabled(graph, true);       
234     }
235     
236     public static void enableDependencies(WriteGraph graph) {
237         Layer0Utils.setDependenciesIndexingDisabled(graph, false);       
238     }
239     
240     public static void collectClusters() {
241         Simantics.getSession().getService(ClusterControl.class).collectClusters(Integer.MAX_VALUE);
242     }
243     
244     public static class SCLUnaryRead extends BinaryRead<Function1<Object,Object>, Object, Object> {
245
246                 public SCLUnaryRead(Function1<Object, Object> parameter1, Object parameter2) {
247                         super(parameter1, parameter2);
248                 }
249
250                 @Override
251                 public Object perform(ReadGraph graph) throws DatabaseException {
252                         return Simantics.applySCLRead(graph, parameter, parameter2);
253                 }
254         
255     }
256     
257     public static Object unaryQuery(ReadGraph graph, Function1<Object,Object> fn, Object value) throws DatabaseException {
258         return graph.syncRequest(new SCLUnaryRead(fn, value));
259     }
260
261     public static Object unaryQueryCached(ReadGraph graph, Function1<Object,Object> fn, Object value) throws DatabaseException {
262         return graph.syncRequest(new SCLUnaryRead(fn, value), TransientCacheAsyncListener.<Object>instance());
263     }
264     
265
266     private static class Subquery implements Read<Object> {
267         Function q;
268
269         public Subquery(Function q) {
270             this.q = q;
271         }
272
273         @Override
274         public Object perform(ReadGraph graph) throws DatabaseException {
275             SCLContext sclContext = SCLContext.getCurrent();
276             Object oldGraph = sclContext.put("graph", graph);
277             try {
278                 return q.apply(Tuple0.INSTANCE);
279             } catch (Throwable e) {
280                 if(e instanceof DatabaseException)
281                     throw (DatabaseException)e;
282                 else
283                     throw new DatabaseException(e);
284             } finally {
285                 sclContext.put("graph", oldGraph);
286             }
287         }
288
289         @Override
290         public int hashCode() {
291             return q.hashCode();
292         }
293         
294         @Override
295         public boolean equals(Object obj) {
296             if(this == obj)
297                 return true;
298             if(obj == null || obj.getClass() != getClass())
299                 return false;
300             Subquery other = (Subquery)obj;
301             return q.equals(other.q);
302         }
303     }
304
305     public static Object subquery(ReadGraph graph, Function q) throws DatabaseException {
306         return graph.syncRequest(new Subquery(q));
307     }
308
309     public static Object subqueryC(ReadGraph graph, Function q) throws DatabaseException {
310         return graph.syncRequest(new Subquery(q), TransientCacheAsyncListener.<Object>instance());
311     }
312     
313     public static void subqueryL(ReadGraph graph, Function query, Function executeCallback, Function1<Throwable, Tuple> exceptionCallback, Function1<Tuple0, Boolean> isDisposedCallback) throws DatabaseException {
314         graph.asyncRequest(new Subquery(query), new SyncListenerAdapter<Object>() {
315             
316             @Override
317             public void execute(ReadGraph graph, Object result) {
318                 executeCallback.apply(result);
319             }
320             
321             @Override
322             public void exception(ReadGraph graph, Throwable t) {
323                 exceptionCallback.apply(t);
324             }
325             
326             @Override
327             public boolean isDisposed() {
328                 return isDisposedCallback.apply(Tuple0.INSTANCE);
329             }
330         });
331     }
332
333     public static Object possibleFromDynamic(Type expectedType, String moduleName, Object value) {
334         
335         try {
336
337                 
338             Failable<Module> failable = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName);
339             Module module = failable.getResult();
340             
341                 RuntimeEnvironment env = SCLOsgi.MODULE_REPOSITORY.createRuntimeEnvironment(
342                                 EnvironmentSpecification.of(moduleName, ""), module.getParentClassLoader());
343
344             JavaTypeTranslator tr = new JavaTypeTranslator(env.getEnvironment());
345             TypeDesc desc = tr.toTypeDesc(expectedType);
346             String className = desc.getFullName();
347             Class<?> clazz = env.getMutableClassLoader().loadClass(className);
348             if (!clazz.isAssignableFrom(value.getClass()))
349                 return null;
350             
351         } catch (ImportFailureException | ClassNotFoundException e) {
352         }
353         return value;
354     }
355
356 }