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