X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.project%2Fsrc%2Forg%2Fsimantics%2Fproject%2Fmanagement%2FPlatformUtil.java;fp=bundles%2Forg.simantics.project%2Fsrc%2Forg%2Fsimantics%2Fproject%2Fmanagement%2FPlatformUtil.java;h=dafb8f10d47f3ce074e31cda6eebc42a5e73fd00;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.project/src/org/simantics/project/management/PlatformUtil.java b/bundles/org.simantics.project/src/org/simantics/project/management/PlatformUtil.java new file mode 100644 index 000000000..dafb8f10d --- /dev/null +++ b/bundles/org.simantics.project/src/org/simantics/project/management/PlatformUtil.java @@ -0,0 +1,393 @@ +/******************************************************************************* + * 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.DataInput; +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.Collection; +import java.util.Enumeration; +import java.util.Map.Entry; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +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.adapter.AdaptException; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.mutable.Variant; +import org.simantics.databoard.container.DataContainer; +import org.simantics.databoard.container.DataContainers; +import org.simantics.databoard.serialization.SerializationException; +import org.simantics.db.common.utils.Logger; +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.representation.TransferableGraph1; +import org.simantics.ltk.FileSource; +import org.simantics.ltk.ISource; +import org.simantics.ltk.Problem; +import org.simantics.scl.reflection.OntologyVersions; + +/** + * This class contains utilities for managing bundles in a active platform. + * + */ +@SuppressWarnings("restriction") +public class PlatformUtil { + + + /** + * 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 null 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; + InputStream is = url.openStream(); + try { + return new Manifest(is); + } finally { + is.close(); + } + } + + /** + * Get the manifest file of a bundle + * + * @param bundle bundle + * @return manifest or null 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; + InputStream is = url.openStream(); + try { + return new Manifest(is); + } finally { + is.close(); + } + } + + /** + * 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 list) + throws IOException + { + for (Bundle bundle : getBundles()) { + Manifest manifest = getSimanticsManifest(bundle); + if (manifest==null) continue; + Attributes attributes = manifest.getMainAttributes(); + for (Entry 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 result) { + for (Bundle bundle : getBundles()) { + Enumeration 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.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; + } + + public static void compile(Bundle b) throws Exception { + + Collection sources = new ArrayList(); + Collection dependencies = new ArrayList(); + + for (Bundle b2 : getBundles()) { + if(b.equals(b2)) continue; + URL url = b2.getEntry("graph.tg"); + if (url==null) continue; + File graphFile = url2file(FileLocator.resolve(b2.getEntry("/graph.tg")), b2.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.defaultLogError(errorStringBuilder.toString()); + } else { + DataContainers.writeFile(new File(bundleFile, "graph.tg"), + new DataContainer("graph", 1, new Variant(TransferableGraph1.BINDING, 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.defaultLogError(e); + } + } + } + } + + /** + * Get all graphs in the Platform + * + * @param collection + * @throws IOException + */ + public static void getAllGraphs(Collection collection) throws IOException { + for (Bundle bundle : getBundles()) { + GraphBundle entry = getGraph(bundle); + if (entry!=null) collection.add(entry); + } + } + + /** + * Get bundle + * + * @param symbolicName + * @return bundle or null 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 ); + } + + /** + * Read the graph in a graph bundle. Graph is read from "graph.tg" file in the root. + * + * @param bundle + * @return transferable graph, or null 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; + InputStream is = url.openStream(); + // NOTE: this is vital for performance. + is = new BufferedInputStream(is, 128*1024); + try { + DataInput dis = new DataInputStream(is); + // or + // dis = new InputStreamReadable(is, ) to protect from OOM + + org.simantics.databoard.container.DataContainer container = + DataContainers.readFile(dis); + + Binding binding = TransferableGraph1.BINDING; + TransferableGraph1 graph = (TransferableGraph1)container.content.getValue(binding); +// TransferableGraph1 graph = (TransferableGraph1) Files.readFile(is, binding); +// System.out.println("getGraph(" + bundle.getSymbolicName() + "): read transferable graph in " + (System.nanoTime()-start)*1e-6 + "ms"); + org.osgi.framework.Version osgiVersion = bundle.getVersion(); + Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier()); + String id = bundle.getSymbolicName(); + VersionedId vid = new VersionedId(id, p2Version); + String name = (String) bundle.getHeaders().get("Bundle-Name"); + if (name == null) name = id; + String immutable = (String) bundle.getHeaders().get("Immutable"); + boolean isImmutable = + immutable != null ? + "true".equals(immutable) : + true; + +// System.out.println("getGraph(" + bundle.getSymbolicName() + "): before hashcode calculation in " + (System.nanoTime()-start)*1e-6 + "ms"); + GraphBundleEx entry = new GraphBundleEx(name, graph, vid, isImmutable); +// System.out.println("getGraph(" + bundle.getSymbolicName() + "): completed in " + (System.nanoTime()-start)*1e-6 + "ms"); + return entry; + } catch (SerializationException e) { + throw new IOException(e); + } catch (IOException e) { + throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e); + } catch (RuntimeException e) { + throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e); + } catch (AdaptException e) { + throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e); + } finally { + is.close(); + } + } + + public static class TGInfo { + public Bundle bundle; + public URL location; + public IVersionedId vid; + } + +} +