1 package org.simantics.modeling;
3 import java.io.ByteArrayInputStream;
5 import java.io.FileNotFoundException;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.UnsupportedEncodingException;
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;
18 import org.eclipse.core.runtime.FileLocator;
19 import org.osgi.framework.Bundle;
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.db.TransferableGraphException;
53 import org.simantics.graph.db.TransferableGraphSource;
54 import org.simantics.graph.db.TransferableGraphs;
55 import org.simantics.graph.diff.Diff;
56 import org.simantics.graph.diff.TransferableGraphDelta1;
57 import org.simantics.graph.representation.Identity;
58 import org.simantics.graph.representation.Root;
59 import org.simantics.graph.representation.TransferableGraph1;
60 import org.simantics.graphfile.ontology.GraphFileResource;
61 import org.simantics.layer0.Layer0;
62 import org.simantics.ltk.ISource;
63 import org.simantics.ltk.Problem;
64 import org.simantics.modeling.internal.Activator;
65 import org.simantics.utils.FileUtils;
66 import org.simantics.utils.datastructures.Pair;
69 * @author Antti Villberg
71 public class CompilePGraphs {
73 public static interface UserAgent {
74 void reportProblems(CompilationResult result);
78 * <code>Simantics/PGraph#compilePGraphs</code> SCL API.
82 * @throws DatabaseException
84 public static void compilePGraphs(Resource r) throws IOException, DatabaseException {
85 compilePGraphs(r, null);
88 public static void compilePGraphs(Resource r, UserAgent userAgent) throws IOException, DatabaseException {
89 final Collection<ISource> sources = new ArrayList<>();
90 Collection<TransferableGraph1> dependencies = new ArrayList<>();
92 for (Bundle b : Activator.getContext().getBundles()) {
93 URL tg = b.getEntry("/graph.tg");
94 if (tg == null) continue;
95 File f = url2file(FileLocator.resolve(tg), b.getSymbolicName());
97 dependencies.add(GraphCompiler.read(f));
98 } catch (Exception e) {
99 throw new IOException("Failed to read compiled transferable graph as dependency: " + f, e);
103 final TransferableGraph1 thisOntology = Simantics.sync(new UniqueRead<TransferableGraph1>() {
106 public TransferableGraph1 perform(ReadGraph graph) throws DatabaseException {
107 Layer0 L0 = Layer0.getInstance(graph);
108 Resource parent = graph.getSingleObject(r, L0.PartOf);
110 CopyHandler ch = new DefaultCopyHandler(r) {
111 protected TransferableGraphConfiguration2 createConfiguration(ReadGraph graph, boolean cut) throws DatabaseException {
112 Map<Resource, ExtentStatus> preStatus = new HashMap<>();
113 preStatus.put(r, ExtentStatus.EXTERNAL);
114 if (!parent.equals(graph.getRootLibrary()))
115 preStatus.put(parent, ExtentStatus.EXTERNAL);
116 return new TransferableGraphConfiguration2(null, Collections.emptyList(), preStatus, true, true);
119 protected TransferableGraphSource computeSource(ReadGraph graph, TransferableGraphConfiguration2 conf) throws DatabaseException {
120 return graph.syncRequest(new ModelTransferableGraphSourceRequest(conf) {
121 protected ModelTransferableGraphSource getSource(ReadGraph graph, TransferableGraphConfiguration2 configuration, DomainProcessorState state, File otherStatementsFile, File valueFile) throws DatabaseException {
122 return new ModelTransferableGraphSource(graph, configuration, state, otherStatementsFile, valueFile) {
124 protected Identity getRootIdentity(DomainProcessorState state, SerialisationSupport support, Resource rootLibrary) throws DatabaseException {
125 return new Identity(state.ids.get(support.getTransientId(rootLibrary)), new Root("", ""));
133 SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();
134 ch.copyToClipboard(graph, clipboard);
135 for (Set<Representation> object : clipboard.getContents()) {
136 TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
145 if (thisOntology == null)
146 throw new DatabaseException("Failed to dump the containing ontology of " + r + " into TransferableGraph1");
148 dependencies.add(thisOntology);
150 Simantics.sync(new ReadRequest() {
152 public void run(ReadGraph graph) throws DatabaseException {
153 Layer0 L0 = Layer0.getInstance(graph);
154 for (Resource file : graph.syncRequest(new ObjectsWithType(r, L0.ConsistsOf, L0.PGraph))) {
155 String src = graph.getRelatedValue(file, L0.PGraph_definition, Bindings.STRING);
156 sources.add(new StringSource(src));
161 GraphCompilerPreferences prefs = new GraphCompilerPreferences();
162 prefs.validate = true;
163 prefs.validateRelationRestrictions = ValidationMode.ERROR;
164 prefs.validateResourceHasType = ValidationMode.IGNORE;
165 final CompilationResult result = Simantics.sync(new UniqueRead<CompilationResult>() {
167 public CompilationResult perform(ReadGraph graph) throws DatabaseException {
168 final Resource root = graph.syncRequest(new IndexRoot(r));
169 final String baseURI = graph.getURI(root);
171 GraphFileResource GF = GraphFileResource.getInstance(graph);
172 ExternalFileLoader fileLoader = fileName -> {
174 Resource file = graph.getResource(baseURI + "/" + fileName);
175 return graph.getRelatedValue(file, GF.HasFiledata, Bindings.BYTE_ARRAY);
176 } catch (DatabaseException e) {
177 throw new IOException(e);
181 return GraphCompiler.compile("1.1", sources, dependencies, fileLoader, prefs);
185 if (!result.getErrors().isEmpty() || !result.getWarnings().isEmpty()) {
186 if (userAgent != null) {
187 userAgent.reportProblems(result);
190 StringBuilder error = new StringBuilder();
191 for (Problem problem : result.getErrors())
192 error.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
193 for (Problem problem : result.getWarnings())
194 error.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
195 throw new DatabaseException(error.toString());
199 final Pair<TransferableGraph1, long[]> existing = Simantics.sync(new UniqueRead<Pair<TransferableGraph1, long[]>>() {
201 public Pair<TransferableGraph1, long[]> perform(ReadGraph graph) throws DatabaseException {
202 Layer0 L0 = Layer0.getInstance(graph);
203 TransferableGraph1 tg = graph.getPossibleRelatedValue(r, L0.SharedOntology_tg, Bindings.getBindingUnchecked( TransferableGraph1.class ));
204 if(tg == null) return null;
205 long[] tgResources = graph.getPossibleRelatedValue(r, L0.SharedOntology_tgResources, Bindings.LONG_ARRAY);
206 if(tgResources == null) return null;
207 return Pair.make(tg, tgResources);
211 if (existing != null) {
212 Simantics.sync(new WriteRequest() {
214 public void perform(WriteGraph graph) throws DatabaseException {
215 TransferableGraphDelta1 delta = new Diff(existing.first, result.getGraph()).diff();
216 long[] resourceArray = TransferableGraphs.applyDelta(graph, existing.second, delta);
218 Layer0 L0 = Layer0.getInstance(graph);
219 graph.claimLiteral(r, L0.SharedOntology_tg, result.getGraph(), Bindings.getBindingUnchecked( TransferableGraph1.class ));
220 graph.claimLiteral(r, L0.SharedOntology_tgResources, L0.ResourceIdArray, resourceArray, Bindings.LONG_ARRAY);
222 Layer0Utils.addCommentMetadata(graph, "Compiled ontology " + graph.getURI(r));
226 final DefaultPasteImportAdvisor advisor = new DefaultPasteImportAdvisor(r);
228 DefaultPasteHandler.defaultExecute(result.getGraph(), r, advisor);
229 } catch (TransferableGraphException e) {
230 // TODO: defaultExecute never actually throws this exception!
231 throw new DatabaseException(e);
234 Simantics.sync(new WriteRequest() {
236 public void perform(WriteGraph graph) throws DatabaseException {
237 Layer0 L0 = Layer0.getInstance(graph);
238 graph.claimLiteral(r, L0.SharedOntology_tg, result.getGraph(), Bindings.getBindingUnchecked( TransferableGraph1.class ));
239 graph.claimLiteral(r, L0.SharedOntology_tgResources, L0.ResourceIdArray, advisor.getResourceIds(), Bindings.LONG_ARRAY);
241 Layer0Utils.addCommentMetadata(graph, "Compiled ontology " + graph.getURI(r));
247 private static File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException {
248 String tmpDirStr = System.getProperty("java.io.tmpdir");
249 if (tmpDirStr == null)
250 throw new NullPointerException("java.io.tmpdir property is null");
251 File tmpDir = new File(tmpDirStr);
252 File libFile = new File(tmpDir, libName);
253 return FileUtils.copyResource(libURL, libFile, false);
256 private static File url2file(URL url, String fileName) {
257 if ("file".equals(url.getProtocol())) {
259 File path = new File(URLDecoder.decode(url.getPath(), "UTF-8"));
261 } catch (UnsupportedEncodingException e) {
262 Logger.defaultLogError(e);
264 } else if ("jar".equals(url.getProtocol())) {
266 File libFile = extractLib(url, fileName);
268 } catch (FileNotFoundException e) {
269 Logger.defaultLogError(e);
270 } catch (IOException e) {
271 Logger.defaultLogError(e);
274 System.err.println("Unsupported URL protocol '" + url + "' for FastLZ native library file '" + fileName);
279 private static class StringSource implements ISource {
281 private ByteArrayInputStream baos;
283 public StringSource(String s) {
285 this.baos = new ByteArrayInputStream(src.getBytes());
289 public int startPos() {
294 public int startLine() {
299 public InputStream open() throws IOException {
304 public int length() throws IOException {
309 public String getName() {