package org.simantics.modeling.ui.actions; import static org.simantics.db.common.utils.Transaction.endTransaction; import java.io.ByteArrayInputStream; import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.FileLocator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.osgi.framework.Bundle; import org.simantics.PlatformException; import org.simantics.Simantics; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.common.utils.Logger; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.adapter.ActionFactory; import org.simantics.db.layer0.adapter.CopyHandler; import org.simantics.db.layer0.adapter.SubgraphExtent.ExtentStatus; import org.simantics.db.layer0.adapter.impl.DefaultCopyHandler; import org.simantics.db.layer0.adapter.impl.DefaultPasteHandler; import org.simantics.db.layer0.adapter.impl.DefaultPasteImportAdvisor; import org.simantics.db.layer0.util.ClipboardUtils; import org.simantics.db.layer0.util.DomainProcessorState; import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.layer0.util.ModelTransferableGraphSource; import org.simantics.db.layer0.util.ModelTransferableGraphSourceRequest; import org.simantics.db.layer0.util.SimanticsClipboard.Representation; import org.simantics.db.layer0.util.SimanticsClipboardImpl; import org.simantics.db.layer0.util.SimanticsKeys; import org.simantics.db.layer0.util.TransferableGraphConfiguration2; import org.simantics.db.service.SerialisationSupport; import org.simantics.graph.compiler.CompilationResult; import org.simantics.graph.compiler.GraphCompiler; import org.simantics.graph.compiler.GraphCompilerPreferences; import org.simantics.graph.compiler.ValidationMode; import org.simantics.graph.db.TransferableGraphSource; import org.simantics.graph.db.TransferableGraphs; import org.simantics.graph.diff.Diff; import org.simantics.graph.diff.TransferableGraphDelta1; import org.simantics.graph.representation.Identity; import org.simantics.graph.representation.Root; import org.simantics.graph.representation.TransferableGraph1; import org.simantics.layer0.Layer0; import org.simantics.ltk.ISource; import org.simantics.ltk.Problem; import org.simantics.modeling.ui.Activator; import org.simantics.utils.datastructures.Pair; /** * @author Antti Villberg */ public class CompilePGraphs implements ActionFactory { @Override public Runnable create(Object target) { if (!(target instanceof Resource)) return null; final Resource r = (Resource)target; return new Runnable() { private void uncheckedClose(Closeable closeable) { try { if (closeable != null) closeable.close(); } catch (IOException e) { //ignore } } private File copyResource(URL url, File targetFile) throws IOException, FileNotFoundException { FileOutputStream os = null; InputStream is = null; try { if (targetFile.exists()) targetFile.delete(); is = url.openStream(); int read; byte [] buffer = new byte [16384]; os = new FileOutputStream (targetFile); while ((read = is.read (buffer)) != -1) { os.write(buffer, 0, read); } os.close (); is.close (); return targetFile; } finally { uncheckedClose(os); uncheckedClose(is); } } private File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException { String tmpDirStr = System.getProperty("java.io.tmpdir"); if (tmpDirStr == null) throw new NullPointerException("java.io.tmpdir property is null"); File tmpDir = new File(tmpDirStr); File libFile = new File(tmpDir, libName); return copyResource(libURL, libFile); } private File url2file(URL url, String fileName) { if ("file".equals(url.getProtocol())) { try { File path = new File(URLDecoder.decode(url.getPath(), "UTF-8")); return path; } catch (UnsupportedEncodingException e) { Logger.defaultLogError(e); } } else if ("jar".equals(url.getProtocol())) { try { File libFile = extractLib(url, fileName); return libFile; } catch (FileNotFoundException e) { Logger.defaultLogError(e); } catch (IOException e) { Logger.defaultLogError(e); } } else { System.err.println("Unsupported URL protocol '" + url + "' for FastLZ native library file '" + fileName); } return null; } @Override public void run() { try { final Collection sources = new ArrayList(); Collection dependencies = new ArrayList(); for(Bundle b : Activator.getContext().getBundles()) { URL tg = b.getEntry("/graph.tg"); if(tg == null) continue; File f = url2file(FileLocator.resolve(tg), b.getSymbolicName()); dependencies.add(GraphCompiler.read(f)); } final TransferableGraph1 thisOntology = Simantics.sync(new UniqueRead() { @Override public TransferableGraph1 perform(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Resource parent = graph.getSingleObject(r, L0.PartOf); CopyHandler ch = new DefaultCopyHandler(r) { protected TransferableGraphConfiguration2 createConfiguration(ReadGraph graph, boolean cut) throws DatabaseException { Map preStatus = new HashMap(); preStatus.put(r, ExtentStatus.EXTERNAL); if(!parent.equals(graph.getRootLibrary())) preStatus.put(parent, ExtentStatus.EXTERNAL); return new TransferableGraphConfiguration2(null, Collections.emptyList(), preStatus, true, true); } protected TransferableGraphSource computeSource(ReadGraph graph, TransferableGraphConfiguration2 conf) throws DatabaseException { return graph.syncRequest(new ModelTransferableGraphSourceRequest(conf) { protected ModelTransferableGraphSource getSource(ReadGraph graph, TransferableGraphConfiguration2 configuration, DomainProcessorState state, File otherStatementsFile, File valueFile) throws DatabaseException { return new ModelTransferableGraphSource(graph, configuration, state, otherStatementsFile, valueFile) { @Override protected Identity getRootIdentity(DomainProcessorState state, SerialisationSupport support, Resource rootLibrary) throws DatabaseException { return new Identity(state.ids.get(support.getTransientId(rootLibrary)), new Root("", "")); } }; } }); } }; SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl(); ch.copyToClipboard(graph, clipboard); for (Set object : clipboard.getContents()) { TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH); if(tg != null) return tg; } return null; } }); dependencies.add(thisOntology); Simantics.sync(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); for(Resource file : graph.syncRequest(new ObjectsWithType(r, L0.ConsistsOf, L0.PGraph))) { final String src = graph.getRelatedValue(file, L0.PGraph_definition, Bindings.STRING); final ByteArrayInputStream baos = new ByteArrayInputStream(src.getBytes()); sources.add(new ISource() { @Override public int startPos() { return 0; } @Override public int startLine() { return 0; } @Override public InputStream open() throws IOException { return baos; } @Override public int length() throws IOException { return src.length(); } @Override public String getName() { return "Source"; } }); } } }); final StringBuilder errorStringBuilder = new StringBuilder(); GraphCompilerPreferences prefs = new GraphCompilerPreferences(); prefs.validate = true; prefs.validateRelationRestrictions = ValidationMode.ERROR; prefs.validateResourceHasType = ValidationMode.IGNORE; final CompilationResult result = GraphCompiler.compile("1.1", sources, dependencies, null, prefs); for(Problem problem : result.getErrors()) errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n"); for(Problem problem : result.getWarnings()) errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n"); if(!result.getErrors().isEmpty() || !result.getWarnings().isEmpty()) { class ErrorMessageDialog extends MessageDialog { public ErrorMessageDialog(Shell shell) { super(shell, "Unsatisfied dependencies", null, "The following dependencies were missing. Please import the dependencies and try again.", MessageDialog.ERROR, new String[] { "Continue" }, 0); } @Override protected Control createCustomArea(Composite composite) { GridLayoutFactory.fillDefaults().applyTo(composite); org.eclipse.swt.widgets.List list = new org.eclipse.swt.widgets.List(composite, SWT.BORDER | SWT.READ_ONLY); GridDataFactory.fillDefaults().grab(true, true).applyTo(list); for(Problem problem : result.getErrors()) list.add(problem.getLocation() + ": " + problem.getDescription() + "\n"); for(Problem problem : result.getWarnings()) list.add(problem.getLocation() + ": " + problem.getDescription() + "\n"); return composite; } } ErrorMessageDialog md = new ErrorMessageDialog(Display.getCurrent().getActiveShell()); md.open(); return; } final Pair existing = Simantics.sync(new UniqueRead>() { @Override public Pair perform(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); TransferableGraph1 tg = graph.getPossibleRelatedValue(r, L0.SharedOntology_tg, Bindings.getBindingUnchecked( TransferableGraph1.class )); if(tg == null) return null; long[] tgResources = graph.getPossibleRelatedValue(r, L0.SharedOntology_tgResources, Bindings.LONG_ARRAY); if(tgResources == null) return null; return Pair.make(tg, tgResources); } }); if(existing != null) { try { Simantics.sync(new WriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { TransferableGraphDelta1 delta = new Diff(existing.first, result.getGraph()).diff(); long[] resourceArray = TransferableGraphs.applyDelta(graph, existing.second, delta); Layer0 L0 = Layer0.getInstance(graph); graph.claimLiteral(r, L0.SharedOntology_tg, result.getGraph(), Bindings.getBindingUnchecked( TransferableGraph1.class )); graph.claimLiteral(r, L0.SharedOntology_tgResources, L0.ResourceIdArray, resourceArray, Bindings.LONG_ARRAY); Layer0Utils.addCommentMetadata(graph, "Compiled ontology " + graph.getURI(r)); } }); } catch (Throwable t) { throw new PlatformException(t); } finally { endTransaction(); } } else { final DefaultPasteImportAdvisor advisor = new DefaultPasteImportAdvisor(r); DefaultPasteHandler.defaultExecute(result.getGraph(), r, advisor); Simantics.sync(new WriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); graph.claimLiteral(r, L0.SharedOntology_tg, result.getGraph(), Bindings.getBindingUnchecked( TransferableGraph1.class )); graph.claimLiteral(r, L0.SharedOntology_tgResources, L0.ResourceIdArray, advisor.getResourceIds(), Bindings.LONG_ARRAY); Layer0Utils.addCommentMetadata(graph, "Compiled ontology " + graph.getURI(r)); } }); } } catch (Exception e) { Logger.defaultLogError(e); } } }; } }