-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.project.management;\r
-\r
-import java.io.BufferedInputStream;\r
-import java.io.Closeable;\r
-import java.io.DataInput;\r
-import java.io.DataInputStream;\r
-import java.io.File;\r
-import java.io.FileNotFoundException;\r
-import java.io.FileOutputStream;\r
-import java.io.FilenameFilter;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.UnsupportedEncodingException;\r
-import java.net.URL;\r
-import java.net.URLDecoder;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Enumeration;\r
-import java.util.Map.Entry;\r
-import java.util.jar.Attributes;\r
-import java.util.jar.Manifest;\r
-\r
-import org.eclipse.core.internal.runtime.PlatformActivator;\r
-import org.eclipse.core.runtime.FileLocator;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.eclipse.equinox.p2.metadata.IVersionedId;\r
-import org.eclipse.equinox.p2.metadata.Version;\r
-import org.eclipse.equinox.p2.metadata.VersionedId;\r
-import org.osgi.framework.Bundle;\r
-import org.simantics.databoard.adapter.AdaptException;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.binding.mutable.Variant;\r
-import org.simantics.databoard.container.DataContainer;\r
-import org.simantics.databoard.container.DataContainers;\r
-import org.simantics.databoard.serialization.SerializationException;\r
-import org.simantics.db.common.utils.Logger;\r
-import org.simantics.graph.compiler.CompilationResult;\r
-import org.simantics.graph.compiler.GraphCompiler;\r
-import org.simantics.graph.compiler.GraphCompilerPreferences;\r
-import org.simantics.graph.compiler.ValidationMode;\r
-import org.simantics.graph.representation.TransferableGraph1;\r
-import org.simantics.ltk.FileSource;\r
-import org.simantics.ltk.ISource;\r
-import org.simantics.ltk.Problem;\r
-import org.simantics.scl.reflection.OntologyVersions;\r
-\r
-/**\r
- * This class contains utilities for managing bundles in a active platform. \r
- *\r
- */\r
-@SuppressWarnings("restriction")\r
-public class PlatformUtil {\r
-\r
- \r
- /**\r
- * Get all bundles in the platform.\r
- * \r
- * @return\r
- */\r
- public static Bundle[] getBundles() {\r
- return PlatformActivator.getContext().getBundles();\r
- }\r
- \r
- /**\r
- * Get the manifest file of a bundle\r
- * \r
- * @param bundle bundle\r
- * @return manifest or <tt>null</tt> if doesn't not exist\r
- * @throws IOException \r
- */\r
- public static Manifest getManifest(Bundle bundle) throws IOException {\r
- URL url = bundle.getEntry("META-INF/MANIFEST.MF");\r
- if (url==null) return null;\r
- InputStream is = url.openStream();\r
- try {\r
- return new Manifest(is); \r
- } finally {\r
- is.close();\r
- }\r
- }\r
- \r
- /**\r
- * Get the manifest file of a bundle\r
- * \r
- * @param bundle bundle\r
- * @return manifest or <tt>null</tt> if doesn't not exist\r
- * @throws IOException \r
- */\r
- public static Manifest getSimanticsManifest(Bundle bundle) throws IOException {\r
- URL url = bundle.getEntry("META-INF/SIMANTICS.MF");\r
- if (url==null) return null;\r
- InputStream is = url.openStream();\r
- try {\r
- return new Manifest(is); \r
- } finally {\r
- is.close();\r
- }\r
- }\r
- \r
- /**\r
- * Get a list (BundleIds) of all user installable units. These are the \r
- * top-level items that are visible for the end-user. \r
- * The list is acquired from the bundles of the current application. \r
- * \r
- * @param list of simantics features URIs\r
- * @throws IOException \r
- */\r
- public static void getUserInstallableUnits(Collection<String> list) \r
- throws IOException \r
- {\r
- for (Bundle bundle : getBundles()) {\r
- Manifest manifest = getSimanticsManifest(bundle);\r
- if (manifest==null) continue;\r
- Attributes attributes = manifest.getMainAttributes();\r
- for (Entry<Object, Object> entry2 : attributes.entrySet()) {\r
- Object key = entry2.getKey();\r
- if (key.toString().contains("Installable-Unit")) {\r
- String bid = entry2.getValue().toString(); \r
- list.add( bid );\r
- }\r
- }\r
- } \r
- }\r
- \r
- /**\r
- * Get all transferable graphs in the platform\r
- * \r
- * @param result collection to be filled with transferable graph info \r
- */\r
- public static void getPlatformTGInfos(Collection<TGInfo> result) {\r
- for (Bundle bundle : getBundles()) {\r
- Enumeration<URL> e = bundle.findEntries("graphs/", "*.tg", false);\r
- if (e==null) continue;\r
- while (e.hasMoreElements()) {\r
- org.osgi.framework.Version osgiVersion = bundle.getVersion();\r
- Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());\r
- String id = bundle.getSymbolicName();\r
- \r
- TGInfo info = new TGInfo();\r
- info.location = e.nextElement();\r
- info.bundle = bundle;\r
- info.vid = new VersionedId(id, p2Version);\r
- result.add( info );\r
- }\r
- }\r
- }\r
-\r
- private static void uncheckedClose(Closeable closeable) {\r
- try {\r
- if (closeable != null)\r
- closeable.close();\r
- } catch (IOException e) {\r
- //ignore\r
- }\r
- }\r
- \r
- private static File copyResource(URL url, File targetFile) throws IOException, FileNotFoundException {\r
- FileOutputStream os = null;\r
- InputStream is = null;\r
- try {\r
- if (targetFile.exists())\r
- targetFile.delete();\r
-\r
- is = url.openStream();\r
- int read;\r
- byte [] buffer = new byte [16384];\r
- os = new FileOutputStream (targetFile);\r
- while ((read = is.read (buffer)) != -1) {\r
- os.write(buffer, 0, read);\r
- }\r
- os.close ();\r
- is.close ();\r
-\r
- return targetFile;\r
- } finally {\r
- uncheckedClose(os);\r
- uncheckedClose(is);\r
- }\r
- }\r
- \r
- private static File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException {\r
- String tmpDirStr = System.getProperty("java.io.tmpdir");\r
- if (tmpDirStr == null)\r
- throw new NullPointerException("java.io.tmpdir property is null");\r
- File tmpDir = new File(tmpDirStr);\r
- File libFile = new File(tmpDir, libName);\r
- return copyResource(libURL, libFile);\r
- }\r
- \r
- private static File url2file(URL url, String fileName) {\r
- if ("file".equals(url.getProtocol())) {\r
- try {\r
- File path = new File(URLDecoder.decode(url.getPath(), "UTF-8"));\r
- return path;\r
- } catch (UnsupportedEncodingException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- } else if ("jar".equals(url.getProtocol())) {\r
- try {\r
- File libFile = extractLib(url, fileName);\r
- return libFile;\r
- } catch (FileNotFoundException e) {\r
- Logger.defaultLogError(e);\r
- } catch (IOException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- } else {\r
- System.err.println("Unsupported URL protocol '" + url + "' for FastLZ native library file '" + fileName);\r
- } \r
- return null;\r
- }\r
- \r
- public static void compile(Bundle b) throws Exception {\r
- \r
- Collection<ISource> sources = new ArrayList<ISource>();\r
- Collection<TransferableGraph1> dependencies = new ArrayList<TransferableGraph1>();\r
- \r
- for (Bundle b2 : getBundles()) {\r
- if(b.equals(b2)) continue;\r
- URL url = b2.getEntry("graph.tg");\r
- if (url==null) continue;\r
- File graphFile = url2file(FileLocator.resolve(b2.getEntry("/graph.tg")), b2.toString());\r
- dependencies.add(GraphCompiler.read(graphFile));\r
- }\r
- \r
- File bundleFile = FileLocator.getBundleFile(b);\r
- if(bundleFile.isDirectory()) {\r
- File folder = new File(bundleFile, "dynamicGraph");\r
- for(File f : folder.listFiles(new FilenameFilter() {\r
- \r
- @Override\r
- public boolean accept(File dir, String name) {\r
- return name.endsWith(".pgraph");\r
- }\r
- \r
- })) {\r
- sources.add(new FileSource(f));\r
- }\r
- } \r
- \r
-// System.out.println("source is " + tmpFile.getAbsolutePath());\r
- \r
- final StringBuilder errorStringBuilder = new StringBuilder();\r
- GraphCompilerPreferences prefs = new GraphCompilerPreferences();\r
- prefs.validate = true;\r
- prefs.validateRelationRestrictions = ValidationMode.ERROR;\r
- prefs.validateResourceHasType = ValidationMode.ERROR;\r
- String currentLayer0Version = OntologyVersions.getInstance().currentOntologyVersion("http://www.simantics.org/Layer0-0.0");\r
- CompilationResult result = GraphCompiler.compile(currentLayer0Version, sources, dependencies, null, prefs);\r
- \r
- for(Problem problem : result.getErrors())\r
- errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");\r
- for(Problem problem : result.getWarnings())\r
- errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");\r
-\r
- if(errorStringBuilder.length() > 0) {\r
- Logger.defaultLogError(errorStringBuilder.toString());\r
- } else {\r
- DataContainers.writeFile(new File(bundleFile, "graph.tg"), \r
- new DataContainer("graph", 1, new Variant(TransferableGraph1.BINDING, result.getGraph())));\r
- }\r
- \r
- }\r
- \r
- /**\r
- * Compile all dynamic ontologies in the Platform\r
- * \r
- * @param collection\r
- * @throws IOException\r
- */\r
- public static void compileAllDynamicOntologies() {\r
- for (Bundle bundle : getBundles()) {\r
- if(bundle.getEntry("dynamicGraph") != null) {\r
- try {\r
- File bundleFile = FileLocator.getBundleFile(bundle);\r
- if(bundleFile.isDirectory()) {\r
- File tg = new File(bundleFile, "graph.tg");\r
- long tgLastModified = tg.lastModified();\r
- File folder = new File(bundleFile, "dynamicGraph");\r
- for(File f : folder.listFiles()) {\r
- if(f.isFile() && f.getName().endsWith(".pgraph") && f.lastModified() > tgLastModified) {\r
- compile(bundle);\r
- break;\r
- }\r
- }\r
- }\r
- } catch (Throwable e) {\r
- Logger.defaultLogError(e);\r
- }\r
- }\r
- }\r
- }\r
- \r
- /**\r
- * Get all graphs in the Platform\r
- * \r
- * @param collection\r
- * @throws IOException\r
- */\r
- public static void getAllGraphs(Collection<GraphBundle> collection) throws IOException {\r
- for (Bundle bundle : getBundles()) {\r
- GraphBundle entry = getGraph(bundle);\r
- if (entry!=null) collection.add(entry);\r
- }\r
- }\r
-\r
- /**\r
- * Get bundle \r
- * \r
- * @param symbolicName\r
- * @return bundle or <tt>null</tt> if there is no bundle or graph \r
- * @throws IOException\r
- */\r
- public static GraphBundle getGraph(String symbolicName) throws IOException {\r
- Bundle bundle = Platform.getBundle(symbolicName);\r
- if (bundle == null) return null;\r
- return getGraph( bundle );\r
- }\r
- \r
- /**\r
- * Read the graph in a graph bundle. Graph is read from "graph.tg" file in the root.\r
- * \r
- * @param bundle\r
- * @return transferable graph, or <tt>null</tt> if there is no graph in the bundle. \r
- * @throws IOException \r
- */\r
- public static GraphBundleEx getGraph(Bundle bundle) throws IOException {\r
- URL url = bundle.getEntry("graph.tg");\r
- \r
- if (url==null) return null;\r
- InputStream is = url.openStream(); \r
- // NOTE: this is vital for performance.\r
- is = new BufferedInputStream(is, 128*1024);\r
- try {\r
- DataInput dis = new DataInputStream(is);\r
- // or\r
- // dis = new InputStreamReadable(is, <max limit>) to protect from OOM\r
- \r
- org.simantics.databoard.container.DataContainer container = \r
- DataContainers.readFile(dis); \r
-\r
- Binding binding = TransferableGraph1.BINDING;\r
- TransferableGraph1 graph = (TransferableGraph1)container.content.getValue(binding);\r
-// TransferableGraph1 graph = (TransferableGraph1) Files.readFile(is, binding);\r
-// System.out.println("getGraph(" + bundle.getSymbolicName() + "): read transferable graph in " + (System.nanoTime()-start)*1e-6 + "ms");\r
- org.osgi.framework.Version osgiVersion = bundle.getVersion();\r
- Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());\r
- String id = bundle.getSymbolicName();\r
- VersionedId vid = new VersionedId(id, p2Version);\r
- String name = (String) bundle.getHeaders().get("Bundle-Name");\r
- if (name == null) name = id;\r
- String immutable = (String) bundle.getHeaders().get("Immutable");\r
- boolean isImmutable = \r
- immutable != null ? \r
- "true".equals(immutable) : \r
- true;\r
-\r
-// System.out.println("getGraph(" + bundle.getSymbolicName() + "): before hashcode calculation in " + (System.nanoTime()-start)*1e-6 + "ms");\r
- GraphBundleEx entry = new GraphBundleEx(name, graph, vid, isImmutable);\r
-// System.out.println("getGraph(" + bundle.getSymbolicName() + "): completed in " + (System.nanoTime()-start)*1e-6 + "ms");\r
- return entry;\r
- } catch (SerializationException e) {\r
- throw new IOException(e);\r
- } catch (IOException e) {\r
- throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);\r
- } catch (RuntimeException e) {\r
- throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);\r
- } catch (AdaptException e) {\r
- throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);\r
- } finally {\r
- is.close();\r
- }\r
- }\r
- \r
- public static class TGInfo {\r
- public Bundle bundle;\r
- public URL location;\r
- public IVersionedId vid;\r
- }\r
- \r
-}\r
-\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.project.management;
+
+import java.io.BufferedInputStream;
+import java.io.Closeable;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+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.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.internal.runtime.PlatformActivator;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.equinox.p2.metadata.IVersionedId;
+import org.eclipse.equinox.p2.metadata.Version;
+import org.eclipse.equinox.p2.metadata.VersionedId;
+import org.osgi.framework.Bundle;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.adapter.AdaptException;
+import org.simantics.databoard.binding.mutable.Variant;
+import org.simantics.databoard.container.DataContainer;
+import org.simantics.databoard.container.DataContainers;
+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.compiler.internal.ltk.FileSource;
+import org.simantics.graph.compiler.internal.ltk.ISource;
+import org.simantics.graph.compiler.internal.ltk.Problem;
+import org.simantics.graph.representation.Extensions;
+import org.simantics.graph.representation.TransferableGraph1;
+import org.simantics.graph.representation.TransferableGraphFileReader;
+import org.simantics.scl.reflection.OntologyVersions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class contains utilities for managing bundles in a active platform.
+ *
+ */
+@SuppressWarnings("restriction")
+public class PlatformUtil {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PlatformUtil.class);
+
+ /**
+ * Get all bundles in the platform.
+ *
+ * @return
+ */
+ public static Bundle[] getBundles() {
+ return PlatformActivator.getContext().getBundles();
+ }
+
+ /**
+ * Get the manifest file of a bundle
+ *
+ * @param bundle bundle
+ * @return manifest or <tt>null</tt> if doesn't not exist
+ * @throws IOException
+ */
+ public static Manifest getManifest(Bundle bundle) throws IOException {
+ URL url = bundle.getEntry("META-INF/MANIFEST.MF");
+ if (url==null) return null;
+ try (InputStream is = url.openStream()) {
+ return new Manifest(is);
+ }
+ }
+
+ /**
+ * Get the manifest file of a bundle
+ *
+ * @param bundle bundle
+ * @return manifest or <tt>null</tt> if doesn't not exist
+ * @throws IOException
+ */
+ public static Manifest getSimanticsManifest(Bundle bundle) throws IOException {
+ URL url = bundle.getEntry("META-INF/SIMANTICS.MF");
+ if (url==null) return null;
+ try (InputStream is = url.openStream()) {
+ return new Manifest(is);
+ }
+ }
+
+ /**
+ * Get a list (BundleIds) of all user installable units. These are the
+ * top-level items that are visible for the end-user.
+ * The list is acquired from the bundles of the current application.
+ *
+ * @param list of simantics features URIs
+ * @throws IOException
+ */
+ public static void getUserInstallableUnits(Collection<String> list)
+ throws IOException
+ {
+ for (Bundle bundle : getBundles()) {
+ Manifest manifest = getSimanticsManifest(bundle);
+ if (manifest==null) continue;
+ Attributes attributes = manifest.getMainAttributes();
+ for (Entry<Object, Object> entry2 : attributes.entrySet()) {
+ Object key = entry2.getKey();
+ if (key.toString().contains("Installable-Unit")) {
+ String bid = entry2.getValue().toString();
+ list.add( bid );
+ }
+ }
+ }
+ }
+
+ /**
+ * Get all transferable graphs in the platform
+ *
+ * @param result collection to be filled with transferable graph info
+ */
+ public static void getPlatformTGInfos(Collection<TGInfo> result) {
+ for (Bundle bundle : getBundles()) {
+ Enumeration<URL> e = bundle.findEntries("graphs/", "*.tg", false);
+ if (e==null) continue;
+ while (e.hasMoreElements()) {
+ org.osgi.framework.Version osgiVersion = bundle.getVersion();
+ Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());
+ String id = bundle.getSymbolicName();
+
+ TGInfo info = new TGInfo();
+ info.location = e.nextElement();
+ info.bundle = bundle;
+ info.vid = new VersionedId(id, p2Version);
+ result.add( info );
+ }
+ }
+ }
+
+ private static void uncheckedClose(Closeable closeable) {
+ try {
+ if (closeable != null)
+ closeable.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+
+ private static 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 static 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 static 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.error("Failed to decode " + url, e);
+ }
+ } else if ("jar".equals(url.getProtocol())) {
+ try {
+ File libFile = extractLib(url, fileName);
+ return libFile;
+ } catch (FileNotFoundException e) {
+ LOGGER.error("Extraction to " + fileName + " failed, url not found: " + url, e);
+ } catch (IOException e) {
+ LOGGER.error("Extraction to " + fileName + " failed from url " + url, e);
+ }
+ } else {
+ LOGGER.error("Unsupported URL protocol '" + url + "' for reading as file '" + fileName + "'");
+ }
+ return null;
+ }
+
+ public static Collection<URL> getTGFiles(Bundle b) {
+ Enumeration<URL> enu = b.findEntries("/", "*.tg", false);
+ if (enu == null)
+ return Collections.emptyList();
+ if (!enu.hasMoreElements())
+ return Collections.emptyList();
+ ArrayList<URL> result = new ArrayList<>();
+ while (enu.hasMoreElements())
+ result.add(enu.nextElement());
+ return result;
+ }
+
+ public static void compile(Bundle b) throws Exception {
+
+ Collection<ISource> sources = new ArrayList<>();
+ Collection<TransferableGraph1> dependencies = new ArrayList<>();
+
+ for (Bundle b2 : getBundles()) {
+ if(b.equals(b2)) continue;
+ for (URL url : getTGFiles(b2)) {
+ File graphFile = url2file(url, b2.toString() + url.toString());
+ dependencies.add(GraphCompiler.read(graphFile));
+ }
+ }
+
+ File bundleFile = FileLocator.getBundleFile(b);
+ if(bundleFile.isDirectory()) {
+ File folder = new File(bundleFile, "dynamicGraph");
+ for(File f : folder.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".pgraph");
+ }
+
+ })) {
+ sources.add(new FileSource(f));
+ }
+ }
+
+// System.out.println("source is " + tmpFile.getAbsolutePath());
+
+ final StringBuilder errorStringBuilder = new StringBuilder();
+ GraphCompilerPreferences prefs = new GraphCompilerPreferences();
+ prefs.validate = true;
+ prefs.validateRelationRestrictions = ValidationMode.ERROR;
+ prefs.validateResourceHasType = ValidationMode.ERROR;
+ String currentLayer0Version = OntologyVersions.getInstance().currentOntologyVersion("http://www.simantics.org/Layer0-0.0");
+ CompilationResult result = GraphCompiler.compile(currentLayer0Version, 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(errorStringBuilder.length() > 0) {
+ LOGGER.error(errorStringBuilder.toString());
+ } else {
+ GraphCompiler.write(new File(bundleFile, "graph.tg"), result.getGraph());
+ }
+
+ }
+
+ /**
+ * Compile all dynamic ontologies in the Platform
+ *
+ * @param collection
+ * @throws IOException
+ */
+ public static void compileAllDynamicOntologies() {
+ for (Bundle bundle : getBundles()) {
+ if(bundle.getEntry("dynamicGraph") != null) {
+ try {
+ File bundleFile = FileLocator.getBundleFile(bundle);
+ if(bundleFile.isDirectory()) {
+ File tg = new File(bundleFile, "graph.tg");
+ long tgLastModified = tg.lastModified();
+ File folder = new File(bundleFile, "dynamicGraph");
+ for(File f : folder.listFiles()) {
+ if(f.isFile() && f.getName().endsWith(".pgraph") && f.lastModified() > tgLastModified) {
+ compile(bundle);
+ break;
+ }
+ }
+ }
+ } catch (Throwable e) {
+ LOGGER.error("Failed to compile dynamic ontologies in bundle " + bundle.getSymbolicName(), e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get all graphs in the Platform
+ *
+ * @param collection
+ * @throws IOException
+ */
+ public static Collection<GraphBundle> getAllGraphs() throws IOException {
+ AtomicReference<IOException> problem = new AtomicReference<>();
+
+ Collection<GraphBundle> gbundles = Arrays.stream(getBundles())
+ .parallel()
+ .map(b -> {
+ try {
+ return problem.get() == null ? getGraphs(b) : Collections.<GraphBundleEx>emptyList();
+ } catch (IOException e) {
+ if (LOGGER.isWarnEnabled())
+ LOGGER.debug("Could not get graph from bundle {}", b, e);
+ problem.set(e);
+ return Collections.<GraphBundleEx>emptyList();
+ }
+ })
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList());
+
+ if (problem.get() != null)
+ throw problem.get();
+ return gbundles;
+ }
+
+ /**
+ * Get bundle
+ *
+ * @param symbolicName
+ * @return bundle or <tt>null</tt> if there is no bundle or graph
+ * @throws IOException
+ */
+ public static GraphBundle getGraph(String symbolicName) throws IOException {
+ Bundle bundle = Platform.getBundle(symbolicName);
+ if (bundle == null) return null;
+ return getGraph( bundle );
+ }
+
+ public static Collection<GraphBundleEx> getGraphs(Bundle bundle) throws IOException {
+ return getTGFiles(bundle).stream()
+ .map(url -> {
+ try {
+ GraphBundleEx result = tryGetOnDemandGraph(bundle, url);
+ return result != null ? result : getCompleteGraph(bundle, url);
+ } catch (IOException e) {
+ if (LOGGER.isWarnEnabled())
+ LOGGER.warn("Could not get graph from bundle url {}", url, e);
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ private static String tgFileId(Bundle bundle, URL url) {
+ String urlString = url.toString();
+ String file = urlString.substring(urlString.lastIndexOf("/") + 1);
+ return bundle.getSymbolicName() + "_" + file;
+ }
+
+ /**
+ * Read the graph in a graph bundle. Graph is read from "graph.tg" file in the root.
+ *
+ * @param bundle
+ * @return transferable graph, or <tt>null</tt> if there is no graph in the bundle.
+ * @throws IOException
+ */
+ public static GraphBundleEx getGraph(Bundle bundle) throws IOException {
+ URL url = bundle.getEntry("graph.tg");
+ if (url == null)
+ return null;
+ GraphBundleEx result = tryGetOnDemandGraph(bundle, url);
+ return result != null ? result : getCompleteGraph(bundle, url);
+ }
+
+ private static GraphBundleEx getCompleteGraph(Bundle bundle, URL url) throws IOException {
+ try {
+ String id = tgFileId(bundle, url);
+ return new GraphBundleEx(
+ getBundleName(bundle, id),
+ readTG(url),
+ new VersionedId(id, toP2Version(bundle)),
+ isImmutable(bundle));
+ } catch (Exception e) {
+ throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
+ } catch (Error e) {
+ LOGGER.error("Serious problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
+ throw e;
+ }
+ }
+
+ /**
+ * Read the graph in a graph bundle. Graph is read from "graph.tg" file in the root.
+ *
+ * @param bundle
+ * @return transferable graph, or <tt>null</tt> if there is no graph in the bundle.
+ * @throws IOException
+ */
+ private static GraphBundleEx tryGetOnDemandGraph(Bundle bundle, URL url) throws IOException {
+ try {
+ Integer cachedHash = readCachedHash(url);
+ if (cachedHash == null) {
+ LOGGER.info("No cached hash for " + bundle);
+ return null;
+ }
+
+ Supplier<TransferableGraph1> graphSource = () -> {
+ try {
+ return readTG(url);
+ } catch (Exception e) {
+ throw new RuntimeException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
+ } catch (Error e) {
+ LOGGER.error("Serious problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
+ throw e;
+ }
+ };
+
+ String id = tgFileId(bundle, url);
+
+ return new GraphBundleEx(
+ getBundleName(bundle, id),
+ graphSource,
+ cachedHash,
+ new VersionedId(id, toP2Version(bundle)),
+ isImmutable(bundle));
+ } catch (Exception e) {
+ throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
+ }
+ }
+
+ private static TransferableGraph1 readTG(URL url) throws Exception {
+ try (InputStream is = url.openStream()) {
+ return TransferableGraphFileReader.read(is);
+ }
+ }
+
+ private static DataContainer readHeader(URL url) throws IOException {
+ try (InputStream is = url.openStream()) {
+ return DataContainers.readHeader(new DataInputStream(new BufferedInputStream(is, 1 << 14)));
+ }
+ }
+
+ private static Integer readCachedHash(URL url) throws IOException, AdaptException {
+ DataContainer header = readHeader(url);
+ Variant hashCode = header.metadata.get(Extensions.CACHED_HASHCODE);
+ return hashCode != null ? (Integer) hashCode.getValue(Bindings.INTEGER) : null;
+ }
+
+ private static Version toP2Version(Bundle bundle) {
+ org.osgi.framework.Version osgiVersion = bundle.getVersion();
+ return Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());
+ }
+
+ private static String getBundleName(Bundle bundle, String id) {
+ String name = (String) bundle.getHeaders().get("Bundle-Name");
+ return name != null ? name : id;
+ }
+
+ private static boolean isImmutable(Bundle bundle) {
+ String immutable = (String) bundle.getHeaders().get("Immutable");
+ return immutable != null ? "true".equals(immutable) : true;
+ }
+
+ public static class TGInfo {
+ public Bundle bundle;
+ public URL location;
+ public IVersionedId vid;
+ }
+
+}
\ No newline at end of file