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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.project.features.registry;
14 import java.io.File;
\r
15 import java.io.FileNotFoundException;
\r
16 import java.io.IOException;
\r
17 import java.io.InputStream;
\r
18 import java.util.ArrayList;
\r
19 import java.util.Collection;
\r
20 import java.util.Enumeration;
\r
21 import java.util.List;
\r
22 import java.util.Set;
\r
23 import java.util.TreeSet;
\r
24 import java.util.jar.Attributes;
\r
25 import java.util.jar.JarEntry;
\r
26 import java.util.jar.JarFile;
\r
27 import java.util.jar.Manifest;
\r
28 import java.util.logging.Logger;
\r
30 import javax.xml.parsers.DocumentBuilder;
\r
31 import javax.xml.parsers.DocumentBuilderFactory;
\r
32 import javax.xml.parsers.ParserConfigurationException;
\r
34 import org.eclipse.equinox.p2.metadata.Version;
\r
35 import org.eclipse.equinox.p2.metadata.VersionedId;
\r
36 import org.simantics.databoard.Bindings;
\r
37 import org.simantics.databoard.Files;
\r
38 import org.simantics.databoard.binding.Binding;
\r
39 import org.simantics.databoard.serialization.SerializationException;
\r
40 import org.simantics.graph.representation.TransferableGraph1;
\r
41 import org.simantics.project.management.GraphBundleEx;
\r
42 import org.simantics.utils.strings.StringUtils;
\r
43 import org.w3c.dom.Document;
\r
44 import org.w3c.dom.Element;
\r
45 import org.w3c.dom.Node;
\r
46 import org.w3c.dom.NodeList;
\r
47 import org.xml.sax.SAXException;
\r
50 * A class for parsing plug-in bundle repositories for finding:
\r
52 * <li>bundles that contain transferable graphs (graph.tg) or project feature,
\r
53 * represented as {@link GraphBundleEx} objects</li>
\r
54 * <li>project feature extensions that contain installGroup definitions,
\r
55 * represented as {@link GroupReference} objects</li>
\r
59 * Use {@link #parse(String)} or {@link #parse(File)} to parse a bundle or
\r
60 * bundles from a directory. After parsing, {@link #getGraphBundles()} and
\r
61 * {@link #getGroupReferences()} can be used to get what was found during
\r
66 public class PluginParser {
68 protected Logger log = Logger.getLogger(PluginParser.class.toString());
70 protected List<GraphBundleEx> graphBundles = new ArrayList<GraphBundleEx>();
\r
72 protected Set<GroupReference> groupReferences = new TreeSet<GroupReference>();
\r
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
\r
85 * repositories so far
\r
87 public List<GraphBundleEx> getGraphBundles() {
\r
88 return graphBundles;
\r
91 public Set<GroupReference> getGroupReferences() {
\r
92 return groupReferences;
\r
96 * @param filename Jar file, or folder that contain jar files
\r
98 public void parse(String filename) {
\r
99 parse(new File(filename));
\r
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));