Automatically import also SCLMain modules of dependent index roots
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / util / RuntimeEnvironmentRequest2.java
1 package org.simantics.db.layer0.util;
2
3 import java.util.Collection;
4
5 import org.simantics.db.ReadGraph;
6 import org.simantics.db.Resource;
7 import org.simantics.db.common.request.BinaryRead;
8 import org.simantics.db.common.request.ObjectsWithType;
9 import org.simantics.db.common.request.ParametrizedPrimitiveRead;
10 import org.simantics.db.common.utils.CommonDBUtils;
11 import org.simantics.db.exception.DatabaseException;
12 import org.simantics.db.layer0.internal.SimanticsInternal;
13 import org.simantics.db.procedure.Listener;
14 import org.simantics.db.request.Read;
15 import org.simantics.layer0.Layer0;
16 import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
17 import org.simantics.scl.compiler.module.repository.ImportFailureException;
18 import org.simantics.scl.compiler.module.repository.UpdateListener;
19 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
20 import org.simantics.scl.osgi.SCLOsgi;
21 import org.simantics.scl.runtime.SCLContext;
22
23 /**
24  * Finds the runtime environment of a model or other index root.
25  * 
26  * @author Hannu Niemistö
27  * @author Antti Villberg
28  * 
29  * Difference between this class and {@code RuntimeEnvironmentRequest} is an additional parameter
30  * that is typically some component type. All modules under this resource are added to the environment
31  * in addition to the SCLMain of the root resource. 
32  */
33 public class RuntimeEnvironmentRequest2 extends BinaryRead<Resource, Resource, RuntimeEnvironment> {
34
35     public RuntimeEnvironmentRequest2(Resource componentType, Resource indexRoot) {
36         super(componentType, indexRoot);
37     }
38
39     protected void fillEnvironmentSpecification(EnvironmentSpecification environmentSpecification) {
40     }
41
42     static class UpdateListenerImpl extends UpdateListener {
43
44         final EnvironmentSpecification environmentSpecification;
45         final Listener<RuntimeEnvironment> callback;
46
47         UpdateListenerImpl(EnvironmentSpecification environmentSpecification, Listener<RuntimeEnvironment> callback) {
48             this.environmentSpecification = environmentSpecification;
49             this.callback = callback;
50         }
51
52         @Override
53         public void notifyAboutUpdate() {
54             if(callback.isDisposed()) {
55                 stopListening();
56                 return;
57             }
58             getRuntimeEnvironment(environmentSpecification, callback, this);
59         }
60     };
61
62     public static void getRuntimeEnvironment(EnvironmentSpecification environmentSpecification, Listener<RuntimeEnvironment> callback, UpdateListenerImpl listener) {
63
64         try {
65
66             SCLContext context = SCLContext.getCurrent();
67
68             RuntimeEnvironment env;
69             Object graph = context.get("graph");
70             if(graph == null)
71                 try {
72                     env = SimanticsInternal.getSession().syncRequest(new Read<RuntimeEnvironment>() {
73                         @Override
74                         public RuntimeEnvironment perform(ReadGraph graph) throws DatabaseException {
75
76                             SCLContext sclContext = SCLContext.getCurrent();
77                             Object oldGraph = sclContext.get("graph");
78                             try {
79                                 sclContext.put("graph", graph);
80                                 return SCLOsgi.MODULE_REPOSITORY.createRuntimeEnvironment(
81                                         environmentSpecification,
82                                         callback.getClass().getClassLoader(), listener);
83                             } catch (ImportFailureException e) {
84                                 throw new DatabaseException(e);
85                             } catch (Throwable t) {
86                                 throw new DatabaseException(t);
87                             } finally {
88                                 sclContext.put("graph", oldGraph);
89                             }
90                         }
91                     });
92                 } catch (DatabaseException e) {
93                     callback.exception(e);
94                     return;
95                 }
96             else 
97                 env = SCLOsgi.MODULE_REPOSITORY.createRuntimeEnvironment(
98                         environmentSpecification,
99                         callback.getClass().getClassLoader(), listener);
100             callback.execute(env);
101         } catch (ImportFailureException e) {
102             callback.exception(new DatabaseException(e));
103         }
104
105     }
106
107     @Override
108     public RuntimeEnvironment perform(ReadGraph graph)
109             throws DatabaseException {
110         final EnvironmentSpecification environmentSpecification = EnvironmentSpecification.of(
111                 "Builtin", "",
112                 "StandardLibrary", "",
113                 "Simantics/All", "");
114         fillEnvironmentSpecification(environmentSpecification);
115
116         Layer0 L0 = Layer0.getInstance(graph);
117         if (parameter != null) {
118             Collection<Resource> sclModules = graph.syncRequest(new ObjectsWithType(parameter, L0.ConsistsOf, L0.SCLModule));
119             for (Resource sclModule : sclModules) {
120                 environmentSpecification.importModule(graph.getURI(sclModule), "");
121             }
122         } else {
123             // `parameter` is optional and can be null for e.g. procedural user components
124         }
125
126         Resource mainModule = CommonDBUtils.getPossibleChild(graph, parameter2, "SCLMain");
127         if(mainModule != null) {
128             environmentSpecification.importModule(graph.getURI(mainModule), "");
129             for(Resource l : graph.getObjects(parameter2, L0.IsLinkedTo)) {
130                 mainModule = CommonDBUtils.getPossibleChild(graph, l, "SCLMain");
131                 if(mainModule != null)
132                     environmentSpecification.importModule(graph.getURI(mainModule), "");
133             }
134         }
135
136         return graph.syncRequest(new ParametrizedPrimitiveRead<EnvironmentSpecification, RuntimeEnvironment>(environmentSpecification) {
137
138             UpdateListenerImpl sclListener;
139
140             @Override
141             public void register(ReadGraph graph, Listener<RuntimeEnvironment> procedure) {
142
143                 SCLContext context = SCLContext.getCurrent();
144                 Object oldGraph = context.put("graph", graph);
145                 try {
146
147                     if(procedure.isDisposed()) {
148                         getRuntimeEnvironment(parameter, procedure, null);
149                     } else {
150                         sclListener = new UpdateListenerImpl(parameter, procedure);
151                         sclListener.notifyAboutUpdate();
152                     }
153
154                 } finally {
155                     context.put("graph", oldGraph);
156                 }
157
158             }
159
160             @Override
161             public void unregistered() {
162                 if(sclListener != null)
163                     sclListener.stopListening();
164             }
165
166         });
167     }
168
169     @Override
170     public int hashCode() {
171         return 31*getClass().hashCode() + super.hashCode();
172     }
173
174 }