From: wisberg Date: Thu, 20 Jul 2006 22:25:26 +0000 (+0000) Subject: preliminary support for reading OSGI manifests X-Git-Tag: PRE_PIPELINE~32 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=52260f75fc3908c95ab0a7f3b9c811983f79ae58;p=aspectj.git preliminary support for reading OSGI manifests --- diff --git a/build/src/org/aspectj/internal/tools/build/Util.java b/build/src/org/aspectj/internal/tools/build/Util.java index 0e3cfe1f6..2fc2dcb72 100644 --- a/build/src/org/aspectj/internal/tools/build/Util.java +++ b/build/src/org/aspectj/internal/tools/build/Util.java @@ -15,11 +15,13 @@ 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); + } + } + } }