]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.project/src/org/simantics/project/features/registry/PluginParser.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.project / src / org / simantics / project / features / registry / PluginParser.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.project.features.registry;
13
14 import java.io.File;
15 import java.io.FileNotFoundException;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Enumeration;
21 import java.util.List;
22 import java.util.Set;
23 import java.util.TreeSet;
24 import java.util.jar.Attributes;
25 import java.util.jar.JarEntry;
26 import java.util.jar.JarFile;
27 import java.util.jar.Manifest;
28 import java.util.logging.Logger;
29
30 import javax.xml.parsers.DocumentBuilder;
31 import javax.xml.parsers.DocumentBuilderFactory;
32 import javax.xml.parsers.ParserConfigurationException;
33
34 import org.eclipse.equinox.p2.metadata.Version;
35 import org.eclipse.equinox.p2.metadata.VersionedId;
36 import org.simantics.databoard.Bindings;
37 import org.simantics.databoard.Files;
38 import org.simantics.databoard.binding.Binding;
39 import org.simantics.databoard.serialization.SerializationException;
40 import org.simantics.graph.representation.TransferableGraph1;
41 import org.simantics.project.management.GraphBundleEx;
42 import org.simantics.utils.strings.StringUtils;
43 import org.w3c.dom.Document;
44 import org.w3c.dom.Element;
45 import org.w3c.dom.Node;
46 import org.w3c.dom.NodeList;
47 import org.xml.sax.SAXException;
48
49 /**
50  * A class for parsing plug-in bundle repositories for finding:
51  * <ol>
52  * <li>bundles that contain transferable graphs (graph.tg) or project feature,
53  * represented as {@link GraphBundleEx} objects</li>
54  * <li>project feature extensions that contain installGroup definitions,
55  * represented as {@link GroupReference} objects</li>
56  * </ol>
57  * 
58  * <p>
59  * Use {@link #parse(String)} or {@link #parse(File)} to parse a bundle or
60  * bundles from a directory. After parsing, {@link #getGraphBundles()} and
61  * {@link #getGroupReferences()} can be used to get what was found during
62  * parsing.
63  * 
64  * @author J-P Laine
65  */
66 public class PluginParser {
67
68     protected Logger log = Logger.getLogger(PluginParser.class.toString());
69
70     protected List<GraphBundleEx> graphBundles    = new ArrayList<GraphBundleEx>();
71
72     protected Set<GroupReference> groupReferences = new TreeSet<GroupReference>();
73
74     /**
75      * @param args
76      */
77     public static void main(String[] args) {
78         PluginParser tester = new PluginParser();
79
80         tester.parse("/home/jplaine/tmp/");
81     }
82
83     /**
84      * @return the list of versioned graph bundles found in the parsed bundle
85      *         repositories so far
86      */
87     public List<GraphBundleEx> getGraphBundles() {
88         return graphBundles;
89     }
90
91     public Set<GroupReference> getGroupReferences() {
92         return groupReferences;
93     }
94
95     /**
96      * @param filename Jar file, or folder that contain jar files
97      */
98     public void parse(String filename) {
99         parse(new File(filename));
100     }
101
102     /**
103      * @param root Jar file, or folder that contains jar files
104      */
105     public void parse(File root) {
106         if(root.isFile()) {
107             parseJar(root.getAbsoluteFile().toString());
108         } else if(root.isDirectory()) {
109             for(File file : root.listFiles()) {
110                 if (file.isFile()) {
111                     parseJar(file.getAbsoluteFile().toString());
112                 }
113             }
114         }
115     }
116
117     /*
118      * This is what to parse:
119      * 
120            <plugin>
121              <extension
122                  point="org.simantics.project.feature">
123               <feature
124                     class="org.simantics.sysdyn.ui.project.SysdynProject"
125                     description="System dynamics modelling project. Create system dynamics models and simulate them with OpenModelica."
126                     id="org.simantics.sysdyn.project"
127                     label="System Dynamics Project"
128                     published="true">
129                  <requires id="org.simantics.sysdyn.dependencies"/>
130                  <requires id="org.simantics.simulation.experimentManager"/>
131                  <installGroup id="org.simantics.sysdyn.feature.group" version="[1.0.0,2.0.0)"/>
132               </feature>
133               <feature
134                     class="org.simantics.project.features.DependencyValidationFeature:http://www.simantics.org/Sysdyn-1.1/ImportedOntologies"
135                     id="org.simantics.sysdyn.dependencies"
136                     label="System Dynamics ontology dependencies">
137               </feature>
138            </extension>
139            </plugin>
140      * 
141      */
142     public Collection<GroupReference> parsePluginXML(InputStream is) throws IOException {
143         Collection<GroupReference> result = new ArrayList<GroupReference>();
144
145         try {
146             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
147             DocumentBuilder db = dbf.newDocumentBuilder();
148             Document doc = db.parse(is);
149             doc.getDocumentElement().normalize();
150             for(Element element : getElementsByTagName(doc.getDocumentElement(), "extension")) {
151                 if("org.simantics.project.feature".equals(element.getAttribute("point"))) {
152                     for(Element feature : getElementsByTagName(element, "feature")) {
153 //                                              log.info("class = "+feature.getAttribute("class"));
154 //                                              log.info("description = "+feature.getAttribute("description"));
155 //                                              log.info("id = "+feature.getAttribute("id"));
156 //                                              log.info("label = "+feature.getAttribute("label"));
157 //                                              log.info("published = "+feature.getAttribute("published"));
158
159                         for(Element installGroup : getElementsByTagName(feature, "installGroup")) {
160 //                                                      log.info("id = "+installGroup.getAttribute("id"));
161 //                                                      log.info("version = "+installGroup.getAttribute("version"));
162
163                             String id = StringUtils.safeString(installGroup.getAttribute("id"));
164                             if (id.isEmpty()) {
165                                 // Invalid extension
166                                 // TODO: log warning
167                                 continue;
168                             }
169                             String version = StringUtils.safeString(installGroup.getAttribute("version"));
170                             if (version.isEmpty())
171                                 // Empty version implies no version, mark that with null.
172                                 version = null;
173
174                             result.add(new GroupReference(id, version));
175                         }
176                     }
177                 }
178             }
179         } catch (ParserConfigurationException e) {
180             throw new IOException("Problem loading plugin.xml ", e);
181         } catch (SAXException e) {
182             throw new IOException("Problem loading plugin.xml ", e);
183         } finally {
184             is.close();
185         }
186         return result;
187
188     }
189
190     public GraphBundleEx parseGraph(InputStream is, Manifest mf) throws IOException {
191         String name = "";
192         String symbolicName = "";
193         VersionedId vid = null;
194
195         if(mf != null) {
196             Attributes attr = mf.getMainAttributes();
197
198             String versionInfo = attr.getValue("Bundle-Version");
199             symbolicName = attr.getValue("Bundle-SymbolicName");
200             org.osgi.framework.Version osgiVersion = new org.osgi.framework.Version(versionInfo);
201             Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier());
202             vid = new VersionedId(symbolicName, p2Version);
203
204             name = attr.getValue("Bundle-Name");
205             if(name == null) name = symbolicName;
206         }
207
208         GraphBundleEx bundleEntry = null;
209         try {
210             Binding binding = Bindings.getBindingUnchecked( TransferableGraph1.class );
211             TransferableGraph1 graph = (TransferableGraph1) Files.readFile(is, binding);
212
213             //System.out.println("getGraph(" + bundle.getSymbolicName() + "): before hashcode calculation in " + (System.nanoTime()-start)*1e-6 + "ms");
214             bundleEntry = new GraphBundleEx(name, graph, vid);
215             //System.out.println("getGraph(" + bundle.getSymbolicName() + "): completed in " + (System.nanoTime()-start)*1e-6 + "ms");
216         } catch (SerializationException ex) {
217             throw new IOException(ex);
218         } catch (IOException ex) {
219             throw new IOException("Problem loading graph.tg from bundle " + symbolicName, ex);
220         } catch (RuntimeException ex) {
221             throw new IOException("Problem loading graph.tg from bundle " + symbolicName, ex);
222         } finally {
223             is.close();
224         }
225
226         return bundleEntry;
227     }
228
229     public void parseJar(String filename) {
230         try {
231             JarFile jar = new JarFile(filename);
232             Enumeration<JarEntry> e = jar.entries();
233             while (e.hasMoreElements()) {
234                 JarEntry entry = e.nextElement();
235                 if(entry.isDirectory()) continue;
236
237                 if("plugin.xml".equals(entry.getName())) {
238                     InputStream is = jar.getInputStream(entry);
239                     Collection<GroupReference> groupReferences = parsePluginXML(is);
240                     for(GroupReference ref : groupReferences) {
241                         log.info("Found group reference: "+ref);
242                     }
243                 } else if("graph.tg".equals(entry.getName())) {
244                     InputStream is = jar.getInputStream(entry);
245                     Manifest mf = jar.getManifest();
246
247                     GraphBundleEx bundleEntry = parseGraph(is, mf);
248                     log.info("Found graph bundle: "+bundleEntry);
249                 }
250             }
251             jar.close();
252         } catch (FileNotFoundException e) {
253             e.printStackTrace();
254         } catch (IOException e) {
255             e.printStackTrace();
256         }
257     }
258
259     public static Collection<Element> getElementsByTagName(Element parent, String name) {
260         List<Element> elements = new ArrayList<Element>();
261         NodeList nodeLst = parent.getElementsByTagName(name);
262         for (int s = 0; s < nodeLst.getLength(); s++) {
263             if (nodeLst.item(s).getNodeType() == Node.ELEMENT_NODE) {
264                 elements.add((Element) nodeLst.item(s));
265             }
266         }
267         return elements;
268     }
269
270 }