]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.db/src/org/simantics/scl/db/SCLFunctions.java
Playground for Antti.
[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 import java.util.ArrayList;
5 import java.util.List;
6 import java.util.concurrent.Callable;
7
8 import org.cojen.classfile.TypeDesc;
9 import org.simantics.Simantics;
10 import org.simantics.db.ReadGraph;
11 import org.simantics.db.Resource;
12 import org.simantics.db.VirtualGraph;
13 import org.simantics.db.WriteGraph;
14 import org.simantics.db.common.procedure.adapter.SyncListenerAdapter;
15 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
16 import org.simantics.db.common.request.BinaryRead;
17 import org.simantics.db.common.request.DelayedWriteRequest;
18 import org.simantics.db.common.request.ReadRequest;
19 import org.simantics.db.common.request.UnaryRead;
20 import org.simantics.db.common.request.WriteRequest;
21 import org.simantics.db.common.request.WriteResultRequest;
22 import org.simantics.db.exception.DatabaseException;
23 import org.simantics.db.layer0.util.Layer0Utils;
24 import org.simantics.db.layer0.variable.Variables;
25 import org.simantics.db.request.Read;
26 import org.simantics.db.service.ClusterControl;
27 import org.simantics.db.service.QueryControl;
28 import org.simantics.db.service.SerialisationSupport;
29 import org.simantics.db.service.VirtualGraphSupport;
30 import org.simantics.layer0.utils.triggers.IActivationManager;
31 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
32 import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
33 import org.simantics.scl.compiler.errors.DoesNotExist;
34 import org.simantics.scl.compiler.errors.Failable;
35 import org.simantics.scl.compiler.errors.Failure;
36 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
37 import org.simantics.scl.compiler.module.Module;
38 import org.simantics.scl.compiler.module.repository.ImportFailureException;
39 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
40 import org.simantics.scl.compiler.runtime.RuntimeModule;
41 import org.simantics.scl.compiler.top.ValueNotFound;
42 import org.simantics.scl.compiler.types.TCon;
43 import org.simantics.scl.compiler.types.Type;
44 import org.simantics.scl.compiler.types.Types;
45 import org.simantics.scl.compiler.types.exceptions.MatchException;
46 import org.simantics.scl.compiler.types.util.MultiFunction;
47 import org.simantics.scl.osgi.SCLOsgi;
48 import org.simantics.scl.reflection.ValueNotFoundException;
49 import org.simantics.scl.runtime.SCLContext;
50 import org.simantics.scl.runtime.function.Function;
51 import org.simantics.scl.runtime.function.Function1;
52 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
53 import org.simantics.scl.runtime.tuple.Tuple;
54 import org.simantics.scl.runtime.tuple.Tuple0;
55 import org.simantics.utils.DataContainer;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 @SuppressWarnings({"rawtypes", "unchecked"})
60 public class SCLFunctions {
61
62     private static final Logger LOGGER = LoggerFactory.getLogger(SCLFunctions.class);
63
64     public static final String GRAPH = "graph";
65
66     public static <T> T safeExec(final Function f) {
67         try {
68             return (T)f.apply(Tuple0.INSTANCE);
69         } catch (Throwable t) {
70             LOGGER.error("safeExec caught exception", t);
71             return null;
72         }
73     }
74
75     public static Function resolveFunction(RuntimeModule rm, String function) throws ValueNotFound {
76         return (Function)rm.getValue(function);
77     }
78     
79     private static SCLValue resolveSCLValue(RuntimeModule rm, String function) throws ValueNotFound {
80         return rm.getModule().getValue(function);
81     }
82     
83     private static RuntimeModule resolveRuntimeModule(String module) throws ValueNotFound {
84         Failable<RuntimeModule> f = SCLOsgi.MODULE_REPOSITORY.getRuntimeModule(module);
85         if(f.didSucceed())
86             return f.getResult();
87         else if(f == DoesNotExist.INSTANCE)
88             throw new ValueNotFound("Didn't find module " + module);
89         else
90             throw new ValueNotFound(((Failure)f).toString());
91     }
92     
93     private static List<TCon> getEffects(SCLValue value) throws ValueNotFoundException, ValueNotFound, MatchException {
94     
95         Type type = value.getType();
96         MultiFunction mfun = Types.matchFunction(type, 1);
97         ArrayList<TCon> concreteEffects = new ArrayList<>();
98         mfun.effect.collectConcreteEffects(concreteEffects);
99         return concreteEffects;
100         
101     }
102
103     public static List<TCon> getEffects(RuntimeModule rm, String function) throws ValueNotFoundException, ValueNotFound, MatchException {
104         return getEffects(resolveSCLValue(rm, function));
105     }
106
107     public static List<TCon> getEffects(String module, String function) throws ValueNotFoundException, ValueNotFound, MatchException {
108         return getEffects(resolveSCLValue(resolveRuntimeModule(module), function));
109     }
110     
111     private static <T> T evaluate(Function function, Object ... args) {
112         return (T)function.applyArray(args);
113     }
114
115     private static <T> T evaluate(RuntimeModule rm, String function, Object ... args) throws ValueNotFound {
116         return evaluate(resolveFunction(rm, function));
117     }
118
119     public static <T> T evaluate(String module, String function, Object ... args) throws ValueNotFound {
120         return evaluate(resolveRuntimeModule(module), function, args);
121     }
122
123     public static <T> T evaluateDB(String module, String function, Object ... args) throws DatabaseException {
124         try {
125             RuntimeModule rm = resolveRuntimeModule(module);
126             List<TCon> effects = getEffects(resolveSCLValue(rm, function));
127             Function f = resolveFunction(rm, function);
128             if(effects.contains(Types.WRITE_GRAPH)) {
129                 return syncWrite(f, args);
130             } else if(effects.contains(Types.READ_GRAPH)) {
131                 return syncRead(f, args);
132             } else {
133                 return evaluate(f, args);
134             }
135         } catch (ValueNotFound e) {
136             throw new DatabaseException("SCL Value not found: " + e.name);
137         } catch (Throwable t) {
138             if (t instanceof DatabaseException)
139                 throw (DatabaseException) t;
140             throw new DatabaseException(t);
141         }
142     }
143     
144     public static <T> T evaluateGraph(String module, String function, Object graph, Object ... args) throws DatabaseException {
145         final SCLContext context = SCLContext.getCurrent();
146         SCLContext.push(context);
147         Object oldGraph = context.put(GRAPH, graph);
148         try {
149             return evaluateDB(module, function, args);
150         } finally {
151             context.put(GRAPH, oldGraph);
152             SCLContext.pop();
153         }
154     }
155     
156     public static void runWithGraph(Object graph, Runnable r) {
157         final SCLContext context = SCLContext.getCurrent();
158         SCLContext.push(context);
159         Object oldGraph = context.put(GRAPH, graph);
160         try {
161             r.run();
162         } finally {
163             context.put(GRAPH, oldGraph);
164             SCLContext.pop();
165         }
166     }
167
168     private static Object[] NO_ARGS = new Object[] { Tuple0.INSTANCE };
169
170     public static <T> void asyncRead(final Function f) throws DatabaseException {    
171         asyncRead(f, NO_ARGS);
172     }
173
174     public static void asyncRead(final Function f, final Object ... args) throws DatabaseException {
175         final SCLContext context = SCLContext.createDerivedContext();
176         Simantics.getSession().asyncRequest(new ReadRequest() {
177             @Override
178             public void run(ReadGraph graph) throws DatabaseException {
179                 SCLContext.push(context);
180                 context.put(GRAPH, graph);
181                 try {
182                     f.apply(Tuple0.INSTANCE);
183                 } finally {
184                     SCLContext.pop();
185                 }
186             }
187         });
188     }
189     
190     public static <T> T syncRead(final Function f) throws DatabaseException {
191         return syncRead(f, NO_ARGS);
192     }
193     
194     public static <T> T syncRead(final Function f, final Object ... args) throws DatabaseException {
195         final SCLContext context = SCLContext.getCurrent();
196         Object graph = context.get(GRAPH);
197         if (graph != null) {
198             return (T)f.applyArray(args);
199         } else {
200             return Simantics.getSession().syncRequest(new Read<T>() {
201                 @Override
202                 public T perform(ReadGraph graph) throws DatabaseException {
203                     SCLContext.push(context);
204                     ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
205                     try {
206                         return (T)f.apply(Tuple0.INSTANCE);
207                     } finally {
208                         context.put(GRAPH, oldGraph);
209                         SCLContext.pop();
210                     }
211                 }
212             });
213         }
214     }
215
216     public static void asyncWrite(final Function f) throws DatabaseException {
217         asyncWrite(f, NO_ARGS);
218     }
219
220     public static void asyncWrite(final Function f, final Object ... args) throws DatabaseException {
221         SCLContext context = SCLContext.createDerivedContext();
222         if (Simantics.peekSession() != null) {
223             Simantics.getSession().asyncRequest(new WriteRequest() {
224                 @Override
225                 public void perform(WriteGraph graph) throws DatabaseException {
226                     SCLContext.push(context);
227                     context.put(GRAPH, graph);
228                     try {
229                         f.apply(args);
230                     } finally {
231                         SCLContext.pop();
232                     }
233                 }
234             });
235         } else {
236             LOGGER.warn("No session available for asynchronous write requests");
237         }
238     }
239     
240     public static <T> T syncWrite(final Function f) throws DatabaseException {
241         return syncWrite(f, NO_ARGS);
242     }
243
244     public static <T> T syncWrite(final Function f, final Object ... args) throws DatabaseException {
245         final SCLContext context = SCLContext.getCurrent();
246         Object graph = context.get(GRAPH);
247         if (graph != null) {
248             return (T)f.apply(Tuple0.INSTANCE);
249         } else {
250             final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
251             return Simantics.getSession().syncRequest(new WriteResultRequest<T>() {
252                 @Override
253                 public T perform(WriteGraph graph) throws DatabaseException {
254                     SCLContext.push(context);
255                     SCLReportingHandler oldPrinter = (SCLReportingHandler)context.put(SCLReportingHandler.REPORTING_HANDLER, printer);
256                     ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
257                     try {
258                         return (T)f.apply(args);
259                     } finally {
260                         context.put(GRAPH, oldGraph);
261                         context.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
262                         SCLContext.pop();
263                     }
264                 }
265             });
266         }
267     }
268     
269     public static <T> T delayedSyncWrite(final Function f) throws DatabaseException {
270         final SCLContext context = SCLContext.getCurrent();
271         final DataContainer<T> dc = new DataContainer<T>(null);
272
273         DelayedWriteRequest request = new DelayedWriteRequest() {
274             @Override
275             public void perform(WriteGraph graph) throws DatabaseException {
276                 final SCLContext context = SCLContext.getCurrent();
277                 SCLContext.push(context);
278                 ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
279                 try {
280                     dc.set((T)f.apply(Tuple0.INSTANCE));
281                 } finally {
282                     context.put(GRAPH, oldGraph);
283                     SCLContext.pop();
284                 }
285             }
286         };
287     
288         Object graph = context.get(GRAPH);
289         if (graph != null) {
290             if (graph instanceof WriteGraph) {
291                 ((WriteGraph)graph).syncRequest(request);
292             } else {
293                 throw new DatabaseException("Caller is inside a read transaction.");
294             }
295         } else {
296             Simantics.getSession().syncRequest(request);
297         }
298         return dc.get();
299     }
300
301     public static <T> T virtualSyncWriteMem(WriteGraph graph, String virtualGraphId, final Function f) throws DatabaseException {
302         final SCLContext context = SCLContext.getCurrent();
303         VirtualGraphSupport vgs = graph.getService(VirtualGraphSupport.class);
304         VirtualGraph vg = vgs.getMemoryPersistent(virtualGraphId);
305         return graph.syncRequest(new WriteResultRequest<T>(vg) {
306             @Override
307             public T perform(WriteGraph graph) throws DatabaseException {
308                 SCLContext.push(context);
309                 ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
310                 try {
311                     return (T)f.apply(Tuple0.INSTANCE);
312                 } finally {
313                     context.put(GRAPH, oldGraph);
314                     SCLContext.pop();
315                 }
316             }
317         });
318     }
319     
320     public static <T> T virtualSyncWriteWS(WriteGraph graph, String virtualGraphId, final Function f) throws DatabaseException {
321         final SCLContext context = SCLContext.getCurrent();
322         VirtualGraphSupport vgs = graph.getService(VirtualGraphSupport.class);
323         VirtualGraph vg = vgs.getWorkspacePersistent(virtualGraphId);
324         return graph.syncRequest(new WriteResultRequest<T>(vg) {
325             @Override
326             public T perform(WriteGraph graph) throws DatabaseException {
327                 SCLContext.push(context);
328                 ReadGraph oldGraph = (ReadGraph)context.put(GRAPH, graph);
329                 try {
330                     return (T)f.apply(Tuple0.INSTANCE);
331                 } finally {
332                     context.put(GRAPH, oldGraph);
333                     SCLContext.pop();
334                 }
335             }
336         });
337     }
338     
339     public static <T> T readValue(final String uri) throws DatabaseException {
340         return Simantics.getSession().syncRequest(new Read<T>() {
341             @Override
342             public T perform(ReadGraph graph) throws DatabaseException {
343                 return Variables.getVariable(graph, uri).getValue(graph);
344             }
345         });
346     }
347     
348     public static <T> void writeValue(final String uri, final T value) throws DatabaseException {
349         Simantics.getSession().syncRequest(new WriteRequest() {
350             @Override
351             public void perform(WriteGraph graph) throws DatabaseException {
352                 Variables.getVariable(graph, uri).setValue(graph, value);
353             }
354         });
355     }
356     
357     public static void activateOnce(Resource r) {
358         Simantics.getSession().getService(IActivationManager.class).activateOnce(r);
359     }
360     
361     public static void syncActivateOnce(WriteGraph graph, Resource r) throws DatabaseException {
362         graph.getService(IActivationManager.class).activateOnce(graph, r);
363     }
364
365     public static Resource resourceFromId(ReadGraph graph, long id) throws DatabaseException, IOException {
366         SerialisationSupport ss = graph.getService(SerialisationSupport.class);
367         return ss.getResource(id);
368     }
369     
370     public static void disableDependencies(WriteGraph graph) {
371         Layer0Utils.setDependenciesIndexingDisabled(graph, true);       
372     }
373     
374     public static void enableDependencies(WriteGraph graph) {
375         Layer0Utils.setDependenciesIndexingDisabled(graph, false);       
376     }
377     
378     public static void collectClusters() {
379         Simantics.getSession().getService(ClusterControl.class).collectClusters(Integer.MAX_VALUE);
380     }
381     
382     public static class SCLUnaryRead extends BinaryRead<Function1<Object,Object>, Object, Object> {
383
384         public SCLUnaryRead(Function1<Object, Object> parameter1, Object parameter2) {
385              super(parameter1, parameter2);
386         }
387
388         @Override
389         public Object perform(ReadGraph graph) throws DatabaseException {
390             return Simantics.applySCLRead(graph, parameter, parameter2);
391         }
392
393     }
394     
395     public static Object unaryQuery(ReadGraph graph, Function1<Object,Object> fn, Object value) throws DatabaseException {
396         return graph.syncRequest(new SCLUnaryRead(fn, value));
397     }
398
399     public static Object unaryQueryCached(ReadGraph graph, Function1<Object,Object> fn, Object value) throws DatabaseException {
400         return graph.syncRequest(new SCLUnaryRead(fn, value), TransientCacheAsyncListener.<Object>instance());
401     }
402     
403
404     private static class Subquery extends UnaryRead<Function, Object> {
405
406         public Subquery(Function q) {
407             super(q);
408         }
409
410         @Override
411         public Object perform(ReadGraph graph) throws DatabaseException {
412             return Simantics.applySCLRead(graph, parameter, Tuple0.INSTANCE);
413         }
414
415     }
416
417     public static Object subquery(ReadGraph graph, Function q) throws DatabaseException {
418         return graph.syncRequest(new Subquery(q));
419     }
420
421     public static Object subqueryC(ReadGraph graph, Function q) throws DatabaseException {
422         return graph.syncRequest(new Subquery(q), TransientCacheAsyncListener.<Object>instance());
423     }
424     
425     public static void subqueryL(ReadGraph graph, Function query, Function executeCallback, Function1<Throwable, Tuple> exceptionCallback, Function1<Tuple0, Boolean> isDisposedCallback) throws DatabaseException {
426         graph.syncRequest(new Subquery(query), new SyncListenerAdapter<Object>() {
427             @Override
428             public void execute(ReadGraph graph, Object result) throws DatabaseException {
429                 Simantics.applySCLRead(graph, executeCallback, result);
430             }
431             
432             @Override
433             public void exception(ReadGraph graph, Throwable t) throws DatabaseException {
434                 Simantics.applySCLRead(graph, exceptionCallback, t);
435             }
436             
437             @Override
438             public boolean isDisposed() {
439                 return isDisposedCallback.apply(Tuple0.INSTANCE);
440             }
441         });
442     }
443
444     public static Object possibleFromDynamic(Type expectedType, String moduleName, Object value) {
445     
446         try {
447
448         
449             Failable<Module> failable = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName);
450             Module module = failable.getResult();
451             
452             RuntimeEnvironment env = SCLOsgi.MODULE_REPOSITORY.createRuntimeEnvironment(
453             EnvironmentSpecification.of(moduleName, ""), module.getParentClassLoader());
454
455             JavaTypeTranslator tr = new JavaTypeTranslator(env.getEnvironment());
456             TypeDesc desc = tr.toTypeDesc(expectedType);
457             String className = desc.getFullName();
458             Class<?> clazz = env.getMutableClassLoader().loadClass(className);
459             if (!clazz.isAssignableFrom(value.getClass()))
460                 return null;
461             
462         } catch (ImportFailureException | ClassNotFoundException e) {
463         }
464         return value;
465     }
466
467     public static void restrictQueries(ReadGraph graph, int amount, int step, int maxTimeInMs) {
468
469         QueryControl qc = graph.getService(QueryControl.class);
470         long start = System.currentTimeMillis();
471         while(true) {
472             int current = qc.count();
473             if(current < amount) return;
474             qc.gc(graph, step);
475             long duration = System.currentTimeMillis() - start;
476             if(duration > maxTimeInMs) return;
477         }
478
479     }
480
481     public static int countQueries(ReadGraph graph) {
482
483         QueryControl qc = graph.getService(QueryControl.class);
484         return qc.count();
485
486     }
487     
488 }