4272b9de7f28e9277c94c29328c7546afdcbddf6
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / actions / CompilePGraphs.java
1 package org.simantics.modeling.ui.actions;
2
3 import static org.simantics.db.common.utils.Transaction.endTransaction;
4
5 import java.io.ByteArrayInputStream;
6 import java.io.Closeable;
7 import java.io.File;
8 import java.io.FileNotFoundException;
9 import java.io.FileOutputStream;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.io.UnsupportedEncodingException;
13 import java.net.URL;
14 import java.net.URLDecoder;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.Map;
20 import java.util.Set;
21
22 import org.eclipse.core.runtime.FileLocator;
23 import org.eclipse.jface.dialogs.MessageDialog;
24 import org.eclipse.jface.layout.GridDataFactory;
25 import org.eclipse.jface.layout.GridLayoutFactory;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.widgets.Composite;
28 import org.eclipse.swt.widgets.Control;
29 import org.eclipse.swt.widgets.Display;
30 import org.eclipse.swt.widgets.Shell;
31 import org.osgi.framework.Bundle;
32 import org.simantics.PlatformException;
33 import org.simantics.Simantics;
34 import org.simantics.databoard.Bindings;
35 import org.simantics.db.ReadGraph;
36 import org.simantics.db.Resource;
37 import org.simantics.db.WriteGraph;
38 import org.simantics.db.common.request.IndexRoot;
39 import org.simantics.db.common.request.ObjectsWithType;
40 import org.simantics.db.common.request.ReadRequest;
41 import org.simantics.db.common.request.UniqueRead;
42 import org.simantics.db.common.request.WriteRequest;
43 import org.simantics.db.common.utils.Logger;
44 import org.simantics.db.exception.DatabaseException;
45 import org.simantics.db.layer0.adapter.ActionFactory;
46 import org.simantics.db.layer0.adapter.CopyHandler;
47 import org.simantics.db.layer0.adapter.SubgraphExtent.ExtentStatus;
48 import org.simantics.db.layer0.adapter.impl.DefaultCopyHandler;
49 import org.simantics.db.layer0.adapter.impl.DefaultPasteHandler;
50 import org.simantics.db.layer0.adapter.impl.DefaultPasteImportAdvisor;
51 import org.simantics.db.layer0.util.ClipboardUtils;
52 import org.simantics.db.layer0.util.DomainProcessorState;
53 import org.simantics.db.layer0.util.Layer0Utils;
54 import org.simantics.db.layer0.util.ModelTransferableGraphSource;
55 import org.simantics.db.layer0.util.ModelTransferableGraphSourceRequest;
56 import org.simantics.db.layer0.util.SimanticsClipboard.Representation;
57 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
58 import org.simantics.db.layer0.util.SimanticsKeys;
59 import org.simantics.db.layer0.util.TransferableGraphConfiguration2;
60 import org.simantics.db.service.SerialisationSupport;
61 import org.simantics.graph.compiler.CompilationResult;
62 import org.simantics.graph.compiler.ExternalFileLoader;
63 import org.simantics.graph.compiler.GraphCompiler;
64 import org.simantics.graph.compiler.GraphCompilerPreferences;
65 import org.simantics.graph.compiler.ValidationMode;
66 import org.simantics.graph.db.TransferableGraphSource;
67 import org.simantics.graph.db.TransferableGraphs;
68 import org.simantics.graph.diff.Diff;
69 import org.simantics.graph.diff.TransferableGraphDelta1;
70 import org.simantics.graph.representation.Identity;
71 import org.simantics.graph.representation.Root;
72 import org.simantics.graph.representation.TransferableGraph1;
73 import org.simantics.graphfile.ontology.GraphFileResource;
74 import org.simantics.layer0.Layer0;
75 import org.simantics.ltk.ISource;
76 import org.simantics.ltk.Problem;
77 import org.simantics.modeling.ui.Activator;
78 import org.simantics.utils.datastructures.Pair;
79
80 /**
81  * @author Antti Villberg
82  */
83 public class CompilePGraphs implements ActionFactory {
84
85     @Override
86     public Runnable create(Object target) {
87         
88         if (!(target instanceof Resource))
89             return null;
90         
91         final Resource r = (Resource)target;
92
93         return new Runnable() {
94                 
95             private void uncheckedClose(Closeable closeable) {
96                 try {
97                     if (closeable != null)
98                         closeable.close();
99                 } catch (IOException e) {
100                     //ignore
101                 }
102             }
103                 
104             private File copyResource(URL url, File targetFile) throws IOException, FileNotFoundException {
105                 FileOutputStream os = null;
106                 InputStream is = null;
107                 try {
108                     if (targetFile.exists())
109                         targetFile.delete();
110
111                     is = url.openStream();
112                     int read;
113                     byte [] buffer = new byte [16384];
114                     os = new FileOutputStream (targetFile);
115                     while ((read = is.read (buffer)) != -1) {
116                         os.write(buffer, 0, read);
117                     }
118                     os.close ();
119                     is.close ();
120
121                     return targetFile;
122                 } finally {
123                     uncheckedClose(os);
124                     uncheckedClose(is);
125                 }
126             }
127                 
128             private File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException {
129                 String tmpDirStr = System.getProperty("java.io.tmpdir");
130                 if (tmpDirStr == null)
131                     throw new NullPointerException("java.io.tmpdir property is null");
132                 File tmpDir = new File(tmpDirStr);
133                 File libFile = new File(tmpDir, libName);
134                 return copyResource(libURL, libFile);
135             }
136                 
137                 private File url2file(URL url, String fileName) {
138                         if ("file".equals(url.getProtocol())) {
139                                 try {
140                                         File path = new File(URLDecoder.decode(url.getPath(), "UTF-8"));
141                                         return path;
142                                 } catch (UnsupportedEncodingException e) {
143                                         Logger.defaultLogError(e);
144                                 }
145                         } else if ("jar".equals(url.getProtocol())) {
146                                 try {
147                                         File libFile = extractLib(url, fileName);
148                                         return libFile;
149                                 } catch (FileNotFoundException e) {
150                                         Logger.defaultLogError(e);
151                                 } catch (IOException e) {
152                                         Logger.defaultLogError(e);
153                                 }
154                         } else {
155                                 System.err.println("Unsupported URL protocol '" + url + "' for FastLZ native library file '" + fileName);
156                         }       
157                         return null;
158                 }
159                         @Override
160                         public void run() {
161                                 
162                                 try {
163                                         
164                                 final Collection<ISource> sources = new ArrayList<ISource>();
165                                 Collection<TransferableGraph1> dependencies = new ArrayList<TransferableGraph1>();
166
167                                 for(Bundle b : Activator.getContext().getBundles()) {
168                                         URL tg = b.getEntry("/graph.tg");
169                                         if(tg == null) continue;
170                                         File f = url2file(FileLocator.resolve(tg), b.getSymbolicName());
171                                         dependencies.add(GraphCompiler.read(f));
172                                 }
173
174                                 final TransferableGraph1 thisOntology = Simantics.sync(new UniqueRead<TransferableGraph1>() {
175
176                                                 @Override
177                                                 public TransferableGraph1 perform(ReadGraph graph) throws DatabaseException {
178                                                         
179                                                         Layer0 L0 = Layer0.getInstance(graph);
180                                                         Resource parent = graph.getSingleObject(r, L0.PartOf);
181                                                         
182                                     CopyHandler ch = new DefaultCopyHandler(r) {
183                                         
184                                         protected TransferableGraphConfiguration2 createConfiguration(ReadGraph graph, boolean cut) throws DatabaseException {
185
186                                                 Map<Resource, ExtentStatus> preStatus = new HashMap<Resource, ExtentStatus>();
187                                                 preStatus.put(r, ExtentStatus.EXTERNAL);
188                                                 if(!parent.equals(graph.getRootLibrary()))
189                                                         preStatus.put(parent, ExtentStatus.EXTERNAL);
190                                                 
191                                                 return new TransferableGraphConfiguration2(null, Collections.emptyList(), preStatus, true, true);
192                                                 
193                                         }
194
195                                         protected TransferableGraphSource computeSource(ReadGraph graph, TransferableGraphConfiguration2 conf) throws DatabaseException {
196                                                 return graph.syncRequest(new ModelTransferableGraphSourceRequest(conf) {
197
198                                                         protected ModelTransferableGraphSource getSource(ReadGraph graph, TransferableGraphConfiguration2 configuration, DomainProcessorState state, File otherStatementsFile, File valueFile) throws DatabaseException {
199                                                         return new ModelTransferableGraphSource(graph, configuration, state, otherStatementsFile, valueFile) {
200
201                                                                         @Override
202                                                                         protected Identity getRootIdentity(DomainProcessorState state, SerialisationSupport support, Resource rootLibrary) throws DatabaseException {
203                                                                                 return new Identity(state.ids.get(support.getTransientId(rootLibrary)), new Root("", ""));
204                                                                         }
205
206                                                         };
207                                                         }
208
209                                                 });
210                                         }
211                                         
212                                     };
213                                     SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();
214                                     ch.copyToClipboard(graph, clipboard);
215                                     for (Set<Representation> object : clipboard.getContents()) {
216                                         TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
217                                         if(tg != null) return tg;
218                                     }
219                                                         return null;
220                                                 }
221                                         
222                                 });
223
224                                 dependencies.add(thisOntology);
225                                 
226                                         Simantics.sync(new ReadRequest() {
227
228                                                 @Override
229                                                 public void run(ReadGraph graph) throws DatabaseException {
230                                                         Layer0 L0 = Layer0.getInstance(graph);
231                                                         for(Resource file : graph.syncRequest(new ObjectsWithType(r, L0.ConsistsOf, L0.PGraph))) {
232                                                                 
233                                                                 final String src = graph.getRelatedValue(file, L0.PGraph_definition, Bindings.STRING);
234
235                                                                 final ByteArrayInputStream baos = new ByteArrayInputStream(src.getBytes()); 
236                                                         
237                                                         sources.add(new ISource() {
238                                                                         
239                                                                         @Override
240                                                                         public int startPos() {
241                                                                                 return 0;
242                                                                         }
243                                                                         
244                                                                         @Override
245                                                                         public int startLine() {
246                                                                                 return 0;
247                                                                         }
248                                                                         
249                                                                         @Override
250                                                                         public InputStream open() throws IOException {
251                                                                                 return baos;
252                                                                         }
253                                                                         
254                                                                         @Override
255                                                                         public int length() throws IOException {
256                                                                                 return src.length();
257                                                                         }
258                                                                         
259                                                                         @Override
260                                                                         public String getName() {
261                                                                                 return "Source";
262                                                                         }
263                                                                         
264                                                                 });
265                                                                 
266                                                         }
267                                                 }
268                                                 
269                                         });
270                                 
271                                 final StringBuilder errorStringBuilder = new StringBuilder();
272                                 GraphCompilerPreferences prefs = new GraphCompilerPreferences();
273                                 prefs.validate = true;
274                                 prefs.validateRelationRestrictions = ValidationMode.ERROR;
275                                 prefs.validateResourceHasType = ValidationMode.IGNORE;
276                                 
277                                 final CompilationResult result = Simantics.sync(new UniqueRead<CompilationResult>() {
278
279                                                 @Override
280                                                 public CompilationResult perform(ReadGraph graph) throws DatabaseException {
281                                                         
282                                                         final Resource root = graph.syncRequest(new IndexRoot(r));
283                                                         final String baseURI = graph.getURI(root);
284
285                                                         ExternalFileLoader fileLoader = new ExternalFileLoader() {
286                                                                 @Override
287                                                                 public byte[] load(String fileName) throws IOException {
288                                                                         try {
289                                                                                 GraphFileResource GF = GraphFileResource.getInstance(graph);
290                                                                                 Resource file = graph.getResource(baseURI + "/" + fileName);
291                                                                                 return graph.getRelatedValue(file, GF.HasFiledata, Bindings.BYTE_ARRAY);
292                                                                         } catch (DatabaseException e) {
293                                                                                 throw new IOException(e);
294                                                                         }
295                                                                 }
296                                                         };
297
298                                                         return GraphCompiler.compile("1.1", sources, dependencies, fileLoader, prefs);
299                                                         
300                                                 }
301                                         
302                                 });
303                                 
304                                 for(Problem problem : result.getErrors())
305                                         errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
306                                 for(Problem problem : result.getWarnings())
307                                         errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
308                                 
309                                 if(!result.getErrors().isEmpty() || !result.getWarnings().isEmpty()) {
310
311                                         class ErrorMessageDialog extends MessageDialog {
312
313                                                 public ErrorMessageDialog(Shell shell) {
314                                                         super(shell, 
315                                                                         "Unsatisfied dependencies", null, 
316                                                                         "The following dependencies were missing. Please import the dependencies and try again.", 
317                                                                         MessageDialog.ERROR, new String[] { "Continue" }, 0);
318                                                 }
319
320                                                 @Override
321                                                 protected Control createCustomArea(Composite composite) {
322                                                         
323                                                         GridLayoutFactory.fillDefaults().applyTo(composite);
324                                                         
325                                                         org.eclipse.swt.widgets.List list = new org.eclipse.swt.widgets.List(composite, SWT.BORDER | SWT.READ_ONLY);
326                                                         GridDataFactory.fillDefaults().grab(true, true).applyTo(list);
327                                                 for(Problem problem : result.getErrors())
328                                                         list.add(problem.getLocation() + ": " + problem.getDescription() + "\n");
329                                                 for(Problem problem : result.getWarnings())
330                                                         list.add(problem.getLocation() + ": " + problem.getDescription() + "\n");
331
332                                                         return composite;
333                                                         
334                                                 }
335
336                                         }
337
338                                         ErrorMessageDialog md = new ErrorMessageDialog(Display.getCurrent().getActiveShell());
339                                         md.open();
340
341                                         return;
342                                 }
343                                 
344                                 
345                                 final Pair<TransferableGraph1, long[]> existing = Simantics.sync(new UniqueRead<Pair<TransferableGraph1, long[]>>() {
346
347                                                 @Override
348                                                 public Pair<TransferableGraph1, long[]> perform(ReadGraph graph) throws DatabaseException {
349                                                         Layer0 L0 = Layer0.getInstance(graph);
350                                                         TransferableGraph1 tg = graph.getPossibleRelatedValue(r, L0.SharedOntology_tg, Bindings.getBindingUnchecked( TransferableGraph1.class ));
351                                                         if(tg == null) return null;
352                                                         long[] tgResources = graph.getPossibleRelatedValue(r, L0.SharedOntology_tgResources, Bindings.LONG_ARRAY);
353                                                         if(tgResources == null) return null;
354                                                         return Pair.make(tg,  tgResources);
355                                                 }
356                                         
357                                 });
358                                 
359                                 if(existing != null) {
360                                         
361                             try {
362                                 
363                                                         Simantics.sync(new WriteRequest() {
364                                                                 
365                                                                 @Override
366                                                                 public void perform(WriteGraph graph) throws DatabaseException {
367
368                                                     TransferableGraphDelta1 delta = new Diff(existing.first, result.getGraph()).diff();
369                                                 long[] resourceArray = TransferableGraphs.applyDelta(graph, existing.second, delta);
370
371                                                                         Layer0 L0 = Layer0.getInstance(graph);
372                                                                         graph.claimLiteral(r, L0.SharedOntology_tg, result.getGraph(), Bindings.getBindingUnchecked( TransferableGraph1.class ));
373                                                                         graph.claimLiteral(r, L0.SharedOntology_tgResources, L0.ResourceIdArray, resourceArray, Bindings.LONG_ARRAY);
374                                                                         
375                                                         Layer0Utils.addCommentMetadata(graph, "Compiled ontology " + graph.getURI(r));
376
377                                                                 }
378                                                                 
379                                                         });
380
381                             } catch (Throwable t) {
382                                 throw new PlatformException(t);
383                             } finally {
384                                 endTransaction();
385                             }
386                                         
387                                 } else {
388                                 
389                                         final DefaultPasteImportAdvisor advisor = new DefaultPasteImportAdvisor(r);
390                                         
391                                         DefaultPasteHandler.defaultExecute(result.getGraph(), r, advisor);
392                                         
393                                                 Simantics.sync(new WriteRequest() {
394         
395                                                         @Override
396                                                         public void perform(WriteGraph graph) throws DatabaseException {
397         
398                                                                 Layer0 L0 = Layer0.getInstance(graph);
399                                                                 graph.claimLiteral(r, L0.SharedOntology_tg, result.getGraph(), Bindings.getBindingUnchecked( TransferableGraph1.class ));
400                                                                 graph.claimLiteral(r, L0.SharedOntology_tgResources, L0.ResourceIdArray, advisor.getResourceIds(), Bindings.LONG_ARRAY);
401
402                                                 Layer0Utils.addCommentMetadata(graph, "Compiled ontology " + graph.getURI(r));
403
404                                                         }
405                                                         
406                                                 });
407                                                 
408                                 }
409                                         
410                                 } catch (Exception e) {
411                                         Logger.defaultLogError(e);
412                                 }
413                                 
414                         }
415                 
416         };
417         
418     }
419
420 }