Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.sling.osgi.obr; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import org.apache.commons.io.IOUtils; import org.osgi.framework.Constants; import org.osgi.framework.Version; import aQute.lib.osgi.Analyzer; /** * The <code>Resource</code> TODO * * @author fmeschbe * @version $Rev$, $Date: 2007-07-02 16:13:58 +0200 (Mon, 02 Jul 2007) $ */ public class Resource implements Serializable, Comparable<Resource> { /** * The name of the bundle manifest header providing the specification(s) of * the bundle(s) to be installed along with this Assembly Bundle (value is * "Assembly-Bundles"). */ public static final String ASSEMBLY_BUNDLES = "Assembly-Bundles"; private URL resourceURL; private String name; private String id; private String presentationName; private String symbolicName; private String uri; private String version; private String description; private long size; private String documentation; private String copyright; private String vendor; private String contact; private String license; private String source; private SortedSet<String> categories; private SortedMap<String, List<Object>> capabilities; private SortedMap<String, List<Object>> requirements; private BundleSpec[] bundleSpecs; public static Resource create(File file) throws IOException { return create(file.toURL()); } public static Resource create(URL file) throws IOException { JarInputStream jar = null; try { URLConnection conn = file.openConnection(); jar = new JarInputStream(conn.getInputStream()); Manifest manifest = jar.getManifest(); if (manifest == null) { throw new IOException(file + " is not a valid JAR file: Manifest not first entry"); } return new Resource(file, manifest.getMainAttributes(), conn.getContentLength()); } finally { IOUtils.closeQuietly(jar); } } private Resource(URL resourceURL, Attributes attrs, long size) throws IOException { this.capabilities = new TreeMap<String, List<Object>>(); this.requirements = new TreeMap<String, List<Object>>(); this.resourceURL = resourceURL; this.name = this.getName(resourceURL.getPath()); this.presentationName = attrs.getValue(Constants.BUNDLE_NAME); this.symbolicName = attrs.getValue(Constants.BUNDLE_SYMBOLICNAME); this.uri = attrs.getValue(Constants.BUNDLE_UPDATELOCATION); this.version = attrs.getValue(Constants.BUNDLE_VERSION); this.description = attrs.getValue(Constants.BUNDLE_DESCRIPTION); this.size = size; this.documentation = attrs.getValue(Constants.BUNDLE_DOCURL); this.copyright = attrs.getValue(Constants.BUNDLE_COPYRIGHT); this.vendor = attrs.getValue(Constants.BUNDLE_VENDOR); this.contact = attrs.getValue(Constants.BUNDLE_CONTACTADDRESS); this.license = attrs.getValue("Bundle-LicenseURL"); this.source = attrs.getValue("Bundle-SourceURL"); String categoryString = attrs.getValue(Constants.BUNDLE_CATEGORY); // require symbolicName if (this.symbolicName == null || this.symbolicName.length() == 0) { throw new IOException("Missing Bundle-SymbolicName, not a valid Bundle"); } // default version valu if (this.version == null || this.version.length() == 0) { this.version = "0.0.0"; } // default value for the id this.id = this.symbolicName + ":" + this.version; this.categories = new TreeSet<String>(); if (categoryString != null) { String[] catList = categoryString.split(","); for (int i = 0; catList != null && i < catList.length; i++) { String cat = catList[i].trim(); if (cat.length() > 0) { this.categories.add(cat); } } } this.addCapability(new BundleCapability(attrs)); this.addExportedServices(attrs.getValue(Constants.EXPORT_SERVICE)); this.addExportedPackages(attrs.getValue(Constants.EXPORT_PACKAGE)); this.addImportedServices(attrs.getValue(Constants.IMPORT_SERVICE)); this.addImportedPackages(attrs.getValue(Constants.IMPORT_PACKAGE)); // parse bundle specifications of Assembly Bundle this.addBundleSpecs(attrs.getValue(ASSEMBLY_BUNDLES)); } void addCapability(Capability capability) { this.addToMapList(this.capabilities, capability.getName(), capability); } public Iterator<Object> getCapabilities() { return this.getMapListIterator(this.capabilities); } void addRequirement(Requirement requirement) { this.addToMapList(this.requirements, requirement.getName(), requirement); } public Iterator<Object> getRequirements() { return this.getMapListIterator(this.requirements); } public SortedSet<String> getCategories() { return this.categories; } public BundleSpec[] getBundleSpecs() { return this.bundleSpecs; } /** * @return the contact */ public String getContact() { return this.contact; } /** * @return the copyright */ public String getCopyright() { return this.copyright; } /** * @return the description */ public String getDescription() { return this.description; } /** * @return the documentation */ public String getDocumentation() { return this.documentation; } /** * @return the id */ public String getId() { return this.id; } /** * Sets the id * @param id */ public void setId(String id) { this.id = id; } /** * @return the license */ public String getLicense() { return this.license; } /** * @return the presentationName */ public String getPresentationName() { return this.presentationName; } /** * @return the size */ public long getSize() { return this.size; } /** * @return the source */ public String getSource() { return this.source; } /** * @return the symbolicName */ public String getSymbolicName() { return this.symbolicName; } /** * @return the uri */ public String getPath() { return this.uri; } /** * Sets the uri * @param uri */ public void setUri(String uri) { this.uri = uri; } /** * @return the vendor */ public String getVendor() { return this.vendor; } /** * @return the version */ public String getVersion() { return this.version; } /** * @return the URL location of the bundle file */ public URL getResourceURL() { return this.resourceURL; } /** * @return the name part of the bundle file URL location */ public String getResourceName() { return this.name; } /** * Returns an <code>InputStream</code> on the resource bundle file * @throws IOException If an error occurrs opening the stream. */ public void spool(OutputStream out) throws IOException { URLConnection conn = this.getResourceURL().openConnection(); InputStream ins = null; try { ins = conn.getInputStream(); Repository.spool(ins, out); } finally { IOUtils.closeQuietly(ins); } } //---------- Serializable interface --------------------------------------- public void serialize(PrintWriter out, String indent) { out.print(indent); out.print("<resource"); this.printAttribute(out, "id", this.id); this.printAttribute(out, "presentationname", this.presentationName); this.printAttribute(out, "symbolicname", this.symbolicName); this.printAttribute(out, "uri", this.uri); this.printAttribute(out, "version", this.version); out.println('>'); String childIndent = indent + " "; this.printElement(out, childIndent, "description", this.description); this.printElement(out, childIndent, "size", String.valueOf(this.size)); this.printElement(out, childIndent, "documentation", this.documentation); this.printElement(out, childIndent, "copyright", this.copyright); this.printElement(out, childIndent, "vendor", this.vendor); this.printElement(out, childIndent, "contact", this.contact); this.printElement(out, childIndent, "license", this.license); this.printElement(out, childIndent, "source", this.source); for (String cat : this.getCategories()) { out.print("<category"); this.printAttribute(out, "id", cat); out.println("/>"); } this.printMap(out, childIndent, this.capabilities); this.printMap(out, childIndent, this.requirements); out.print(indent); out.println("</resource>"); } //---------- Comparable interface ----------------------------------------- /** * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int compareTo(Resource other) { if (this.equals(other)) { return 0; } if (this.getSymbolicName().equals(other.getSymbolicName())) { // compare version Version thisVersion = new Version(this.getVersion()); Version otherVersion = new Version(other.getVersion()); return thisVersion.compareTo(otherVersion); } return this.getSymbolicName().compareTo(other.getSymbolicName()); } //---------- Object overwrite --------------------------------------------- public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof Resource) { Resource other = (Resource) obj; return this.getSymbolicName().equals(other.getSymbolicName()) && this.getVersion().equals(other.getVersion()); } return false; } public int hashCode() { return this.getSymbolicName().hashCode() * 33 + this.getVersion().hashCode() * 17; } public String toString() { return this.getSymbolicName() + " - " + this.getVersion(); } //---------- internal ----------------------------------------------------- // helper private String getName(String path) { int lastSlash = path.lastIndexOf('/'); if (lastSlash >= 0) { return path.substring(lastSlash + 1); } return path; } private void addExportedServices(String exportService) { if (exportService == null || exportService.length() == 0) { return; } } private void addExportedPackages(String exportPackage) { if (exportPackage == null || exportPackage.length() == 0) { return; } // R4Package[] pkgs = ManifestParser.parseImportExportHeader(exportPackage); // for (int i=0; i < pkgs.length; i++) { // // <capability name="package"> // // <p n="package" v="org.apache.felix.upnp.extra.controller"/> // // <p n="version" t="version" v="1.0.0"/> // // </capability> // addCapability(new PackageCapability(new R4Export(pkgs[i]))); // } Map pkgs = Analyzer.parseHeader(exportPackage, null); for (Iterator pi = pkgs.entrySet().iterator(); pi.hasNext();) { // <capability name="package"> // <p n="package" v="org.apache.felix.upnp.extra.controller"/> // <p n="version" t="version" v="1.0.0"/> // </capability> this.addCapability(new PackageCapability((Map.Entry) pi.next())); } } private void addImportedServices(String importService) { if (importService == null || importService.length() == 0) { return; } } private void addImportedPackages(String importPackage) { if (importPackage == null || importPackage.length() == 0) { return; } // R4Package[] pkgs = ManifestParser.parseImportExportHeader(importPackage); // for (int i=0; i < pkgs.length; i++) { // // <require extend="false" // // filter="(&(package=org.xml.sax)(version>=0.0.0))" // // multiple="false" // // name="package" // // optional="false"> // // Import package org.xml.sax // // </require> // addRequirement(new PackageRequirement(new R4Import(pkgs[i]))); // } Map pkgs = Analyzer.parseHeader(importPackage, null); for (Iterator pi = pkgs.entrySet().iterator(); pi.hasNext();) { // <require extend="false" // filter="(&(package=org.xml.sax)(version>=0.0.0))" // multiple="false" // name="package" // optional="false"> // Import package org.xml.sax // </require> this.addRequirement(new PackageRequirement((Map.Entry) pi.next())); } } private void addToMapList(Map<String, List<Object>> map, String name, Object value) { List<Object> current = map.get(name); if (current == null) { current = new ArrayList<Object>(); map.put(name, current); } current.add(value); } private void addBundleSpecs(String spec) { if (spec == null) { // this is not expected ... this.bundleSpecs = new BundleSpec[0]; } else { spec = spec.trim(); List<BundleSpec> specs = new ArrayList<BundleSpec>(); boolean quoted = false; int start = 0; for (int i = 0; i < spec.length(); i++) { char c = spec.charAt(i); if (quoted) { if (c == '\\') { // escape skip to next i++; } else if (c == '"') { quoted = false; } } else { if (c == '"') { // start quoting quoted = true; } else if (c == ',') { // spec separation specs.add(new BundleSpec(spec.substring(start, i))); start = i + 1; } } } if (start < spec.length()) { specs.add(new BundleSpec(spec.substring(start))); } this.bundleSpecs = specs.toArray(new BundleSpec[specs.size()]); } } private Iterator<Object> getMapListIterator(final Map<String, List<Object>> map) { return new Iterator<Object>() { private Iterator<List<Object>> mapIter; private Iterator<Object> listIter; private Object next; { this.mapIter = map.values().iterator(); this.next = this.seek(); } public boolean hasNext() { return this.next != null; } public Object next() { if (this.next == null) { throw new NoSuchElementException("next"); } Object toReturn = this.next; this.next = this.seek(); return toReturn; } private Object seek() { while (this.listIter == null || !this.listIter.hasNext()) { if (this.mapIter.hasNext()) { List<Object> nextlist = this.mapIter.next(); this.listIter = nextlist.iterator(); } else { return null; } } return this.listIter.next(); } public void remove() { throw new UnsupportedOperationException("remove"); } }; } private void printAttribute(PrintWriter out, String name, String value) { if (value != null) { out.print(' '); out.print(name); out.print("=\""); out.print(value); out.print('"'); } } private void printElement(PrintWriter out, String indent, String name, String value) { if (value != null) { out.print(indent); out.print('<'); out.print(name); out.print('>'); out.print(value); out.print("</"); out.print(name); out.println('>'); } } private void printMap(PrintWriter out, String indent, Map map) { for (Iterator mi = this.getMapListIterator(map); mi.hasNext();) { Serializable ser = (Serializable) mi.next(); ser.serialize(out, indent); } } }