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.features.registry;
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;
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;
30 import javax.xml.parsers.DocumentBuilder;
31 import javax.xml.parsers.DocumentBuilderFactory;
32 import javax.xml.parsers.ParserConfigurationException;
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;
50 * A class for parsing plug-in bundle repositories for finding:
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>
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
66 public class PluginParser {
68 protected Logger log = Logger.getLogger(PluginParser.class.toString());
70 protected List<GraphBundleEx> graphBundles = new ArrayList<GraphBundleEx>();
72 protected Set<GroupReference> groupReferences = new TreeSet<GroupReference>();
77 public static void main(String[] args) {
78 PluginParser tester = new PluginParser();
80 tester.parse("/home/jplaine/tmp/");
84 * @return the list of versioned graph bundles found in the parsed bundle
87 public List<GraphBundleEx> getGraphBundles() {
91 public Set<GroupReference> getGroupReferences() {
92 return groupReferences;
96 * @param filename Jar file, or folder that contain jar files
98 public void parse(String filename) {
99 parse(new File(filename));
103 * @param root Jar file, or folder that contains jar files
105 public void parse(File root) {
107 parseJar(root.getAbsoluteFile().toString());
108 } else if(root.isDirectory()) {
109 for(File file : root.listFiles()) {
111 parseJar(file.getAbsoluteFile().toString());
118 * This is what to parse:
122 point="org.simantics.project.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"
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)"/>
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">
142 public Collection<GroupReference> parsePluginXML(InputStream is) throws IOException {
143 Collection<GroupReference> result = new ArrayList<GroupReference>();
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"));
159 for(Element installGroup : getElementsByTagName(feature, "installGroup")) {
160 // log.info("id = "+installGroup.getAttribute("id"));
161 // log.info("version = "+installGroup.getAttribute("version"));
163 String id = StringUtils.safeString(installGroup.getAttribute("id"));
169 String version = StringUtils.safeString(installGroup.getAttribute("version"));
170 if (version.isEmpty())
171 // Empty version implies no version, mark that with null.
174 result.add(new GroupReference(id, version));
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);
190 public GraphBundleEx parseGraph(InputStream is, Manifest mf) throws IOException {
192 String symbolicName = "";
193 VersionedId vid = null;
196 Attributes attr = mf.getMainAttributes();
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);
204 name = attr.getValue("Bundle-Name");
205 if(name == null) name = symbolicName;
208 GraphBundleEx bundleEntry = null;
210 Binding binding = Bindings.getBindingUnchecked( TransferableGraph1.class );
211 TransferableGraph1 graph = (TransferableGraph1) Files.readFile(is, binding);
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);
229 public void parseJar(String filename) {
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;
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);
243 } else if("graph.tg".equals(entry.getName())) {
244 InputStream is = jar.getInputStream(entry);
245 Manifest mf = jar.getManifest();
247 GraphBundleEx bundleEntry = parseGraph(is, mf);
248 log.info("Found graph bundle: "+bundleEntry);
252 } catch (FileNotFoundException e) {
254 } catch (IOException e) {
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));