/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.project.features.registry; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionedId; import org.simantics.databoard.Bindings; import org.simantics.databoard.Files; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.serialization.SerializationException; import org.simantics.graph.representation.TransferableGraph1; import org.simantics.project.management.GraphBundleEx; import org.simantics.utils.strings.StringUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * A class for parsing plug-in bundle repositories for finding: *
    *
  1. bundles that contain transferable graphs (graph.tg) or project feature, * represented as {@link GraphBundleEx} objects
  2. *
  3. project feature extensions that contain installGroup definitions, * represented as {@link GroupReference} objects
  4. *
* *

* Use {@link #parse(String)} or {@link #parse(File)} to parse a bundle or * bundles from a directory. After parsing, {@link #getGraphBundles()} and * {@link #getGroupReferences()} can be used to get what was found during * parsing. * * @author J-P Laine */ public class PluginParser { protected Logger log = Logger.getLogger(PluginParser.class.toString()); protected List graphBundles = new ArrayList(); protected Set groupReferences = new TreeSet(); /** * @param args */ public static void main(String[] args) { PluginParser tester = new PluginParser(); tester.parse("/home/jplaine/tmp/"); } /** * @return the list of versioned graph bundles found in the parsed bundle * repositories so far */ public List getGraphBundles() { return graphBundles; } public Set getGroupReferences() { return groupReferences; } /** * @param filename Jar file, or folder that contain jar files */ public void parse(String filename) { parse(new File(filename)); } /** * @param root Jar file, or folder that contains jar files */ public void parse(File root) { if(root.isFile()) { parseJar(root.getAbsoluteFile().toString()); } else if(root.isDirectory()) { for(File file : root.listFiles()) { if (file.isFile()) { parseJar(file.getAbsoluteFile().toString()); } } } } /* * This is what to parse: * * */ public Collection parsePluginXML(InputStream is) throws IOException { Collection result = new ArrayList(); try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(is); doc.getDocumentElement().normalize(); for(Element element : getElementsByTagName(doc.getDocumentElement(), "extension")) { if("org.simantics.project.feature".equals(element.getAttribute("point"))) { for(Element feature : getElementsByTagName(element, "feature")) { // log.info("class = "+feature.getAttribute("class")); // log.info("description = "+feature.getAttribute("description")); // log.info("id = "+feature.getAttribute("id")); // log.info("label = "+feature.getAttribute("label")); // log.info("published = "+feature.getAttribute("published")); for(Element installGroup : getElementsByTagName(feature, "installGroup")) { // log.info("id = "+installGroup.getAttribute("id")); // log.info("version = "+installGroup.getAttribute("version")); String id = StringUtils.safeString(installGroup.getAttribute("id")); if (id.isEmpty()) { // Invalid extension // TODO: log warning continue; } String version = StringUtils.safeString(installGroup.getAttribute("version")); if (version.isEmpty()) // Empty version implies no version, mark that with null. version = null; result.add(new GroupReference(id, version)); } } } } } catch (ParserConfigurationException e) { throw new IOException("Problem loading plugin.xml ", e); } catch (SAXException e) { throw new IOException("Problem loading plugin.xml ", e); } finally { is.close(); } return result; } public GraphBundleEx parseGraph(InputStream is, Manifest mf) throws IOException { String name = ""; String symbolicName = ""; VersionedId vid = null; if(mf != null) { Attributes attr = mf.getMainAttributes(); String versionInfo = attr.getValue("Bundle-Version"); symbolicName = attr.getValue("Bundle-SymbolicName"); org.osgi.framework.Version osgiVersion = new org.osgi.framework.Version(versionInfo); Version p2Version = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro(), osgiVersion.getQualifier()); vid = new VersionedId(symbolicName, p2Version); name = attr.getValue("Bundle-Name"); if(name == null) name = symbolicName; } GraphBundleEx bundleEntry = null; try { Binding binding = Bindings.getBindingUnchecked( TransferableGraph1.class ); TransferableGraph1 graph = (TransferableGraph1) Files.readFile(is, binding); //System.out.println("getGraph(" + bundle.getSymbolicName() + "): before hashcode calculation in " + (System.nanoTime()-start)*1e-6 + "ms"); bundleEntry = new GraphBundleEx(name, graph, vid); //System.out.println("getGraph(" + bundle.getSymbolicName() + "): completed in " + (System.nanoTime()-start)*1e-6 + "ms"); } catch (SerializationException ex) { throw new IOException(ex); } catch (IOException ex) { throw new IOException("Problem loading graph.tg from bundle " + symbolicName, ex); } catch (RuntimeException ex) { throw new IOException("Problem loading graph.tg from bundle " + symbolicName, ex); } finally { is.close(); } return bundleEntry; } public void parseJar(String filename) { try { JarFile jar = new JarFile(filename); Enumeration e = jar.entries(); while (e.hasMoreElements()) { JarEntry entry = e.nextElement(); if(entry.isDirectory()) continue; if("plugin.xml".equals(entry.getName())) { InputStream is = jar.getInputStream(entry); Collection groupReferences = parsePluginXML(is); for(GroupReference ref : groupReferences) { log.info("Found group reference: "+ref); } } else if("graph.tg".equals(entry.getName())) { InputStream is = jar.getInputStream(entry); Manifest mf = jar.getManifest(); GraphBundleEx bundleEntry = parseGraph(is, mf); log.info("Found graph bundle: "+bundleEntry); } } jar.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static Collection getElementsByTagName(Element parent, String name) { List elements = new ArrayList(); NodeList nodeLst = parent.getElementsByTagName(name); for (int s = 0; s < nodeLst.getLength(); s++) { if (nodeLst.item(s).getNodeType() == Node.ELEMENT_NODE) { elements.add((Element) nodeLst.item(s)); } } return elements; } }