1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.project.management;
14 import java.io.BufferedInputStream;
15 import java.io.Closeable;
16 import java.io.DataInput;
17 import java.io.DataInputStream;
19 import java.io.FileNotFoundException;
20 import java.io.FileOutputStream;
21 import java.io.FilenameFilter;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.UnsupportedEncodingException;
26 import java.net.URLDecoder;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Enumeration;
30 import java.util.Map.Entry;
31 import java.util.jar.Attributes;
32 import java.util.jar.Manifest;
34 import org.eclipse.core.internal.runtime.PlatformActivator;
35 import org.eclipse.core.runtime.FileLocator;
36 import org.eclipse.core.runtime.Platform;
37 import org.eclipse.equinox.p2.metadata.IVersionedId;
38 import org.eclipse.equinox.p2.metadata.Version;
39 import org.eclipse.equinox.p2.metadata.VersionedId;
40 import org.osgi.framework.Bundle;
41 import org.simantics.databoard.adapter.AdaptException;
42 import org.simantics.databoard.binding.Binding;
43 import org.simantics.databoard.binding.mutable.Variant;
44 import org.simantics.databoard.container.DataContainer;
45 import org.simantics.databoard.container.DataContainers;
46 import org.simantics.databoard.serialization.SerializationException;
47 import org.simantics.graph.compiler.CompilationResult;
48 import org.simantics.graph.compiler.GraphCompiler;
49 import org.simantics.graph.compiler.GraphCompilerPreferences;
50 import org.simantics.graph.compiler.ValidationMode;
51 import org.simantics.graph.representation.TransferableGraph1;
52 import org.simantics.ltk.FileSource;
53 import org.simantics.ltk.ISource;
54 import org.simantics.ltk.Problem;
55 import org.simantics.scl.reflection.OntologyVersions;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
60 * This class contains utilities for managing bundles in a active platform.
63 @SuppressWarnings("restriction")
64 public class PlatformUtil {
66 private static final Logger LOGGER = LoggerFactory.getLogger(PlatformUtil.class);
69 * Get all bundles in the platform.
73 public static Bundle[] getBundles() {
74 return PlatformActivator.getContext().getBundles();
78 * Get the manifest file of a bundle
80 * @param bundle bundle
81 * @return manifest or <tt>null</tt> if doesn't not exist
84 public static Manifest getManifest(Bundle bundle) throws IOException {
85 URL url = bundle.getEntry("META-INF/MANIFEST.MF");
86 if (url==null) return null;
87 InputStream is = url.openStream();
89 return new Manifest(is);
96 * Get the manifest file of a bundle
98 * @param bundle bundle
99 * @return manifest or <tt>null</tt> if doesn't not exist
100 * @throws IOException
102 public static Manifest getSimanticsManifest(Bundle bundle) throws IOException {
103 URL url = bundle.getEntry("META-INF/SIMANTICS.MF");
104 if (url==null) return null;
105 InputStream is = url.openStream();
107 return new Manifest(is);
114 * Get a list (BundleIds) of all user installable units. These are the
115 * top-level items that are visible for the end-user.
116 * The list is acquired from the bundles of the current application.
118 * @param list of simantics features URIs
119 * @throws IOException
121 public static void getUserInstallableUnits(Collection<String> list)
124 for (Bundle bundle : getBundles()) {
125 Manifest manifest = getSimanticsManifest(bundle);
126 if (manifest==null) continue;
127 Attributes attributes = manifest.getMainAttributes();
128 for (Entry<Object, Object> entry2 : attributes.entrySet()) {
129 Object key = entry2.getKey();
130 if (key.toString().contains("Installable-Unit")) {
131 String bid = entry2.getValue().toString();
139 * Get all transferable graphs in the platform
141 * @param result collection to be filled with transferable graph info
143 public static void getPlatformTGInfos(Collection<TGInfo> result) {
144 for (Bundle bundle : getBundles()) {
145 Enumeration<URL> e = bundle.findEntries("graphs/", "*.tg", false);
146 if (e==null) continue;
147 while (e.hasMoreElements()) {
148 org.osgi.framework.Version osgiVersion = bundle.getVersion();
149 Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());
150 String id = bundle.getSymbolicName();
152 TGInfo info = new TGInfo();
153 info.location = e.nextElement();
154 info.bundle = bundle;
155 info.vid = new VersionedId(id, p2Version);
161 private static void uncheckedClose(Closeable closeable) {
163 if (closeable != null)
165 } catch (IOException e) {
170 private static File copyResource(URL url, File targetFile) throws IOException, FileNotFoundException {
171 FileOutputStream os = null;
172 InputStream is = null;
174 if (targetFile.exists())
177 is = url.openStream();
179 byte [] buffer = new byte [16384];
180 os = new FileOutputStream (targetFile);
181 while ((read = is.read (buffer)) != -1) {
182 os.write(buffer, 0, read);
194 private static File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException {
195 String tmpDirStr = System.getProperty("java.io.tmpdir");
196 if (tmpDirStr == null)
197 throw new NullPointerException("java.io.tmpdir property is null");
198 File tmpDir = new File(tmpDirStr);
199 File libFile = new File(tmpDir, libName);
200 return copyResource(libURL, libFile);
203 private static File url2file(URL url, String fileName) {
204 if ("file".equals(url.getProtocol())) {
206 File path = new File(URLDecoder.decode(url.getPath(), "UTF-8"));
208 } catch (UnsupportedEncodingException e) {
209 LOGGER.error("Failed to decode " + url, e);
211 } else if ("jar".equals(url.getProtocol())) {
213 File libFile = extractLib(url, fileName);
215 } catch (FileNotFoundException e) {
216 LOGGER.error("Extraction to " + fileName + " failed, url not found: " + url, e);
217 } catch (IOException e) {
218 LOGGER.error("Extraction to " + fileName + " failed from url " + url, e);
221 System.err.println("Unsupported URL protocol '" + url + "' for FastLZ native library file '" + fileName);
226 public static void compile(Bundle b) throws Exception {
228 Collection<ISource> sources = new ArrayList<ISource>();
229 Collection<TransferableGraph1> dependencies = new ArrayList<TransferableGraph1>();
231 for (Bundle b2 : getBundles()) {
232 if(b.equals(b2)) continue;
233 URL url = b2.getEntry("graph.tg");
234 if (url==null) continue;
235 File graphFile = url2file(FileLocator.resolve(b2.getEntry("/graph.tg")), b2.toString());
236 dependencies.add(GraphCompiler.read(graphFile));
239 File bundleFile = FileLocator.getBundleFile(b);
240 if(bundleFile.isDirectory()) {
241 File folder = new File(bundleFile, "dynamicGraph");
242 for(File f : folder.listFiles(new FilenameFilter() {
245 public boolean accept(File dir, String name) {
246 return name.endsWith(".pgraph");
250 sources.add(new FileSource(f));
254 // System.out.println("source is " + tmpFile.getAbsolutePath());
256 final StringBuilder errorStringBuilder = new StringBuilder();
257 GraphCompilerPreferences prefs = new GraphCompilerPreferences();
258 prefs.validate = true;
259 prefs.validateRelationRestrictions = ValidationMode.ERROR;
260 prefs.validateResourceHasType = ValidationMode.ERROR;
261 String currentLayer0Version = OntologyVersions.getInstance().currentOntologyVersion("http://www.simantics.org/Layer0-0.0");
262 CompilationResult result = GraphCompiler.compile(currentLayer0Version, sources, dependencies, null, prefs);
264 for(Problem problem : result.getErrors())
265 errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
266 for(Problem problem : result.getWarnings())
267 errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
269 if(errorStringBuilder.length() > 0) {
270 LOGGER.error(errorStringBuilder.toString());
272 DataContainers.writeFile(new File(bundleFile, "graph.tg"),
273 new DataContainer("graph", 1, new Variant(TransferableGraph1.BINDING, result.getGraph())));
279 * Compile all dynamic ontologies in the Platform
282 * @throws IOException
284 public static void compileAllDynamicOntologies() {
285 for (Bundle bundle : getBundles()) {
286 if(bundle.getEntry("dynamicGraph") != null) {
288 File bundleFile = FileLocator.getBundleFile(bundle);
289 if(bundleFile.isDirectory()) {
290 File tg = new File(bundleFile, "graph.tg");
291 long tgLastModified = tg.lastModified();
292 File folder = new File(bundleFile, "dynamicGraph");
293 for(File f : folder.listFiles()) {
294 if(f.isFile() && f.getName().endsWith(".pgraph") && f.lastModified() > tgLastModified) {
300 } catch (Throwable e) {
301 LOGGER.error("Failed to compile dynamic ontologies in bundle " + bundle.getSymbolicName(), e);
308 * Get all graphs in the Platform
311 * @throws IOException
313 public static void getAllGraphs(Collection<GraphBundle> collection) throws IOException {
314 for (Bundle bundle : getBundles()) {
315 GraphBundle entry = getGraph(bundle);
316 if (entry!=null) collection.add(entry);
323 * @param symbolicName
324 * @return bundle or <tt>null</tt> if there is no bundle or graph
325 * @throws IOException
327 public static GraphBundle getGraph(String symbolicName) throws IOException {
328 Bundle bundle = Platform.getBundle(symbolicName);
329 if (bundle == null) return null;
330 return getGraph( bundle );
334 * Read the graph in a graph bundle. Graph is read from "graph.tg" file in the root.
337 * @return transferable graph, or <tt>null</tt> if there is no graph in the bundle.
338 * @throws IOException
340 public static GraphBundleEx getGraph(Bundle bundle) throws IOException {
341 URL url = bundle.getEntry("graph.tg");
343 if (url==null) return null;
344 InputStream is = url.openStream();
345 // NOTE: this is vital for performance.
346 is = new BufferedInputStream(is, 128*1024);
348 DataInput dis = new DataInputStream(is);
350 // dis = new InputStreamReadable(is, <max limit>) to protect from OOM
352 org.simantics.databoard.container.DataContainer container =
353 DataContainers.readFile(dis);
355 Binding binding = TransferableGraph1.BINDING;
356 TransferableGraph1 graph = (TransferableGraph1)container.content.getValue(binding);
357 // TransferableGraph1 graph = (TransferableGraph1) Files.readFile(is, binding);
358 // System.out.println("getGraph(" + bundle.getSymbolicName() + "): read transferable graph in " + (System.nanoTime()-start)*1e-6 + "ms");
359 org.osgi.framework.Version osgiVersion = bundle.getVersion();
360 Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());
361 String id = bundle.getSymbolicName();
362 VersionedId vid = new VersionedId(id, p2Version);
363 String name = (String) bundle.getHeaders().get("Bundle-Name");
364 if (name == null) name = id;
365 String immutable = (String) bundle.getHeaders().get("Immutable");
366 boolean isImmutable =
368 "true".equals(immutable) :
371 // System.out.println("getGraph(" + bundle.getSymbolicName() + "): before hashcode calculation in " + (System.nanoTime()-start)*1e-6 + "ms");
372 GraphBundleEx entry = new GraphBundleEx(name, graph, vid, isImmutable);
373 // System.out.println("getGraph(" + bundle.getSymbolicName() + "): completed in " + (System.nanoTime()-start)*1e-6 + "ms");
375 } catch (Exception e) {
376 throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
378 LOGGER.error("Serious problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
385 public static class TGInfo {
386 public Bundle bundle;
388 public IVersionedId vid;