]> source.dussan.org Git - aspectj.git/commitdiff
preliminary support for reading OSGI manifests
authorwisberg <wisberg>
Thu, 20 Jul 2006 22:25:26 +0000 (22:25 +0000)
committerwisberg <wisberg>
Thu, 20 Jul 2006 22:25:26 +0000 (22:25 +0000)
build/src/org/aspectj/internal/tools/build/Util.java

index 0e3cfe1f616b69975b42bfba66d2a2827ce45ed9..2fc2dcb72d977ab4bdb40b85dacd7e800b0cf703 100644 (file)
 package org.aspectj.internal.tools.build;
 
 import java.io.*;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes.Name;
 
 /** 
  * Build-only utilities.
@@ -237,5 +239,245 @@ public class Util {
         return ((null == list) || (0 == list.length));
     }
 
+    public static void closeSilently(InputStream in) {
+        if (null != in) {
+            try {
+                in.close();
+            } catch (IOException e) {
+                // do nothing
+            }
+        }
+    }
+
+    public static void closeSilently(Reader in) {
+        if (null != in) {
+            try {
+                in.close();
+            } catch (IOException e) {
+                // do nothing
+            }
+        }
+    }
+
+    /**
+     * Report whether actual has different members than expected
+     * @param expected the String[] of expected members (none null)
+     * @param actual the String[] of actual members
+     * @param sb StringBuffer sink for any differences in membership
+     * @return true if any diffs found and sink updated
+     */
+    public static final boolean reportMemberDiffs(String[] expected, String[] actual, StringBuffer sb) {
+        expected = copy(expected);
+        actual = copy(actual);
+        int hits = 0;
+        for (int i = 0; i < expected.length; i++) {
+            int curHit = hits;
+            for (int j = 0; (curHit == hits) && (j < actual.length); j++) {
+                if (null == expected[i]) {
+                    throw new IllegalArgumentException("null at " + i);
+                }
+                if (expected[i].equals(actual[j])) {
+                    expected[i] = null;
+                    actual[j] = null;
+                    hits++;
+                }
+            }
+        }
+        if ((hits != expected.length) || (hits != actual.length)) {
+            sb.append("unexpected [");
+            String prefix = "";
+            for (int i = 0; i < actual.length; i++) {
+                if (null != actual[i]) {
+                    sb.append(prefix);
+                    prefix = ", ";
+                    sb.append("\"");
+                    sb.append(actual[i]);
+                    sb.append("\"");
+                }
+            }
+            sb.append("] missing [");
+            prefix = "";
+            for (int i = 0; i < expected.length; i++) {
+                if (null != expected[i]) {
+                    sb.append(prefix);
+                    prefix = ", ";
+                    sb.append("\"");
+                    sb.append(expected[i]);
+                    sb.append("\"");
+                }
+            }
+            sb.append("]");
+            return true;
+        }
+        return false;
+    }
+
+    private static final String[] copy(String[] ra) {
+        if (null == ra) {
+            return new String[0];
+        }
+        String[] result = new String[ra.length];
+        System.arraycopy(ra, 0, result, 0, ra.length);
+        return result;
+    }
+
+    /**
+     * Support for OSGI bundles read from manifest files.
+     * Currently very limited, and will only support the subset of 
+     * features that we use.
+     * sources:
+     * http://www-128.ibm.com/developerworks/library/os-ecl-osgi/index.html
+     * http://help.eclipse.org/help30/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/osgi/org/osgi/framework/Constants.html
+     */    
+    public static class OSGIBundle {
+        public static final Name BUNDLE_NAME = new Name("Bundle-Name");
+
+        public static final Name BUNDLE_SYMBOLIC_NAME = new Name(
+                "Bundle-SymbolicName");
+
+        public static final Name BUNDLE_VERSION = new Name("Bundle-Version");
+
+        public static final Name BUNDLE_ACTIVATOR = new Name("Bundle-Activator");
+
+        public static final Name BUNDLE_VENDOR = new Name("Bundle-Vendor");
+
+        public static final Name REQUIRE_BUNDLE = new Name("Require-Bundle");
+
+        public static final Name IMPORT_PACKAGE = new Name("Import-Package");
+
+        public static final Name BUNDLE_CLASSPATH = new Name("Bundle-ClassPath");
+
+        /** unmodifiable list of all valid OSGIBundle Name's */
+        public static final List NAMES;
+        static {
+            ArrayList names = new ArrayList();
+            names.add(BUNDLE_NAME);
+            names.add(BUNDLE_SYMBOLIC_NAME);
+            names.add(BUNDLE_VERSION);
+            names.add(BUNDLE_ACTIVATOR);
+            names.add(BUNDLE_VENDOR);
+            names.add(REQUIRE_BUNDLE);
+            names.add(IMPORT_PACKAGE);
+            names.add(BUNDLE_CLASSPATH);
+            NAMES = Collections.unmodifiableList(names);
+        }
+
+        private final Manifest manifest;
+
+        private final Attributes attributes;
+
+        /**
+         * 
+         * @param manifestInputStream
+         *            the InputStream of the manifest.mf - will be closed.
+         * @throws IOException
+         *             if unable to read or close the manifest input stream.
+         */
+        public OSGIBundle(InputStream manifestInputStream) throws IOException {
+            manifest = new Manifest();
+            manifest.read(manifestInputStream);
+            manifestInputStream.close();
+            attributes = manifest.getMainAttributes();
+        }
+
+        public String getAttribute(Name attributeName) {
+            return attributes.getValue(attributeName);
+        }
+
+        public String[] getClasspath() {
+            String cp = getAttribute(OSGIBundle.BUNDLE_CLASSPATH);
+            if (null == cp) {
+                return new String[0];
+            }
+            StringTokenizer st = new StringTokenizer(cp, " ,");
+            String[] result = new String[st.countTokens()];
+            int i = 0;
+            while (st.hasMoreTokens()) {
+                result[i++] = st.nextToken();
+            }
+            return result;
+        }
+
+        /**
+         * XXX ugly/weak hack only handles a single version comma
+         * {name};bundle-version="[1.5.0,1.5.5]";resolution:=optional
+         * @return
+         */
+        public RequiredBundle[] getRequiredBundles() {
+            String value = getAttribute(OSGIBundle.REQUIRE_BUNDLE);
+            if (null == value) {
+                return new RequiredBundle[0];
+            }
+            StringTokenizer st = new StringTokenizer(value, " ,");
+            RequiredBundle[] result = new RequiredBundle[st.countTokens()];
+            int i = 0;
+            int skips = 0;
+            while (st.hasMoreTokens()) {
+                String token = st.nextToken();
+                int first = token.indexOf("\""); 
+                if (-1 != first) {
+                    if (!st.hasMoreTokens()) {
+                        throw new IllegalArgumentException(token);
+                    }
+                    // just assume only one quoted "," for version?
+                    token += "," + st.nextToken();
+                    skips++;
+                }
+                result[i++] = new RequiredBundle(token);
+            }
+            if (skips > 0) {
+                RequiredBundle[] patch = new RequiredBundle[result.length-skips];
+                System.arraycopy(result, 0, patch, 0, patch.length);
+                result = patch;
+            }
+            return result;
+        }
+
+        /**
+         * Wrap each dependency on another bundle 
+         */
+        public static class RequiredBundle {
+            
+            /** unparsed entry text, for debugging */
+            final String text;
+            
+            /** Symbolic name of the required bundle */
+            final String name;
+
+            /** if not null, then start/end versions of required bundle
+             * in the format of the corresponding manifest entry 
+             */
+            final String versions;
+
+            /** if true, then required bundle is optional */
+            final boolean optional;
+
+            private RequiredBundle(String entry) {
+                text = entry;
+                StringTokenizer st = new StringTokenizer(entry, ";");
+                name = st.nextToken();
+                String vers = null;
+                String opt = null;
+                // bundle-version="[1.5.0,1.5.5]";resolution:=optiona
+                final String RESOLUTION = "resolution:=";
+                final String VERSION = "bundle-version=\"";
+                while (st.hasMoreTokens()) {
+                    String token = st.nextToken();
+                    if (token.startsWith(VERSION)) {
+                        int start = VERSION.length();
+                        int end = token.lastIndexOf("\"");
+                        vers = token.substring(start, end);
+                        // e.g., [1.5.0,1.5.5)
+                    } else if (token.startsWith(RESOLUTION)) {
+                        int start = RESOLUTION.length();
+                        int end = token.length();
+                        opt = token.substring(start, end);
+                    } 
+                }
+                versions = vers;
+                optional = "optional".equals(opt);
+            }
+        }
+    }
 }