]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/CompilePGraphs.java
Add utility class org.simantics.modeling.help.HelpContexts
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / CompilePGraphs.java
1 package org.simantics.modeling;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.UnsupportedEncodingException;
9 import java.net.URL;
10 import java.net.URLDecoder;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.Map;
16 import java.util.Set;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.NullProgressMonitor;
20 import org.simantics.Simantics;
21 import org.simantics.databoard.Bindings;
22 import org.simantics.db.ReadGraph;
23 import org.simantics.db.Resource;
24 import org.simantics.db.WriteGraph;
25 import org.simantics.db.common.request.IndexRoot;
26 import org.simantics.db.common.request.ObjectsWithType;
27 import org.simantics.db.common.request.ReadRequest;
28 import org.simantics.db.common.request.UniqueRead;
29 import org.simantics.db.common.request.WriteRequest;
30 import org.simantics.db.common.utils.Logger;
31 import org.simantics.db.exception.DatabaseException;
32 import org.simantics.db.layer0.adapter.CopyHandler;
33 import org.simantics.db.layer0.adapter.SubgraphExtent.ExtentStatus;
34 import org.simantics.db.layer0.adapter.impl.DefaultCopyHandler;
35 import org.simantics.db.layer0.adapter.impl.DefaultPasteHandler;
36 import org.simantics.db.layer0.adapter.impl.DefaultPasteImportAdvisor;
37 import org.simantics.db.layer0.util.ClipboardUtils;
38 import org.simantics.db.layer0.util.DomainProcessorState;
39 import org.simantics.db.layer0.util.Layer0Utils;
40 import org.simantics.db.layer0.util.ModelTransferableGraphSource;
41 import org.simantics.db.layer0.util.ModelTransferableGraphSourceRequest;
42 import org.simantics.db.layer0.util.SimanticsClipboard.Representation;
43 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
44 import org.simantics.db.layer0.util.SimanticsKeys;
45 import org.simantics.db.layer0.util.TransferableGraphConfiguration2;
46 import org.simantics.db.service.SerialisationSupport;
47 import org.simantics.graph.compiler.CompilationResult;
48 import org.simantics.graph.compiler.ExternalFileLoader;
49 import org.simantics.graph.compiler.GraphCompiler;
50 import org.simantics.graph.compiler.GraphCompilerPreferences;
51 import org.simantics.graph.compiler.ValidationMode;
52 import org.simantics.graph.compiler.internal.ltk.ISource;
53 import org.simantics.graph.compiler.internal.ltk.Problem;
54 import org.simantics.graph.db.TransferableGraphException;
55 import org.simantics.graph.db.TransferableGraphSource;
56 import org.simantics.graph.db.TransferableGraphs;
57 import org.simantics.graph.diff.Diff;
58 import org.simantics.graph.diff.TransferableGraphDelta1;
59 import org.simantics.graph.representation.Identity;
60 import org.simantics.graph.representation.Root;
61 import org.simantics.graph.representation.TransferableGraph1;
62 import org.simantics.graph.representation.TransferableGraphUtils;
63 import org.simantics.graphfile.ontology.GraphFileResource;
64 import org.simantics.layer0.Layer0;
65 import org.simantics.modeling.internal.Activator;
66 import org.simantics.project.management.GraphBundle;
67 import org.simantics.project.management.GraphBundleEx;
68 import org.simantics.project.management.GraphBundleRef;
69 import org.simantics.project.management.PlatformUtil;
70 import org.simantics.utils.FileUtils;
71 import org.simantics.utils.datastructures.Pair;
72 import org.slf4j.LoggerFactory;
73
74 /**
75  * @author Antti Villberg
76  */
77 public class CompilePGraphs {
78
79     private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(CompilePGraphs.class);
80
81     public static interface UserAgent {
82         void reportProblems(CompilationResult result);
83     }
84
85     /**
86      * <code>Simantics/PGraph#compilePGraphs</code> SCL API.
87      * 
88      * @param r
89      * @throws IOException
90      * @throws DatabaseException
91      */
92     public static void compilePGraphs(Resource r) throws IOException, DatabaseException {
93         compilePGraphs(r, null);
94     }
95
96     public static void compilePGraphs(Resource r, UserAgent userAgent) throws IOException, DatabaseException {
97         compilePGraphs(r, userAgent, new NullProgressMonitor());
98     }
99     
100     public static void compilePGraphs(Resource r, UserAgent userAgent, IProgressMonitor monitor) throws IOException, DatabaseException {
101         final Collection<ISource> sources = new ArrayList<>();
102         Collection<TransferableGraph1> dependencies = new ArrayList<>();
103
104         final Pair<String, TransferableGraph1> thisOntology = Simantics.sync(new UniqueRead<Pair<String, TransferableGraph1>>() {
105
106             @Override
107             public Pair<String, TransferableGraph1> perform(ReadGraph graph) throws DatabaseException {
108                 Layer0 L0 = Layer0.getInstance(graph);
109                 Resource parent = graph.getSingleObject(r, L0.PartOf);
110
111                 CopyHandler ch = new DefaultCopyHandler(r) {
112                     protected TransferableGraphConfiguration2 createConfiguration(ReadGraph graph, boolean cut) throws DatabaseException {
113                         Map<Resource, ExtentStatus> preStatus = new HashMap<>();
114                         preStatus.put(r, ExtentStatus.EXTERNAL);
115                         if (!parent.equals(graph.getRootLibrary()))
116                             preStatus.put(parent, ExtentStatus.EXTERNAL);
117                         return new TransferableGraphConfiguration2(null, Collections.emptyList(), preStatus, true, true);
118                     }
119
120                     protected TransferableGraphSource computeSource(ReadGraph graph, TransferableGraphConfiguration2 conf) throws DatabaseException {
121                         return graph.syncRequest(new ModelTransferableGraphSourceRequest(conf) {
122                             protected ModelTransferableGraphSource getSource(ReadGraph graph, TransferableGraphConfiguration2 configuration, DomainProcessorState state, File otherStatementsFile, File valueFile) throws DatabaseException {
123                                 return new ModelTransferableGraphSource(graph, configuration, state, otherStatementsFile, valueFile) {
124                                     @Override
125                                     protected Identity getRootIdentity(DomainProcessorState state, SerialisationSupport support, Resource rootLibrary) throws DatabaseException {
126                                         return new Identity(state.ids.get(support.getTransientId(rootLibrary)), new Root("", ""));
127                                     }
128                                 };
129                             }
130                         });
131                     }
132                 };
133
134                 String uri = graph.getURI(r);
135                 SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();
136                 ch.copyToClipboard(graph, clipboard, monitor);
137                 for (Set<Representation> object : clipboard.getContents()) {
138                     TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
139                     if (tg != null)
140                         return Pair.make(uri, tg);
141                 }
142
143                 return null;
144             }
145         });
146
147         if (thisOntology == null)
148             throw new DatabaseException("Failed to dump the containing ontology of " + r + " into TransferableGraph1");
149
150         dependencies.add(thisOntology.second);
151
152         Collection<GraphBundle> tgs = PlatformUtil.getAllGraphs();
153
154         for (GraphBundle b : tgs) {
155             TransferableGraph1 tg = b.getGraph();
156             Identity id = TransferableGraphUtils.getIdentity2(tg, thisOntology.first);
157             if(id == null) {
158                 dependencies.add(tg);
159             }
160         }
161
162         Simantics.sync(new ReadRequest() {
163             @Override
164             public void run(ReadGraph graph) throws DatabaseException {
165                 Layer0 L0 = Layer0.getInstance(graph);
166                 for (Resource file : graph.syncRequest(new ObjectsWithType(r, L0.ConsistsOf, L0.PGraph))) {
167                     String src = graph.getRelatedValue(file, L0.PGraph_definition, Bindings.STRING);
168                     sources.add(new StringSource(src));
169                 }
170             }
171         });
172
173         GraphCompilerPreferences prefs = new GraphCompilerPreferences();
174         prefs.validate = true;
175         prefs.validateRelationRestrictions = ValidationMode.ERROR;
176         prefs.validateResourceHasType = ValidationMode.IGNORE;
177         final CompilationResult result = Simantics.sync(new UniqueRead<CompilationResult>() {
178             @Override
179             public CompilationResult perform(ReadGraph graph) throws DatabaseException {
180                 final Resource root = graph.syncRequest(new IndexRoot(r));
181                 final String baseURI = graph.getURI(root);
182
183                 GraphFileResource GF = GraphFileResource.getInstance(graph);
184                 ExternalFileLoader fileLoader = fileName -> {
185                     try {
186                         Resource file = graph.getResource(baseURI + "/" + fileName);
187                         return graph.getRelatedValue(file, GF.HasFiledata, Bindings.BYTE_ARRAY);
188                     } catch (DatabaseException e) {
189                         throw new IOException(e);
190                     }
191                 };
192
193                 return GraphCompiler.compile("1.1", sources, dependencies, fileLoader, prefs);
194             }
195         });
196
197         if (!result.getErrors().isEmpty() || !result.getWarnings().isEmpty()) {
198             if (userAgent != null) {
199                 userAgent.reportProblems(result);
200                 return;
201             } else {
202                 StringBuilder error = new StringBuilder();
203                 for (Problem problem : result.getErrors())
204                     error.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
205                 for (Problem problem : result.getWarnings())
206                     error.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
207                 throw new DatabaseException(error.toString());
208             }
209         }
210
211         final Pair<TransferableGraph1, long[]> existing = Simantics.sync(new UniqueRead<Pair<TransferableGraph1, long[]>>() {
212             @Override
213             public Pair<TransferableGraph1, long[]> perform(ReadGraph graph) throws DatabaseException {
214                 Layer0 L0 = Layer0.getInstance(graph);
215                 TransferableGraph1 tg = graph.getPossibleRelatedValue(r, L0.SharedOntology_tg, Bindings.getBindingUnchecked( TransferableGraph1.class ));
216                 if(tg == null) return null;
217                 long[] tgResources = graph.getPossibleRelatedValue(r, L0.SharedOntology_tgResources, Bindings.LONG_ARRAY);
218                 if(tgResources == null) return null;
219                 return Pair.make(tg,  tgResources);
220             }
221         });
222
223         if (existing != null) {
224             Simantics.sync(new WriteRequest() {
225                 @Override
226                 public void perform(WriteGraph graph) throws DatabaseException {
227                     TransferableGraphDelta1 delta = new Diff(existing.first, result.getGraph()).diff();
228                     long[] resourceArray = TransferableGraphs.applyDelta(graph, existing.second, delta);
229
230                     Layer0 L0 = Layer0.getInstance(graph);
231                     graph.claimLiteral(r, L0.SharedOntology_tg, result.getGraph(), Bindings.getBindingUnchecked( TransferableGraph1.class ));
232                     graph.claimLiteral(r, L0.SharedOntology_tgResources, L0.ResourceIdArray, resourceArray, Bindings.LONG_ARRAY);
233
234                     Layer0Utils.addCommentMetadata(graph, "Compiled ontology " + graph.getURI(r));
235                 }
236             });
237         } else {
238             final DefaultPasteImportAdvisor advisor = new DefaultPasteImportAdvisor(r);
239             try {
240                 DefaultPasteHandler.defaultExecute(result.getGraph(), r, advisor);
241             } catch (TransferableGraphException e) {
242                 // TODO: defaultExecute never actually throws this exception!
243                 throw new DatabaseException(e);
244             }
245
246             Simantics.sync(new WriteRequest() {
247                 @Override
248                 public void perform(WriteGraph graph) throws DatabaseException {
249                     Layer0 L0 = Layer0.getInstance(graph);
250                     graph.claimLiteral(r, L0.SharedOntology_tg, result.getGraph(), Bindings.getBindingUnchecked( TransferableGraph1.class ));
251                     graph.claimLiteral(r, L0.SharedOntology_tgResources, L0.ResourceIdArray, advisor.getResourceIds(), Bindings.LONG_ARRAY);
252
253                     Layer0Utils.addCommentMetadata(graph, "Compiled ontology " + graph.getURI(r));
254                 }
255             });
256         }
257         
258         // Delete index to get rid of floating old instances of the same ontology
259 //        DatabaseIndexing.deleteAllIndexes();
260     }
261
262     private static File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException {
263         String tmpDirStr = System.getProperty("java.io.tmpdir");
264         if (tmpDirStr == null)
265             throw new NullPointerException("java.io.tmpdir property is null");
266         File tmpDir = new File(tmpDirStr);
267         File libFile = new File(tmpDir, libName);
268         return FileUtils.copyResource(libURL, libFile, false);
269     }
270
271     private static File url2file(URL url, String fileName) {
272         if ("file".equals(url.getProtocol())) {
273             try {
274                 File path = new File(URLDecoder.decode(url.getPath(), "UTF-8"));
275                 return path;
276             } catch (UnsupportedEncodingException e) {
277                 Logger.defaultLogError(e);
278             }
279         } else if ("jar".equals(url.getProtocol())) {
280             try {
281                 File libFile = extractLib(url, fileName);
282                 return libFile;
283             } catch (FileNotFoundException e) {
284                 Logger.defaultLogError(e);
285             } catch (IOException e) {
286                 Logger.defaultLogError(e);
287             }
288         } else {
289             LOGGER.warn("Unsupported URL protocol");
290         }   
291         return null;
292     }
293
294     private static class StringSource implements ISource {
295         private String src;
296         private ByteArrayInputStream baos;
297
298         public StringSource(String s) {
299             this.src = s;
300             this.baos = new ByteArrayInputStream(src.getBytes());
301         }
302
303         @Override
304         public int startPos() {
305             return 0;
306         }
307
308         @Override
309         public int startLine() {
310             return 0;
311         }
312
313         @Override
314         public InputStream open() throws IOException {
315             return baos;
316         }
317
318         @Override
319         public int length() throws IOException {
320             return src.length();
321         }
322
323         @Override
324         public String getName() {
325             return "Source";
326         }
327     }
328
329 }