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.db.common.utils.Logger;
48 import org.simantics.graph.compiler.CompilationResult;
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.representation.TransferableGraph1;
53 import org.simantics.ltk.FileSource;
54 import org.simantics.ltk.ISource;
55 import org.simantics.ltk.Problem;
56 import org.simantics.scl.reflection.OntologyVersions;
59 * This class contains utilities for managing bundles in a active platform.
62 @SuppressWarnings("restriction")
63 public class PlatformUtil {
67 * Get all bundles in the platform.
71 public static Bundle[] getBundles() {
72 return PlatformActivator.getContext().getBundles();
76 * Get the manifest file of a bundle
78 * @param bundle bundle
79 * @return manifest or <tt>null</tt> if doesn't not exist
82 public static Manifest getManifest(Bundle bundle) throws IOException {
83 URL url = bundle.getEntry("META-INF/MANIFEST.MF");
84 if (url==null) return null;
85 InputStream is = url.openStream();
87 return new Manifest(is);
94 * Get the manifest file of a bundle
96 * @param bundle bundle
97 * @return manifest or <tt>null</tt> if doesn't not exist
100 public static Manifest getSimanticsManifest(Bundle bundle) throws IOException {
101 URL url = bundle.getEntry("META-INF/SIMANTICS.MF");
102 if (url==null) return null;
103 InputStream is = url.openStream();
105 return new Manifest(is);
112 * Get a list (BundleIds) of all user installable units. These are the
113 * top-level items that are visible for the end-user.
114 * The list is acquired from the bundles of the current application.
116 * @param list of simantics features URIs
117 * @throws IOException
119 public static void getUserInstallableUnits(Collection<String> list)
122 for (Bundle bundle : getBundles()) {
123 Manifest manifest = getSimanticsManifest(bundle);
124 if (manifest==null) continue;
125 Attributes attributes = manifest.getMainAttributes();
126 for (Entry<Object, Object> entry2 : attributes.entrySet()) {
127 Object key = entry2.getKey();
128 if (key.toString().contains("Installable-Unit")) {
129 String bid = entry2.getValue().toString();
137 * Get all transferable graphs in the platform
139 * @param result collection to be filled with transferable graph info
141 public static void getPlatformTGInfos(Collection<TGInfo> result) {
142 for (Bundle bundle : getBundles()) {
143 Enumeration<URL> e = bundle.findEntries("graphs/", "*.tg", false);
144 if (e==null) continue;
145 while (e.hasMoreElements()) {
146 org.osgi.framework.Version osgiVersion = bundle.getVersion();
147 Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());
148 String id = bundle.getSymbolicName();
150 TGInfo info = new TGInfo();
151 info.location = e.nextElement();
152 info.bundle = bundle;
153 info.vid = new VersionedId(id, p2Version);
159 private static void uncheckedClose(Closeable closeable) {
161 if (closeable != null)
163 } catch (IOException e) {
168 private static File copyResource(URL url, File targetFile) throws IOException, FileNotFoundException {
169 FileOutputStream os = null;
170 InputStream is = null;
172 if (targetFile.exists())
175 is = url.openStream();
177 byte [] buffer = new byte [16384];
178 os = new FileOutputStream (targetFile);
179 while ((read = is.read (buffer)) != -1) {
180 os.write(buffer, 0, read);
192 private static File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException {
193 String tmpDirStr = System.getProperty("java.io.tmpdir");
194 if (tmpDirStr == null)
195 throw new NullPointerException("java.io.tmpdir property is null");
196 File tmpDir = new File(tmpDirStr);
197 File libFile = new File(tmpDir, libName);
198 return copyResource(libURL, libFile);
201 private static File url2file(URL url, String fileName) {
202 if ("file".equals(url.getProtocol())) {
204 File path = new File(URLDecoder.decode(url.getPath(), "UTF-8"));
206 } catch (UnsupportedEncodingException e) {
207 Logger.defaultLogError(e);
209 } else if ("jar".equals(url.getProtocol())) {
211 File libFile = extractLib(url, fileName);
213 } catch (FileNotFoundException e) {
214 Logger.defaultLogError(e);
215 } catch (IOException e) {
216 Logger.defaultLogError(e);
219 System.err.println("Unsupported URL protocol '" + url + "' for FastLZ native library file '" + fileName);
224 public static void compile(Bundle b) throws Exception {
226 Collection<ISource> sources = new ArrayList<ISource>();
227 Collection<TransferableGraph1> dependencies = new ArrayList<TransferableGraph1>();
229 for (Bundle b2 : getBundles()) {
230 if(b.equals(b2)) continue;
231 URL url = b2.getEntry("graph.tg");
232 if (url==null) continue;
233 File graphFile = url2file(FileLocator.resolve(b2.getEntry("/graph.tg")), b2.toString());
234 dependencies.add(GraphCompiler.read(graphFile));
237 File bundleFile = FileLocator.getBundleFile(b);
238 if(bundleFile.isDirectory()) {
239 File folder = new File(bundleFile, "dynamicGraph");
240 for(File f : folder.listFiles(new FilenameFilter() {
243 public boolean accept(File dir, String name) {
244 return name.endsWith(".pgraph");
248 sources.add(new FileSource(f));
252 // System.out.println("source is " + tmpFile.getAbsolutePath());
254 final StringBuilder errorStringBuilder = new StringBuilder();
255 GraphCompilerPreferences prefs = new GraphCompilerPreferences();
256 prefs.validate = true;
257 prefs.validateRelationRestrictions = ValidationMode.ERROR;
258 prefs.validateResourceHasType = ValidationMode.ERROR;
259 String currentLayer0Version = OntologyVersions.getInstance().currentOntologyVersion("http://www.simantics.org/Layer0-0.0");
260 CompilationResult result = GraphCompiler.compile(currentLayer0Version, sources, dependencies, null, prefs);
262 for(Problem problem : result.getErrors())
263 errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
264 for(Problem problem : result.getWarnings())
265 errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");
267 if(errorStringBuilder.length() > 0) {
268 Logger.defaultLogError(errorStringBuilder.toString());
270 DataContainers.writeFile(new File(bundleFile, "graph.tg"),
271 new DataContainer("graph", 1, new Variant(TransferableGraph1.BINDING, result.getGraph())));
277 * Compile all dynamic ontologies in the Platform
280 * @throws IOException
282 public static void compileAllDynamicOntologies() {
283 for (Bundle bundle : getBundles()) {
284 if(bundle.getEntry("dynamicGraph") != null) {
286 File bundleFile = FileLocator.getBundleFile(bundle);
287 if(bundleFile.isDirectory()) {
288 File tg = new File(bundleFile, "graph.tg");
289 long tgLastModified = tg.lastModified();
290 File folder = new File(bundleFile, "dynamicGraph");
291 for(File f : folder.listFiles()) {
292 if(f.isFile() && f.getName().endsWith(".pgraph") && f.lastModified() > tgLastModified) {
298 } catch (Throwable e) {
299 Logger.defaultLogError(e);
306 * Get all graphs in the Platform
309 * @throws IOException
311 public static void getAllGraphs(Collection<GraphBundle> collection) throws IOException {
312 for (Bundle bundle : getBundles()) {
313 GraphBundle entry = getGraph(bundle);
314 if (entry!=null) collection.add(entry);
321 * @param symbolicName
322 * @return bundle or <tt>null</tt> if there is no bundle or graph
323 * @throws IOException
325 public static GraphBundle getGraph(String symbolicName) throws IOException {
326 Bundle bundle = Platform.getBundle(symbolicName);
327 if (bundle == null) return null;
328 return getGraph( bundle );
332 * Read the graph in a graph bundle. Graph is read from "graph.tg" file in the root.
335 * @return transferable graph, or <tt>null</tt> if there is no graph in the bundle.
336 * @throws IOException
338 public static GraphBundleEx getGraph(Bundle bundle) throws IOException {
339 URL url = bundle.getEntry("graph.tg");
341 if (url==null) return null;
342 InputStream is = url.openStream();
343 // NOTE: this is vital for performance.
344 is = new BufferedInputStream(is, 128*1024);
346 DataInput dis = new DataInputStream(is);
348 // dis = new InputStreamReadable(is, <max limit>) to protect from OOM
350 org.simantics.databoard.container.DataContainer container =
351 DataContainers.readFile(dis);
353 Binding binding = TransferableGraph1.BINDING;
354 TransferableGraph1 graph = (TransferableGraph1)container.content.getValue(binding);
355 // TransferableGraph1 graph = (TransferableGraph1) Files.readFile(is, binding);
356 // System.out.println("getGraph(" + bundle.getSymbolicName() + "): read transferable graph in " + (System.nanoTime()-start)*1e-6 + "ms");
357 org.osgi.framework.Version osgiVersion = bundle.getVersion();
358 Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());
359 String id = bundle.getSymbolicName();
360 VersionedId vid = new VersionedId(id, p2Version);
361 String name = (String) bundle.getHeaders().get("Bundle-Name");
362 if (name == null) name = id;
363 String immutable = (String) bundle.getHeaders().get("Immutable");
364 boolean isImmutable =
366 "true".equals(immutable) :
369 // System.out.println("getGraph(" + bundle.getSymbolicName() + "): before hashcode calculation in " + (System.nanoTime()-start)*1e-6 + "ms");
370 GraphBundleEx entry = new GraphBundleEx(name, graph, vid, isImmutable);
371 // System.out.println("getGraph(" + bundle.getSymbolicName() + "): completed in " + (System.nanoTime()-start)*1e-6 + "ms");
373 } catch (SerializationException e) {
374 throw new IOException(e);
375 } catch (IOException e) {
376 throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
377 } catch (RuntimeException e) {
378 throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
379 } catch (AdaptException e) {
380 throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);
386 public static class TGInfo {
387 public Bundle bundle;
389 public IVersionedId vid;