Automatically import also SCLMain modules of dependent index roots
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / util / EnvironmentRequest.java
1 package org.simantics.db.layer0.util;
2
3 import org.simantics.db.ReadGraph;
4 import org.simantics.db.Resource;
5 import org.simantics.db.common.request.ParametrizedPrimitiveRead;
6 import org.simantics.db.common.request.UnaryRead;
7 import org.simantics.db.common.utils.CommonDBUtils;
8 import org.simantics.db.exception.DatabaseException;
9 import org.simantics.db.layer0.internal.SimanticsInternal;
10 import org.simantics.db.procedure.Listener;
11 import org.simantics.db.request.Read;
12 import org.simantics.layer0.Layer0;
13 import org.simantics.scl.compiler.environment.Environment;
14 import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
15 import org.simantics.scl.compiler.module.repository.ImportFailureException;
16 import org.simantics.scl.compiler.module.repository.UpdateListener;
17 import org.simantics.scl.osgi.SCLOsgi;
18 import org.simantics.scl.runtime.SCLContext;
19 import org.simantics.utils.datastructures.Pair;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 /**
24  * Finds the environment of a model or other index root.
25  */
26 public abstract class EnvironmentRequest extends UnaryRead<Resource, Pair<EnvironmentSpecification, Environment>> {
27     private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentRequest.class);
28
29     public EnvironmentRequest(Resource parameter) {
30         super(parameter);
31     }
32
33     protected abstract void fillEnvironmentSpecification(EnvironmentSpecification environmentSpecification);
34     protected abstract String getRootModuleName();
35
36     static class UpdateListenerImpl extends UpdateListener {
37
38         final EnvironmentSpecification environmentSpecification;
39         final Listener<Environment> callback;
40
41         UpdateListenerImpl(EnvironmentSpecification environmentSpecification, Listener<Environment> callback) {
42             this.environmentSpecification = environmentSpecification;
43             this.callback = callback;
44         }
45
46         @Override
47         public void notifyAboutUpdate() {
48             if(callback.isDisposed()) {
49                 stopListening();
50                 return;
51             }
52             getEnvironment(environmentSpecification, callback, this);
53         }
54     };     
55
56     public static void getEnvironment(EnvironmentSpecification environmentSpecification, Listener<Environment> callback, UpdateListenerImpl listener) {
57
58         try {
59
60             SCLContext context = SCLContext.getCurrent();
61
62             Environment env;
63             Object graph = context.get("graph");
64             if(graph == null)
65                 try {
66                     env = SimanticsInternal.getSession().syncRequest(new Read<Environment>() {
67                         @Override
68                         public Environment perform(ReadGraph graph) throws DatabaseException {
69
70                             SCLContext sclContext = SCLContext.getCurrent();
71                             Object oldGraph = sclContext.get("graph");
72                             try {
73                                 sclContext.put("graph", graph);
74                                 return SCLOsgi.MODULE_REPOSITORY.createEnvironment(
75                                         environmentSpecification, listener);
76                             } catch (ImportFailureException e) {
77                                 throw new DatabaseException(e);
78                             } catch (Throwable t) {
79                                 throw new DatabaseException(t);
80                             } finally {
81                                 sclContext.put("graph", oldGraph);
82                             }
83                         }
84                     });
85                 } catch (DatabaseException e) {
86                     LOGGER.error("Finding environment failed", e);
87                     callback.exception(e);
88                     return;
89                 }
90             else 
91                 env = SCLOsgi.MODULE_REPOSITORY.createEnvironment(
92                         environmentSpecification, listener);
93             callback.execute(env);
94         } catch (ImportFailureException e) {
95             LOGGER.error("Finding environment failed", e);
96             callback.exception(new DatabaseException(e));
97         }
98
99     }
100
101     @Override
102     public Pair<EnvironmentSpecification, Environment> perform(ReadGraph graph)
103             throws DatabaseException {
104         final EnvironmentSpecification environmentSpecification = EnvironmentSpecification.of(
105                 "Builtin", "",
106                 "StandardLibrary", "");
107         fillEnvironmentSpecification(environmentSpecification);
108         Resource mainModule = CommonDBUtils.getPossibleChild(graph, parameter, getRootModuleName());
109         String mainModuleUri;
110         if(mainModule != null) {
111             mainModuleUri = graph.getURI(mainModule);
112             environmentSpecification.importModule(mainModuleUri, "");
113             Layer0 L0 = Layer0.getInstance(graph);
114             for(Resource l : graph.getObjects(parameter, L0.IsLinkedTo)) {
115                 mainModule = CommonDBUtils.getPossibleChild(graph, l, "SCLMain");
116                 if(mainModule != null)
117                     environmentSpecification.importModule(graph.getURI(mainModule), "");
118             }
119         }
120         else
121             mainModuleUri = graph.getURI(parameter) + "/#"; // Add something dummy to the model uri that cannot be in a real URI
122
123         try {
124             return Pair.make(environmentSpecification, graph.syncRequest(new ParametrizedPrimitiveRead<String, Environment>(mainModuleUri) {
125     
126                 UpdateListenerImpl sclListener;
127     
128                 @Override
129                 public void register(ReadGraph graph, Listener<Environment> procedure) {
130     
131                     SCLContext context = SCLContext.getCurrent();
132                     Object oldGraph = context.put("graph", graph);
133                     try {
134     
135                         if(procedure.isDisposed()) {
136                             getEnvironment(environmentSpecification, procedure, null);
137                         } else {
138                             sclListener = new UpdateListenerImpl(environmentSpecification, procedure);
139                             sclListener.notifyAboutUpdate();
140                         }
141     
142                     } finally {
143                         context.put("graph", oldGraph);
144                     }
145     
146                 }
147     
148                 @Override
149                 public void unregistered() {
150                     if(sclListener != null)
151                         sclListener.stopListening();
152                 }
153     
154             }));
155         } catch(DatabaseException e) {
156             LOGGER.error("Environment request failed", e);
157             throw e;
158         }
159     }
160
161     @Override
162     public int hashCode() {
163         return 31*getClass().hashCode() + super.hashCode();
164     }
165
166 }