Browse Source

preliminary support for reading OSGI manifests

tags/PRE_PIPELINE
wisberg 18 years ago
parent
commit
52260f75fc
1 changed files with 247 additions and 5 deletions
  1. 247
    5
      build/src/org/aspectj/internal/tools/build/Util.java

+ 247
- 5
build/src/org/aspectj/internal/tools/build/Util.java View File

@@ -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);
}
}
}
}


Loading…
Cancel
Save