org.apache.sling.osgi.obr.Resource.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sling.osgi.obr.Resource.java

Source

/*
 * 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);
        }
    }
}