]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.project/src/org/simantics/project/management/PlatformUtil.java
Merge commit '728147df5d63a3333daff3d8c0e9bfd4f5597e3a'
[simantics/platform.git] / bundles / org.simantics.project / src / org / simantics / project / management / PlatformUtil.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.project.management;\r
13 \r
14 import java.io.BufferedInputStream;\r
15 import java.io.Closeable;\r
16 import java.io.DataInput;\r
17 import java.io.DataInputStream;\r
18 import java.io.File;\r
19 import java.io.FileNotFoundException;\r
20 import java.io.FileOutputStream;\r
21 import java.io.FilenameFilter;\r
22 import java.io.IOException;\r
23 import java.io.InputStream;\r
24 import java.io.UnsupportedEncodingException;\r
25 import java.net.URL;\r
26 import java.net.URLDecoder;\r
27 import java.util.ArrayList;\r
28 import java.util.Collection;\r
29 import java.util.Enumeration;\r
30 import java.util.Map.Entry;\r
31 import java.util.jar.Attributes;\r
32 import java.util.jar.Manifest;\r
33 \r
34 import org.eclipse.core.internal.runtime.PlatformActivator;\r
35 import org.eclipse.core.runtime.FileLocator;\r
36 import org.eclipse.core.runtime.Platform;\r
37 import org.eclipse.equinox.p2.metadata.IVersionedId;\r
38 import org.eclipse.equinox.p2.metadata.Version;\r
39 import org.eclipse.equinox.p2.metadata.VersionedId;\r
40 import org.osgi.framework.Bundle;\r
41 import org.simantics.databoard.adapter.AdaptException;\r
42 import org.simantics.databoard.binding.Binding;\r
43 import org.simantics.databoard.binding.mutable.Variant;\r
44 import org.simantics.databoard.container.DataContainer;\r
45 import org.simantics.databoard.container.DataContainers;\r
46 import org.simantics.databoard.serialization.SerializationException;\r
47 import org.simantics.db.common.utils.Logger;\r
48 import org.simantics.graph.compiler.CompilationResult;\r
49 import org.simantics.graph.compiler.GraphCompiler;\r
50 import org.simantics.graph.compiler.GraphCompilerPreferences;\r
51 import org.simantics.graph.compiler.ValidationMode;\r
52 import org.simantics.graph.representation.TransferableGraph1;\r
53 import org.simantics.ltk.FileSource;\r
54 import org.simantics.ltk.ISource;\r
55 import org.simantics.ltk.Problem;\r
56 import org.simantics.scl.reflection.OntologyVersions;\r
57 \r
58 /**\r
59  * This class contains utilities for managing bundles in a active platform. \r
60  *\r
61  */\r
62 @SuppressWarnings("restriction")\r
63 public class PlatformUtil {\r
64 \r
65         \r
66         /**\r
67          * Get all bundles in the platform.\r
68          * \r
69          * @return\r
70          */\r
71         public static Bundle[] getBundles() {\r
72                 return PlatformActivator.getContext().getBundles();\r
73         }\r
74                 \r
75         /**\r
76          * Get the manifest file of a bundle\r
77          * \r
78          * @param bundle bundle\r
79          * @return manifest or <tt>null</tt> if doesn't not exist\r
80          * @throws IOException \r
81          */\r
82         public static Manifest getManifest(Bundle bundle) throws IOException {\r
83                 URL url = bundle.getEntry("META-INF/MANIFEST.MF");\r
84                 if (url==null) return null;\r
85                 InputStream is = url.openStream();\r
86                 try {\r
87                         return new Manifest(is);                        \r
88                 } finally {\r
89                         is.close();\r
90                 }\r
91         }\r
92         \r
93         /**\r
94          * Get the manifest file of a bundle\r
95          * \r
96          * @param bundle bundle\r
97          * @return manifest or <tt>null</tt> if doesn't not exist\r
98          * @throws IOException \r
99          */\r
100         public static Manifest getSimanticsManifest(Bundle bundle) throws IOException {\r
101                 URL url = bundle.getEntry("META-INF/SIMANTICS.MF");\r
102                 if (url==null) return null;\r
103                 InputStream is = url.openStream();\r
104                 try {\r
105                         return new Manifest(is);                        \r
106                 } finally {\r
107                         is.close();\r
108                 }\r
109         }\r
110         \r
111         /**\r
112          * Get a list (BundleIds) of all user installable units. These are the \r
113          * top-level items that are visible for the end-user. \r
114          * The list is acquired from the bundles of the current application. \r
115          * \r
116          * @param list of simantics features URIs\r
117          * @throws IOException \r
118          */\r
119         public static void getUserInstallableUnits(Collection<String> list) \r
120         throws IOException \r
121         {\r
122                 for (Bundle bundle : getBundles()) {\r
123                         Manifest manifest = getSimanticsManifest(bundle);\r
124                         if (manifest==null) continue;\r
125                         Attributes attributes = manifest.getMainAttributes();\r
126                         for (Entry<Object, Object> entry2 : attributes.entrySet()) {\r
127                                 Object key = entry2.getKey();\r
128                         if (key.toString().contains("Installable-Unit")) {\r
129                                 String bid = entry2.getValue().toString();                              \r
130                                 list.add( bid );\r
131                         }\r
132                         }\r
133                 }               \r
134         }\r
135         \r
136         /**\r
137          * Get all transferable graphs in the platform\r
138          * \r
139          * @param result collection to be filled with transferable graph info \r
140          */\r
141         public static void getPlatformTGInfos(Collection<TGInfo> result) {\r
142                 for (Bundle bundle : getBundles()) {\r
143                         Enumeration<URL> e = bundle.findEntries("graphs/", "*.tg", false);\r
144                         if (e==null) continue;\r
145                         while (e.hasMoreElements()) {\r
146                                 org.osgi.framework.Version osgiVersion = bundle.getVersion();\r
147                                 Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());\r
148                                 String id = bundle.getSymbolicName();\r
149                                 \r
150                                 TGInfo info = new TGInfo();\r
151                                 info.location = e.nextElement();\r
152                                 info.bundle = bundle;\r
153                                 info.vid = new VersionedId(id, p2Version);\r
154                                 result.add( info );\r
155                         }\r
156                 }\r
157         }\r
158 \r
159     private static void uncheckedClose(Closeable closeable) {\r
160         try {\r
161             if (closeable != null)\r
162                 closeable.close();\r
163         } catch (IOException e) {\r
164             //ignore\r
165         }\r
166     }\r
167         \r
168     private static File copyResource(URL url, File targetFile) throws IOException, FileNotFoundException {\r
169         FileOutputStream os = null;\r
170         InputStream is = null;\r
171         try {\r
172             if (targetFile.exists())\r
173                 targetFile.delete();\r
174 \r
175             is = url.openStream();\r
176             int read;\r
177             byte [] buffer = new byte [16384];\r
178             os = new FileOutputStream (targetFile);\r
179             while ((read = is.read (buffer)) != -1) {\r
180                 os.write(buffer, 0, read);\r
181             }\r
182             os.close ();\r
183             is.close ();\r
184 \r
185             return targetFile;\r
186         } finally {\r
187             uncheckedClose(os);\r
188             uncheckedClose(is);\r
189         }\r
190     }\r
191         \r
192     private static File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException {\r
193         String tmpDirStr = System.getProperty("java.io.tmpdir");\r
194         if (tmpDirStr == null)\r
195             throw new NullPointerException("java.io.tmpdir property is null");\r
196         File tmpDir = new File(tmpDirStr);\r
197         File libFile = new File(tmpDir, libName);\r
198         return copyResource(libURL, libFile);\r
199     }\r
200         \r
201     private static File url2file(URL url, String fileName) {\r
202                 if ("file".equals(url.getProtocol())) {\r
203                         try {\r
204                                 File path = new File(URLDecoder.decode(url.getPath(), "UTF-8"));\r
205                                 return path;\r
206                         } catch (UnsupportedEncodingException e) {\r
207                                 Logger.defaultLogError(e);\r
208                         }\r
209                 } else if ("jar".equals(url.getProtocol())) {\r
210                         try {\r
211                                 File libFile = extractLib(url, fileName);\r
212                                 return libFile;\r
213                         } catch (FileNotFoundException e) {\r
214                                 Logger.defaultLogError(e);\r
215                         } catch (IOException e) {\r
216                                 Logger.defaultLogError(e);\r
217                         }\r
218                 } else {\r
219                         System.err.println("Unsupported URL protocol '" + url + "' for FastLZ native library file '" + fileName);\r
220                 }       \r
221                 return null;\r
222         }\r
223         \r
224         public static void compile(Bundle b) throws Exception {\r
225                 \r
226                 Collection<ISource> sources = new ArrayList<ISource>();\r
227                 Collection<TransferableGraph1> dependencies = new ArrayList<TransferableGraph1>();\r
228                 \r
229                 for (Bundle b2 : getBundles()) {\r
230                         if(b.equals(b2)) continue;\r
231                         URL url = b2.getEntry("graph.tg");\r
232                         if (url==null) continue;\r
233                         File graphFile = url2file(FileLocator.resolve(b2.getEntry("/graph.tg")), b2.toString());\r
234                         dependencies.add(GraphCompiler.read(graphFile));\r
235                 }\r
236                 \r
237                 File bundleFile = FileLocator.getBundleFile(b);\r
238                 if(bundleFile.isDirectory()) {\r
239                         File folder = new File(bundleFile, "dynamicGraph");\r
240                         for(File f : folder.listFiles(new FilenameFilter() {\r
241                                 \r
242                                 @Override\r
243                                 public boolean accept(File dir, String name) {\r
244                                         return name.endsWith(".pgraph");\r
245                                 }\r
246                                 \r
247                         })) {\r
248                                 sources.add(new FileSource(f));\r
249                         }\r
250                 }               \r
251                 \r
252 //              System.out.println("source is " + tmpFile.getAbsolutePath());\r
253                 \r
254                 final StringBuilder errorStringBuilder = new StringBuilder();\r
255                 GraphCompilerPreferences prefs = new GraphCompilerPreferences();\r
256                 prefs.validate = true;\r
257                 prefs.validateRelationRestrictions = ValidationMode.ERROR;\r
258                 prefs.validateResourceHasType = ValidationMode.ERROR;\r
259                 String currentLayer0Version = OntologyVersions.getInstance().currentOntologyVersion("http://www.simantics.org/Layer0-0.0");\r
260                 CompilationResult result = GraphCompiler.compile(currentLayer0Version, sources, dependencies, null, prefs);\r
261                 \r
262                 for(Problem problem : result.getErrors())\r
263                         errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");\r
264                 for(Problem problem : result.getWarnings())\r
265                         errorStringBuilder.append(problem.getLocation() + ": " + problem.getDescription() + "\n");\r
266 \r
267                 if(errorStringBuilder.length() > 0) {\r
268                         Logger.defaultLogError(errorStringBuilder.toString());\r
269                 } else {\r
270                         DataContainers.writeFile(new File(bundleFile, "graph.tg"), \r
271                                         new DataContainer("graph", 1, new Variant(TransferableGraph1.BINDING, result.getGraph())));\r
272                 }\r
273                 \r
274         }\r
275         \r
276         /**\r
277          * Compile all dynamic ontologies in the Platform\r
278          * \r
279          * @param collection\r
280          * @throws IOException\r
281          */\r
282         public static void compileAllDynamicOntologies() {\r
283                 for (Bundle bundle : getBundles()) {\r
284                         if(bundle.getEntry("dynamicGraph") != null) {\r
285                                 try {\r
286                                         File bundleFile = FileLocator.getBundleFile(bundle);\r
287                                         if(bundleFile.isDirectory()) {\r
288                                                 File tg = new File(bundleFile, "graph.tg");\r
289                                                 long tgLastModified = tg.lastModified();\r
290                                                 File folder = new File(bundleFile, "dynamicGraph");\r
291                                                 for(File f : folder.listFiles()) {\r
292                                                         if(f.isFile() && f.getName().endsWith(".pgraph") && f.lastModified() > tgLastModified) {\r
293                                                                 compile(bundle);\r
294                                                                 break;\r
295                                                         }\r
296                                                 }\r
297                                         }\r
298                                 } catch (Throwable e) {\r
299                                         Logger.defaultLogError(e);\r
300                                 }\r
301                         }\r
302                 }\r
303         }\r
304         \r
305         /**\r
306          * Get all graphs in the Platform\r
307          * \r
308          * @param collection\r
309          * @throws IOException\r
310          */\r
311         public static void getAllGraphs(Collection<GraphBundle> collection) throws IOException {\r
312                 for (Bundle bundle : getBundles()) {\r
313                         GraphBundle entry = getGraph(bundle);\r
314                         if (entry!=null) collection.add(entry);\r
315                 }\r
316         }\r
317 \r
318         /**\r
319          * Get bundle \r
320          * \r
321          * @param symbolicName\r
322          * @return bundle or <tt>null</tt> if there is no bundle or graph \r
323          * @throws IOException\r
324          */\r
325         public static GraphBundle getGraph(String symbolicName) throws IOException {\r
326                 Bundle bundle = Platform.getBundle(symbolicName);\r
327                 if (bundle == null) return null;\r
328                 return getGraph( bundle );\r
329         }\r
330         \r
331         /**\r
332          * Read the graph in a graph bundle. Graph is read from "graph.tg" file in the root.\r
333          * \r
334          * @param bundle\r
335          * @return transferable graph, or <tt>null</tt> if there is no graph in the bundle. \r
336          * @throws IOException \r
337          */\r
338         public static GraphBundleEx getGraph(Bundle bundle) throws IOException {\r
339                 URL url = bundle.getEntry("graph.tg");\r
340                 \r
341                 if (url==null) return null;\r
342                 InputStream is = url.openStream(); \r
343                 // NOTE: this is vital for performance.\r
344                 is = new BufferedInputStream(is, 128*1024);\r
345                 try {\r
346                         DataInput dis = new DataInputStream(is);\r
347                         // or\r
348                         // dis = new InputStreamReadable(is, <max limit>) to protect from OOM\r
349                         \r
350                         org.simantics.databoard.container.DataContainer container = \r
351                                         DataContainers.readFile(dis); \r
352 \r
353                         Binding binding = TransferableGraph1.BINDING;\r
354                         TransferableGraph1 graph = (TransferableGraph1)container.content.getValue(binding);\r
355 //                      TransferableGraph1 graph = (TransferableGraph1) Files.readFile(is, binding);\r
356 //                      System.out.println("getGraph(" + bundle.getSymbolicName() + "): read transferable graph in " + (System.nanoTime()-start)*1e-6 + "ms");\r
357                         org.osgi.framework.Version osgiVersion = bundle.getVersion();\r
358                         Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());\r
359                         String id = bundle.getSymbolicName();\r
360                         VersionedId vid = new VersionedId(id, p2Version);\r
361                         String name = (String) bundle.getHeaders().get("Bundle-Name");\r
362                         if (name == null) name = id;\r
363                         String immutable = (String) bundle.getHeaders().get("Immutable");\r
364                         boolean isImmutable = \r
365                                         immutable != null ? \r
366                                                         "true".equals(immutable) : \r
367                                                                 true;\r
368 \r
369 //                      System.out.println("getGraph(" + bundle.getSymbolicName() + "): before hashcode calculation in " + (System.nanoTime()-start)*1e-6 + "ms");\r
370                         GraphBundleEx entry = new GraphBundleEx(name, graph, vid, isImmutable);\r
371 //                      System.out.println("getGraph(" + bundle.getSymbolicName() + "): completed in " + (System.nanoTime()-start)*1e-6 + "ms");\r
372                         return entry;\r
373                 } catch (SerializationException e) {\r
374                         throw new IOException(e);\r
375                 } catch (IOException e) {\r
376                         throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);\r
377                 } catch (RuntimeException e) {\r
378                         throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);\r
379                 } catch (AdaptException e) {\r
380                         throw new IOException("Problem loading graph.tg from bundle " + bundle.getSymbolicName(), e);\r
381                 } finally {\r
382                         is.close();\r
383                 }\r
384         }\r
385         \r
386         public static class TGInfo {\r
387                 public Bundle bundle;\r
388                 public URL location;\r
389                 public IVersionedId vid;\r
390         }\r
391         \r
392 }\r
393 \r