You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by mc...@apache.org on 2009/07/13 12:06:50 UTC
svn commit: r793527 [7/7] - in /felix/trunk/bundleplugin: ./
src/main/java/aQute/ src/main/java/aQute/bnd/
src/main/java/aQute/bnd/build/ src/main/java/aQute/bnd/help/
src/main/java/aQute/bnd/make/ src/main/java/aQute/bnd/service/
src/main/java/aQute/b...
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Verifier.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Verifier.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Verifier.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Verifier.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,792 @@
+/* Copyright 2006 aQute SARL
+ * Licensed under the Apache License, Version 2.0, see http://www.apache.org/licenses/LICENSE-2.0 */
+package aQute.lib.osgi;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+import java.util.regex.*;
+
+import aQute.libg.qtokens.*;
+
+public class Verifier extends Analyzer {
+
+ Jar dot;
+ Manifest manifest;
+ Map<String, Map<String, String>> referred = newHashMap();
+ Map<String, Map<String, String>> contained = newHashMap();
+ Map<String, Set<String>> uses = newHashMap();
+ Map<String, Map<String, String>> mimports;
+ Map<String, Map<String, String>> mdynimports;
+ Map<String, Map<String, String>> mexports;
+ List<Jar> bundleClasspath;
+ Map<String, Map<String, String>> ignore = newHashMap(); // Packages
+ // to
+ // ignore
+
+ Map<String, Clazz> classSpace;
+ boolean r3;
+ boolean usesRequire;
+ boolean fragment;
+ Attributes main;
+
+ final static Pattern EENAME = Pattern
+ .compile("CDC-1\\.0/Foundation-1\\.0"
+ + "|CDC-1\\.1/Foundation-1\\.1"
+ + "|OSGi/Minimum-1\\.[1-9]"
+ + "|JRE-1\\.1"
+ + "|J2SE-1\\.2"
+ + "|J2SE-1\\.3"
+ + "|J2SE-1\\.4"
+ + "|J2SE-1\\.5"
+ + "|JavaSE-1\\.6"
+ + "|JavaSE-1\\.7"
+ + "|PersonalJava-1\\.1"
+ + "|PersonalJava-1\\.2"
+ + "|CDC-1\\.0/PersonalBasis-1\\.0"
+ + "|CDC-1\\.0/PersonalJava-1\\.0");
+
+ final static Pattern BUNDLEMANIFESTVERSION = Pattern
+ .compile("2");
+ public final static String SYMBOLICNAME_STRING = "[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)*";
+ public final static Pattern SYMBOLICNAME = Pattern
+ .compile(SYMBOLICNAME_STRING);
+
+ public final static String VERSION_STRING = "[0-9]+(\\.[0-9]+(\\.[0-9]+(\\.[0-9A-Za-z_-]+)?)?)?";
+ public final static Pattern VERSION = Pattern
+ .compile(VERSION_STRING);
+ final static Pattern FILTEROP = Pattern
+ .compile("=|<=|>=|~=");
+ public final static Pattern VERSIONRANGE = Pattern
+ .compile("((\\(|\\[)"
+ + VERSION_STRING
+ + ","
+ + VERSION_STRING
+ + "(\\]|\\)))|"
+ + VERSION_STRING);
+ final static Pattern FILE = Pattern
+ .compile("/?[^/\"\n\r\u0000]+(/[^/\"\n\r\u0000]+)*");
+ final static Pattern WILDCARDPACKAGE = Pattern
+ .compile("((\\p{Alnum}|_)+(\\.(\\p{Alnum}|_)+)*(\\.\\*)?)|\\*");
+ public final static Pattern ISO639 = Pattern
+ .compile("[A-Z][A-Z]");
+ public final static Pattern HEADER_PATTERN = Pattern
+ .compile("[A-Za-z0-9][-a-zA-Z0-9_]+");
+ public final static Pattern TOKEN = Pattern
+ .compile("[-a-zA-Z0-9_]+");
+
+ public final static Pattern NUMBERPATTERN = Pattern
+ .compile("\\d+");
+ public final static Pattern PATHPATTERN = Pattern
+ .compile(".*");
+ public final static Pattern FQNPATTERN = Pattern
+ .compile(".*");
+ public final static Pattern URLPATTERN = Pattern
+ .compile(".*");
+ public final static Pattern ANYPATTERN = Pattern
+ .compile(".*");
+ public final static Pattern FILTERPATTERN = Pattern
+ .compile(".*");
+ public final static Pattern TRUEORFALSEPATTERN = Pattern.compile("true|false|TRUE|FALSE");
+ public static final Pattern WILDCARDNAMEPATTERN = Pattern.compile(".*");
+
+ public final static String EES[] = {
+ "CDC-1.0/Foundation-1.0",
+ "CDC-1.1/Foundation-1.1",
+ "OSGi/Minimum-1.0",
+ "OSGi/Minimum-1.1",
+ "OSGi/Minimum-1.2",
+ "JRE-1.1",
+ "J2SE-1.2",
+ "J2SE-1.3",
+ "J2SE-1.4",
+ "J2SE-1.5",
+ "JavaSE-1.6",
+ "JavaSE-1.7",
+ "PersonalJava-1.1",
+ "PersonalJava-1.2",
+ "CDC-1.0/PersonalBasis-1.0",
+ "CDC-1.0/PersonalJava-1.0"
+ };
+
+ public final static String OSNAMES[] = {
+ "AIX", // IBM
+ "DigitalUnix", // Compaq
+ "Embos", // Segger Embedded Software Solutions
+ "Epoc32", // SymbianOS Symbian OS
+ "FreeBSD", // Free BSD
+ "HPUX", // hp-ux Hewlett Packard
+ "IRIX", // Silicon Graphics
+ "Linux", // Open source
+ "MacOS", // Apple
+ "NetBSD", // Open source
+ "Netware", // Novell
+ "OpenBSD", // Open source
+ "OS2", // OS/2 IBM
+ "QNX", // procnto QNX
+ "Solaris", // Sun (almost an alias of SunOS)
+ "SunOS", // Sun Microsystems
+ "VxWorks", // WindRiver Systems
+ "Windows95", "Win32", "Windows98", "WindowsNT", "WindowsCE",
+ "Windows2000", // Win2000
+ "Windows2003", // Win2003
+ "WindowsXP", "WindowsVista", };
+
+ public final static String PROCESSORNAMES[] = { "68k", // Motorola
+ // 68000
+ "ARM_LE", // Intel Strong ARM. Deprecated because it does not
+ // specify the endianness. See the following two rows.
+ "arm_le", // Intel Strong ARM Little Endian mode
+ "arm_be", // Intel String ARM Big Endian mode
+ "Alpha", //
+ "ia64n",// Hewlett Packard 64 bit
+ "ia64w",// Hewlett Packard 32 bit mode
+ "Ignite", // psc1k PTSC
+ "Mips", // SGI
+ "PArisc", // Hewlett Packard
+ "PowerPC", // power ppc Motorola/IBM Power PC
+ "Sh4", // Hitachi
+ "Sparc", // SUN
+ "S390", // IBM Mainframe 31 bit
+ "S390x", // IBM Mainframe 64-bit
+ "V850E", // NEC V850E
+ "x86", // pentium i386
+ "i486", // i586 i686 Intel& AMD 32 bit
+ "x86-64", };
+
+ Properties properties;
+
+ public Verifier(Jar jar) throws Exception {
+ this(jar, null);
+ }
+
+ public Verifier(Jar jar, Properties properties) throws Exception {
+ this.dot = jar;
+ this.properties = properties;
+ this.manifest = jar.getManifest();
+ if (manifest == null) {
+ manifest = new Manifest();
+ error("This file contains no manifest and is therefore not a bundle");
+ }
+ main = this.manifest.getMainAttributes();
+ verifyHeaders(main);
+ r3 = getHeader(Analyzer.BUNDLE_MANIFESTVERSION) == null;
+ usesRequire = getHeader(Analyzer.REQUIRE_BUNDLE) != null;
+ fragment = getHeader(Analyzer.FRAGMENT_HOST) != null;
+
+ bundleClasspath = getBundleClassPath();
+ mimports = parseHeader(manifest.getMainAttributes().getValue(
+ Analyzer.IMPORT_PACKAGE));
+ mdynimports = parseHeader(manifest.getMainAttributes().getValue(
+ Analyzer.DYNAMICIMPORT_PACKAGE));
+ mexports = parseHeader(manifest.getMainAttributes().getValue(
+ Analyzer.EXPORT_PACKAGE));
+
+ ignore = parseHeader(manifest.getMainAttributes().getValue(
+ Analyzer.IGNORE_PACKAGE));
+ }
+
+ public Verifier() {
+ // TODO Auto-generated constructor stub
+ }
+
+ private void verifyHeaders(Attributes main) {
+ for (Object element : main.keySet()) {
+ Attributes.Name header = (Attributes.Name) element;
+ String h = header.toString();
+ if (!HEADER_PATTERN.matcher(h).matches())
+ error("Invalid Manifest header: " + h + ", pattern="
+ + HEADER_PATTERN);
+ }
+ }
+
+ private List<Jar> getBundleClassPath() {
+ List<Jar> list = newList();
+ String bcp = getHeader(Analyzer.BUNDLE_CLASSPATH);
+ if (bcp == null) {
+ list.add(dot);
+ } else {
+ Map<String, Map<String, String>> entries = parseHeader(bcp);
+ for (String jarOrDir : entries.keySet()) {
+ if (jarOrDir.equals(".")) {
+ list.add(dot);
+ } else {
+ if (jarOrDir.equals("/"))
+ jarOrDir = "";
+ if (jarOrDir.endsWith("/")) {
+ error("Bundle-Classpath directory must not end with a slash: "
+ + jarOrDir);
+ jarOrDir = jarOrDir.substring(0, jarOrDir.length() - 1);
+ }
+
+ Resource resource = dot.getResource(jarOrDir);
+ if (resource != null) {
+ try {
+ Jar sub = new Jar(jarOrDir);
+ addClose(sub);
+ EmbeddedResource.build(sub, resource);
+ if (!jarOrDir.endsWith(".jar"))
+ warning("Valid JAR file on Bundle-Classpath does not have .jar extension: "
+ + jarOrDir);
+ list.add(sub);
+ } catch (Exception e) {
+ error("Invalid embedded JAR file on Bundle-Classpath: "
+ + jarOrDir + ", " + e);
+ }
+ } else if (dot.getDirectories().containsKey(jarOrDir)) {
+ if (r3)
+ error("R3 bundles do not support directories on the Bundle-ClassPath: "
+ + jarOrDir);
+
+ try {
+ Jar sub = new Jar(jarOrDir);
+ addClose(sub);
+ for (Map.Entry<String, Resource> entry : dot
+ .getResources().entrySet()) {
+ if (entry.getKey().startsWith(jarOrDir))
+ sub.putResource(entry.getKey().substring(
+ jarOrDir.length() + 1), entry
+ .getValue());
+ }
+ list.add(sub);
+ } catch (Exception e) {
+ error("Invalid embedded directory file on Bundle-Classpath: "
+ + jarOrDir + ", " + e);
+ }
+ } else {
+ error("Cannot find a file or directory for Bundle-Classpath entry: "
+ + jarOrDir);
+ }
+ }
+ }
+ }
+ return list;
+ }
+
+ /*
+ * Bundle-NativeCode ::= nativecode ( ',' nativecode )* ( â,â optional) ?
+ * nativecode ::= path ( ';' path )* // See 1.4.2 ( ';' parameter )+
+ * optional ::= â*â
+ */
+ public void verifyNative() {
+ String nc = getHeader("Bundle-NativeCode");
+ doNative(nc);
+ }
+
+ public void doNative(String nc) {
+ if (nc != null) {
+ QuotedTokenizer qt = new QuotedTokenizer(nc, ",;=", false);
+ char del;
+ do {
+ do {
+ String name = qt.nextToken();
+ if (name == null) {
+ error("Can not parse name from bundle native code header: "
+ + nc);
+ return;
+ }
+ del = qt.getSeparator();
+ if (del == ';') {
+ if (dot != null && !dot.exists(name)) {
+ error("Native library not found in JAR: " + name);
+ }
+ } else {
+ String value = null;
+ if (del == '=')
+ value = qt.nextToken();
+
+ String key = name.toLowerCase();
+ if (key.equals("osname")) {
+ // ...
+ } else if (key.equals("osversion")) {
+ // verify version range
+ verify(value, VERSIONRANGE);
+ } else if (key.equals("language")) {
+ verify(value, ISO639);
+ } else if (key.equals("processor")) {
+ // verify(value, PROCESSORS);
+ } else if (key.equals("selection-filter")) {
+ // verify syntax filter
+ verifyFilter(value);
+ } else if (name.equals("*") && value == null) {
+ // Wildcard must be at end.
+ if (qt.nextToken() != null)
+ error("Bundle-Native code header may only END in wildcard: nc");
+ } else {
+ warning("Unknown attribute in native code: " + name
+ + "=" + value);
+ }
+ del = qt.getSeparator();
+ }
+ } while (del == ';');
+ } while (del == ',');
+ }
+ }
+
+ public void verifyFilter(String value) {
+ try {
+ verifyFilter(value, 0);
+ } catch (Exception e) {
+ error("Not a valid filter: " + value + e.getMessage());
+ }
+ }
+
+ private void verifyActivator() {
+ String bactivator = getHeader("Bundle-Activator");
+ if (bactivator != null) {
+ Clazz cl = loadClass(bactivator);
+ if (cl == null) {
+ int n = bactivator.lastIndexOf('.');
+ if (n > 0) {
+ String pack = bactivator.substring(0, n);
+ if (mimports.containsKey(pack))
+ return;
+ error("Bundle-Activator not found on the bundle class path nor in imports: "
+ + bactivator);
+ } else
+ error("Activator uses default package and is not local (default package can not be imported): "
+ + bactivator);
+ }
+ }
+ }
+
+ private Clazz loadClass(String className) {
+ String path = className.replace('.', '/') + ".class";
+ return (Clazz) classSpace.get(path);
+ }
+
+ private void verifyComponent() {
+ String serviceComponent = getHeader("Service-Component");
+ if (serviceComponent != null) {
+ Map<String, Map<String, String>> map = parseHeader(serviceComponent);
+ for (String component : map.keySet()) {
+ if (component.indexOf("*")<0 && !dot.exists(component)) {
+ error("Service-Component entry can not be located in JAR: "
+ + component);
+ } else {
+ // validate component ...
+ }
+ }
+ }
+ }
+
+ public void info() {
+ System.out.println("Refers : " + referred);
+ System.out.println("Contains : " + contained);
+ System.out.println("Manifest Imports : " + mimports);
+ System.out.println("Manifest Exports : " + mexports);
+ }
+
+ /**
+ * Invalid exports are exports mentioned in the manifest but not found on
+ * the classpath. This can be calculated with: exports - contains.
+ *
+ * Unfortunately, we also must take duplicate names into account. These
+ * duplicates are of course no erroneous.
+ */
+ private void verifyInvalidExports() {
+ Set<String> invalidExport = newSet(mexports.keySet());
+ invalidExport.removeAll(contained.keySet());
+
+ // We might have duplicate names that are marked for it. These
+ // should not be counted. Should we test them against the contained
+ // set? Hmm. If someone wants to hang himself by using duplicates than
+ // I guess he can go ahead ... This is not a recommended practice
+ for (Iterator<String> i = invalidExport.iterator(); i.hasNext();) {
+ String pack = i.next();
+ if (isDuplicate(pack))
+ i.remove();
+ }
+
+ if (!invalidExport.isEmpty())
+ error("Exporting packages that are not on the Bundle-Classpath"
+ + bundleClasspath + ": " + invalidExport);
+ }
+
+ /**
+ * Invalid imports are imports that we never refer to. They can be
+ * calculated by removing the refered packages from the imported packages.
+ * This leaves packages that the manifest imported but that we never use.
+ */
+ private void verifyInvalidImports() {
+ Set<String> invalidImport = newSet(mimports.keySet());
+ invalidImport.removeAll(referred.keySet());
+ // TODO Added this line but not sure why it worked before ...
+ invalidImport.removeAll(contained.keySet());
+ String bactivator = getHeader(Analyzer.BUNDLE_ACTIVATOR);
+ if (bactivator != null) {
+ int n = bactivator.lastIndexOf('.');
+ if (n > 0) {
+ invalidImport.remove(bactivator.substring(0, n));
+ }
+ }
+ if (isPedantic() && !invalidImport.isEmpty())
+ warning("Importing packages that are never refered to by any class on the Bundle-Classpath"
+ + bundleClasspath + ": " + invalidImport);
+ }
+
+ /**
+ * Check for unresolved imports. These are referals that are not imported by
+ * the manifest and that are not part of our bundle classpath. The are
+ * calculated by removing all the imported packages and contained from the
+ * refered packages.
+ */
+ private void verifyUnresolvedReferences() {
+ Set<String> unresolvedReferences = new TreeSet<String>(referred
+ .keySet());
+ unresolvedReferences.removeAll(mimports.keySet());
+ unresolvedReferences.removeAll(contained.keySet());
+
+ // Remove any java.** packages.
+ for (Iterator<String> p = unresolvedReferences.iterator(); p.hasNext();) {
+ String pack = p.next();
+ if (pack.startsWith("java.") || ignore.containsKey(pack))
+ p.remove();
+ else {
+ // Remove any dynamic imports
+ if (isDynamicImport(pack))
+ p.remove();
+ }
+ }
+
+ if (!unresolvedReferences.isEmpty()) {
+ // Now we want to know the
+ // classes that are the culprits
+ Set<String> culprits = new HashSet<String>();
+ for (Clazz clazz : classSpace.values()) {
+ if (hasOverlap(unresolvedReferences, clazz.imports.keySet()))
+ culprits.add(clazz.getPath());
+ }
+
+ error("Unresolved references to " + unresolvedReferences
+ + " by class(es) on the Bundle-Classpath" + bundleClasspath
+ + ": " + culprits);
+ }
+ }
+
+ /**
+ * @param p
+ * @param pack
+ */
+ private boolean isDynamicImport(String pack) {
+ for (String pattern : mdynimports.keySet()) {
+ // Wildcard?
+ if (pattern.equals("*"))
+ return true; // All packages can be dynamically imported
+
+ if (pattern.endsWith(".*")) {
+ pattern = pattern.substring(0, pattern.length() - 2);
+ if (pack.startsWith(pattern)
+ && (pack.length() == pattern.length() || pack
+ .charAt(pattern.length()) == '.'))
+ return true;
+ } else {
+ if (pack.equals(pattern))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean hasOverlap(Set<?> a, Set<?> b) {
+ for (Iterator<?> i = a.iterator(); i.hasNext();) {
+ if (b.contains(i.next()))
+ return true;
+ }
+ return false;
+ }
+
+ public void verify() throws IOException {
+ if (classSpace == null)
+ classSpace = analyzeBundleClasspath(dot,
+ parseHeader(getHeader(Analyzer.BUNDLE_CLASSPATH)),
+ contained, referred, uses);
+ verifyManifestFirst();
+ verifyActivator();
+ verifyComponent();
+ verifyNative();
+ verifyInvalidExports();
+ verifyInvalidImports();
+ verifyUnresolvedReferences();
+ verifySymbolicName();
+ verifyListHeader("Bundle-RequiredExecutionEnvironment", EENAME, false);
+ verifyHeader("Bundle-ManifestVersion", BUNDLEMANIFESTVERSION, false);
+ verifyHeader("Bundle-Version", VERSION, true);
+ verifyListHeader("Bundle-Classpath", FILE, false);
+ verifyDynamicImportPackage();
+ verifyBundleClasspath();
+ if (usesRequire) {
+ if (!getErrors().isEmpty()) {
+ getWarnings()
+ .add(
+ 0,
+ "Bundle uses Require Bundle, this can generate false errors because then not enough information is available without the required bundles");
+ }
+ }
+ }
+
+ public void verifyBundleClasspath() {
+ Map<String, Map<String, String>> bcp = parseHeader(getHeader(Analyzer.BUNDLE_CLASSPATH));
+ if (bcp.isEmpty() || bcp.containsKey("."))
+ return;
+
+ for (String path : dot.getResources().keySet()) {
+ if (path.endsWith(".class")) {
+ warning("The Bundle-Classpath does not contain the actual bundle JAR (as specified with '.' in the Bundle-Classpath) but the JAR does contain classes. Is this intentional?");
+ return;
+ }
+ }
+ }
+
+ /**
+ * <pre>
+ * DynamicImport-Package ::= dynamic-description
+ * ( ',' dynamic-description )*
+ *
+ * dynamic-description::= wildcard-names ( ';' parameter )*
+ * wildcard-names ::= wildcard-name ( ';' wildcard-name )*
+ * wildcard-name ::= package-name
+ * | ( package-name '.*' ) // See 1.4.2
+ * | '*'
+ * </pre>
+ */
+ private void verifyDynamicImportPackage() {
+ verifyListHeader("DynamicImport-Package", WILDCARDPACKAGE, true);
+ String dynamicImportPackage = getHeader("DynamicImport-Package");
+ if (dynamicImportPackage == null)
+ return;
+
+ Map<String, Map<String, String>> map = parseHeader(dynamicImportPackage);
+ for (String name : map.keySet()) {
+ name = name.trim();
+ if (!verify(name, WILDCARDPACKAGE))
+ error("DynamicImport-Package header contains an invalid package name: "
+ + name);
+
+ Map<String, String> sub = map.get(name);
+ if (r3 && sub.size() != 0) {
+ error("DynamicPackage-Import has attributes on import: "
+ + name
+ + ". This is however, an <=R3 bundle and attributes on this header were introduced in R4. ");
+ }
+ }
+ }
+
+ private void verifyManifestFirst() {
+ if (!dot.manifestFirst) {
+ error("Invalid JAR stream: Manifest should come first to be compatible with JarInputStream, it was not");
+ }
+ }
+
+ private void verifySymbolicName() {
+ Map<String, Map<String, String>> bsn = parseHeader(getHeader(Analyzer.BUNDLE_SYMBOLICNAME));
+ if (!bsn.isEmpty()) {
+ if (bsn.size() > 1)
+ error("More than one BSN specified " + bsn);
+
+ String name = (String) bsn.keySet().iterator().next();
+ if (!SYMBOLICNAME.matcher(name).matches()) {
+ error("Symbolic Name has invalid format: " + name);
+ }
+ }
+ }
+
+ /**
+ * <pre>
+ * filter ::= â(â filter-comp â)â
+ * filter-comp ::= and | or | not | operation
+ * and ::= â&â filter-list
+ * or ::= â|â filter-list
+ * not ::= â!â filter
+ * filter-list ::= filter | filter filter-list
+ * operation ::= simple | present | substring
+ * simple ::= attr filter-type value
+ * filter-type ::= equal | approx | greater | less
+ * equal ::= â=â
+ * approx ::= â˜=â
+ * greater ::= â>=â
+ * less ::= â<=â
+ * present ::= attr â=*â
+ * substring ::= attr â=â initial any final
+ * inital ::= () | value
+ * any ::= â*â star-value
+ * star-value ::= () | value â*â star-value
+ * final ::= () | value
+ * value ::= <see text>
+ * </pre>
+ *
+ * @param expr
+ * @param index
+ * @return
+ */
+
+ int verifyFilter(String expr, int index) {
+ try {
+ while (Character.isWhitespace(expr.charAt(index)))
+ index++;
+
+ if (expr.charAt(index) != '(')
+ throw new IllegalArgumentException(
+ "Filter mismatch: expected ( at position " + index
+ + " : " + expr);
+
+ index++;
+ while (Character.isWhitespace(expr.charAt(index)))
+ index++;
+
+ switch (expr.charAt(index)) {
+ case '!':
+ case '&':
+ case '|':
+ return verifyFilterSubExpression(expr, index) + 1;
+
+ default:
+ return verifyFilterOperation(expr, index) + 1;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new IllegalArgumentException(
+ "Filter mismatch: early EOF from " + index);
+ }
+ }
+
+ private int verifyFilterOperation(String expr, int index) {
+ StringBuffer sb = new StringBuffer();
+ while ("=><~()".indexOf(expr.charAt(index)) < 0) {
+ sb.append(expr.charAt(index++));
+ }
+ String attr = sb.toString().trim();
+ if (attr.length() == 0)
+ throw new IllegalArgumentException(
+ "Filter mismatch: attr at index " + index + " is 0");
+ sb = new StringBuffer();
+ while ("=><~".indexOf(expr.charAt(index)) >= 0) {
+ sb.append(expr.charAt(index++));
+ }
+ String operator = sb.toString();
+ if (!verify(operator, FILTEROP))
+ throw new IllegalArgumentException(
+ "Filter error, illegal operator " + operator + " at index "
+ + index);
+
+ sb = new StringBuffer();
+ while (")".indexOf(expr.charAt(index)) < 0) {
+ switch (expr.charAt(index)) {
+ case '\\':
+ if (expr.charAt(index + 1) == '*'
+ || expr.charAt(index + 1) == ')')
+ index++;
+ else
+ throw new IllegalArgumentException(
+ "Filter error, illegal use of backslash at index "
+ + index
+ + ". Backslash may only be used before * or (");
+ }
+ sb.append(expr.charAt(index++));
+ }
+ return index;
+ }
+
+ private int verifyFilterSubExpression(String expr, int index) {
+ do {
+ index = verifyFilter(expr, index + 1);
+ while (Character.isWhitespace(expr.charAt(index)))
+ index++;
+ if (expr.charAt(index) != ')')
+ throw new IllegalArgumentException(
+ "Filter mismatch: expected ) at position " + index
+ + " : " + expr);
+ index++;
+ } while (expr.charAt(index) == '(');
+ return index;
+ }
+
+ private String getHeader(String string) {
+ return main.getValue(string);
+ }
+
+ @SuppressWarnings("unchecked")
+ private boolean verifyHeader(String name, Pattern regex, boolean error) {
+ String value = manifest.getMainAttributes().getValue(name);
+ if (value == null)
+ return false;
+
+ QuotedTokenizer st = new QuotedTokenizer(value.trim(), ",");
+ for (Iterator<String> i = st.getTokenSet().iterator(); i.hasNext();) {
+ if (!verify((String) i.next(), regex)) {
+ String msg = "Invalid value for " + name + ", " + value
+ + " does not match " + regex.pattern();
+ if (error)
+ error(msg);
+ else
+ warning(msg);
+ }
+ }
+ return true;
+ }
+
+ private boolean verify(String value, Pattern regex) {
+ return regex.matcher(value).matches();
+ }
+
+ private boolean verifyListHeader(String name, Pattern regex, boolean error) {
+ String value = manifest.getMainAttributes().getValue(name);
+ if (value == null)
+ return false;
+
+ Map<String, Map<String, String>> map = parseHeader(value);
+ for (String header : map.keySet()) {
+ if (!regex.matcher(header).matches()) {
+ String msg = "Invalid value for " + name + ", " + value
+ + " does not match " + regex.pattern();
+ if (error)
+ error(msg);
+ else
+ warning(msg);
+ }
+ }
+ return true;
+ }
+
+ public String getProperty(String key, String deflt) {
+ if (properties == null)
+ return deflt;
+ return properties.getProperty(key, deflt);
+ }
+
+ public void setClassSpace(Map<String, Clazz> classspace,
+ Map<String, Map<String, String>> contained,
+ Map<String, Map<String, String>> referred,
+ Map<String, Set<String>> uses) {
+ this.classSpace = classspace;
+ this.contained = contained;
+ this.referred = referred;
+ this.uses = uses;
+ }
+
+ public static boolean isVersion(String version) {
+ return VERSION.matcher(version).matches();
+ }
+
+ public static boolean isIdentifier(String value) {
+ if ( value.length() < 1 )
+ return false;
+
+ if ( !Character.isJavaIdentifierStart(value.charAt(0)))
+ return false;
+
+ for ( int i = 1; i<value.length(); i++ ) {
+ if ( !Character.isJavaIdentifierPart(value.charAt(i)))
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean isMember(String value, String[] matches) {
+ for ( String match : matches ) {
+ if ( match.equals(value) )
+ return true;
+ }
+ return false;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Verifier.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ZipResource.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ZipResource.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ZipResource.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ZipResource.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,82 @@
+/* Copyright 2006 aQute SARL
+ * Licensed under the Apache License, Version 2.0, see http://www.apache.org/licenses/LICENSE-2.0 */
+package aQute.lib.osgi;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+import java.util.zip.*;
+
+public class ZipResource implements Resource {
+ ZipFile zip;
+ ZipEntry entry;
+ long lastModified;
+ String extra;
+
+ ZipResource(ZipFile zip, ZipEntry entry, long lastModified) {
+ this.zip = zip;
+ this.entry = entry;
+ this.lastModified = lastModified;
+ byte[] data = entry.getExtra();
+ if (data != null)
+ this.extra = new String(data);
+ }
+
+ public InputStream openInputStream() throws IOException {
+ return zip.getInputStream(entry);
+ }
+
+ public String toString() {
+ return ":" + entry.getName() + ":";
+ }
+
+ public static ZipFile build(Jar jar, File file) throws ZipException,
+ IOException {
+ return build(jar, file, null);
+ }
+
+ public static ZipFile build(Jar jar, File file, Pattern pattern)
+ throws ZipException, IOException {
+
+ try {
+ ZipFile zip = new ZipFile(file);
+ nextEntry: for (Enumeration<? extends ZipEntry> e = zip.entries(); e
+ .hasMoreElements();) {
+ ZipEntry entry = e.nextElement();
+ if (pattern != null) {
+ Matcher m = pattern.matcher(entry.getName());
+ if (!m.matches())
+ continue nextEntry;
+ }
+ if (!entry.isDirectory()) {
+ long time = entry.getTime();
+ if (time <= 0)
+ time = file.lastModified();
+ jar.putResource(entry.getName(), new ZipResource(zip,
+ entry, time), true);
+ }
+ }
+ return zip;
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException("Problem opening JAR: "
+ + file.getAbsolutePath());
+ }
+ }
+
+ public void write(OutputStream out) throws IOException {
+ FileResource.copy(this, out);
+ }
+
+ public long lastModified() {
+ return lastModified;
+ }
+
+ public String getExtra() {
+ return extra;
+ }
+
+ public void setExtra(String extra) {
+ this.extra = extra;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ZipResource.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/eclipse/EclipseClasspath.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/eclipse/EclipseClasspath.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/eclipse/EclipseClasspath.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/eclipse/EclipseClasspath.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,250 @@
+/* Copyright 2006 aQute SARL
+ * Licensed under the Apache License, Version 2.0, see http://www.apache.org/licenses/LICENSE-2.0 */
+package aQute.lib.osgi.eclipse;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import javax.xml.parsers.*;
+
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+import aQute.libg.reporter.*;
+
+/**
+ * Parse the Eclipse project information for the classpath. Unfortunately, it is
+ * impossible to read the variables. They are ignored but that can cause
+ * problems.
+ *
+ * @version $Revision: 1.1 $
+ */
+public class EclipseClasspath {
+ static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
+ .newInstance();
+ DocumentBuilder db;
+ File project;
+ File workspace;
+ Set<File> sources = new LinkedHashSet<File>();
+ Set<File> allSources = new LinkedHashSet<File>();
+
+ Set<File> classpath = new LinkedHashSet<File>();
+ List<File> dependents = new ArrayList<File>();
+ File output;
+ boolean recurse = true;
+ Set<File> exports = new LinkedHashSet<File>();
+ Map<String, String> properties = new HashMap<String, String>();
+ Reporter reporter;
+ int options;
+ Set<File> bootclasspath = new LinkedHashSet<File>();
+
+ public final static int DO_VARIABLES = 1;
+
+ /**
+ * Parse an Eclipse project structure to discover the classpath.
+ *
+ * @param workspace
+ * Points to workspace
+ * @param project
+ * Points to project
+ * @throws ParserConfigurationException
+ * @throws SAXException
+ * @throws IOException
+ */
+
+ public EclipseClasspath(Reporter reporter, File workspace, File project,
+ int options) throws Exception {
+ this.project = project.getCanonicalFile();
+ this.workspace = workspace.getCanonicalFile();
+ this.reporter = reporter;
+ db = documentBuilderFactory.newDocumentBuilder();
+ parse(this.project, true);
+ db = null;
+ }
+
+ public EclipseClasspath(Reporter reporter, File workspace, File project)
+ throws Exception {
+ this(reporter, workspace, project, 0);
+ }
+
+ /**
+ * Recursive routine to parse the files. If a sub project is detected, it is
+ * parsed before the parsing continues. This should give the right order.
+ *
+ * @param project
+ * Project directory
+ * @param top
+ * If this is the top project
+ * @throws ParserConfigurationException
+ * @throws SAXException
+ * @throws IOException
+ */
+ void parse(File project, boolean top) throws ParserConfigurationException,
+ SAXException, IOException {
+ File file = new File(project, ".classpath");
+ if (!file.exists())
+ throw new FileNotFoundException(".classpath file not found: "
+ + file.getAbsolutePath());
+
+ Document doc = db.parse(file);
+ NodeList nodelist = doc.getDocumentElement().getElementsByTagName(
+ "classpathentry");
+
+ if (nodelist == null)
+ throw new IllegalArgumentException(
+ "Can not find classpathentry in classpath file");
+
+ for (int i = 0; i < nodelist.getLength(); i++) {
+ Node node = nodelist.item(i);
+ NamedNodeMap attrs = node.getAttributes();
+ String kind = get(attrs, "kind");
+ if ("src".equals(kind)) {
+ String path = get(attrs, "path");
+ // TODO boolean exported = "true".equalsIgnoreCase(get(attrs,
+ // "exported"));
+ if (path.startsWith("/")) {
+ // We have another project
+ File subProject = getFile(workspace, project, path);
+ if (recurse)
+ parse(subProject, false);
+ dependents.add(subProject.getCanonicalFile());
+ } else {
+ File src = getFile(workspace, project, path);
+ allSources.add(src);
+ if (top) {
+ // We only want the sources for our own project
+ // or we'll compile all at once. Not a good idea
+ // because project settings can differ.
+ sources.add(src);
+ }
+ }
+ } else if ("lib".equals(kind)) {
+ String path = get(attrs, "path");
+ boolean exported = "true".equalsIgnoreCase(get(attrs,
+ "exported"));
+ if (top || exported) {
+ File jar = getFile(workspace, project, path);
+ if (jar.getName().startsWith("ee."))
+ bootclasspath.add(jar);
+ else
+ classpath.add(jar);
+ if (exported)
+ exports.add(jar);
+ }
+ } else if ("output".equals(kind)) {
+ String path = get(attrs, "path");
+ path = path.replace('/', File.separatorChar);
+ output = getFile(workspace, project, path);
+ classpath.add(output);
+ exports.add(output);
+ } else if ("var".equals(kind)) {
+ boolean exported = "true".equalsIgnoreCase(get(attrs,
+ "exported"));
+ File lib = replaceVar(get(attrs, "path"));
+ File slib = replaceVar(get(attrs, "sourcepath"));
+ if (lib != null) {
+ classpath.add(lib);
+ if (exported)
+ exports.add(lib);
+ }
+ if (slib != null)
+ sources.add(slib);
+ } else if ("con".equals(kind)) {
+ // Should do something useful ...
+ }
+ }
+ }
+
+ private File getFile(File abs, File relative, String opath) {
+ String path = opath.replace('/', File.separatorChar);
+ File result = new File(path);
+ if (result.isAbsolute() && result.isFile()) {
+ return result;
+ }
+ if (path.startsWith(File.separator)) {
+ result = abs;
+ path = path.substring(1);
+ } else
+ result = relative;
+
+ StringTokenizer st = new StringTokenizer(path, File.separator);
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken();
+ result = new File(result, token);
+ }
+
+ if (!result.exists())
+ System.err.println("File not found: project=" + project
+ + " workspace=" + workspace + " path=" + opath + " file="
+ + result);
+ return result;
+ }
+
+ static Pattern PATH = Pattern.compile("([A-Z_]+)/(.*)");
+
+ private File replaceVar(String path) {
+ if ((options & DO_VARIABLES) == 0)
+ return null;
+
+ Matcher m = PATH.matcher(path);
+ if (m.matches()) {
+ String var = m.group(1);
+ String remainder = m.group(2);
+ String base = (String) properties.get(var);
+ if (base != null) {
+ File b = new File(base);
+ File f = new File(b, remainder.replace('/', File.separatorChar));
+ return f;
+ } else
+ reporter.error("Can't find replacement variable for: " + path);
+ } else
+ reporter.error("Cant split variable path: " + path);
+ return null;
+ }
+
+ private String get(NamedNodeMap map, String name) {
+ Node node = map.getNamedItem(name);
+ if (node == null)
+ return null;
+
+ return node.getNodeValue();
+ }
+
+ public Set<File> getClasspath() {
+ return classpath;
+ }
+
+ public Set<File> getSourcepath() {
+ return sources;
+ }
+
+ public File getOutput() {
+ return output;
+ }
+
+ public List<File> getDependents() {
+ return dependents;
+ }
+
+ public void setRecurse(boolean recurse) {
+ this.recurse = recurse;
+ }
+
+ public Set<File> getExports() {
+ return exports;
+ }
+
+ public void setProperties(Map<String, String> map) {
+ this.properties = map;
+ }
+
+ public Set<File> getBootclasspath() {
+ return bootclasspath;
+ }
+
+ public Set<File> getAllSources() {
+ return allSources;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/eclipse/EclipseClasspath.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/libg/generics/Create.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/generics/Create.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/generics/Create.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/generics/Create.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,40 @@
+package aQute.libg.generics;
+
+import java.util.*;
+
+public class Create {
+
+ public static <K,V> Map<K, V> map() {
+ return new LinkedHashMap<K,V>();
+ }
+
+ public static <T> List<T> list() {
+ return new ArrayList<T>();
+ }
+
+ public static <T> Set<T> set() {
+ return new HashSet<T>();
+ }
+
+ public static <T> List<T> list(T[] source) {
+ return new ArrayList<T>(Arrays.asList(source));
+ }
+
+ public static <T> Set<T> set(T[]source) {
+ return new HashSet<T>(Arrays.asList(source));
+ }
+
+ public static <K,V> Map<K, V> copy(Map<K,V> source) {
+ return new LinkedHashMap<K,V>(source);
+ }
+
+ public static <T> List<T> copy(List<T> source) {
+ return new ArrayList<T>(source);
+ }
+
+ public static <T> Set<T> copy(Set<T> source) {
+ return new HashSet<T>(source);
+ }
+
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/libg/generics/Create.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/libg/header/OSGiHeader.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/header/OSGiHeader.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/header/OSGiHeader.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/header/OSGiHeader.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,145 @@
+package aQute.libg.header;
+
+import java.util.*;
+
+import aQute.libg.generics.*;
+import aQute.libg.qtokens.*;
+import aQute.libg.reporter.*;
+
+public class OSGiHeader {
+
+ static public Map<String, Map<String, String>> parseHeader(String value) {
+ return parseHeader(value, null);
+ }
+
+ /**
+ * Standard OSGi header parser. This parser can handle the format clauses
+ * ::= clause ( ',' clause ) + clause ::= name ( ';' name ) (';' key '='
+ * value )
+ *
+ * This is mapped to a Map { name => Map { attr|directive => value } }
+ *
+ * @param value
+ * A string
+ * @return a Map<String,Map<String,String>>
+ */
+ static public Map<String, Map<String, String>> parseHeader(String value,
+ Reporter logger) {
+ if (value == null || value.trim().length() == 0)
+ return Create.map();
+
+ Map<String, Map<String, String>> result = Create.map();
+ QuotedTokenizer qt = new QuotedTokenizer(value, ";=,");
+ char del = 0;
+ do {
+ boolean hadAttribute = false;
+ Map<String, String> clause = Create.map();
+ List<String> aliases = Create.list();
+ String name = qt.nextToken(",;");
+
+ del = qt.getSeparator();
+ if (name == null || name.length() == 0) {
+ if (logger != null && logger.isPedantic()) {
+ logger
+ .warning("Empty clause, usually caused by repeating a comma without any name field or by having spaces after the backslash of a property file: "
+ + value);
+ }
+ if (name == null)
+ break;
+ } else {
+ name = name.trim();
+
+ aliases.add(name);
+ while (del == ';') {
+ String adname = qt.nextToken();
+ if ((del = qt.getSeparator()) != '=') {
+ if (hadAttribute)
+ if (logger != null) {
+ logger
+ .error("Header contains name field after attribute or directive: "
+ + adname
+ + " from "
+ + value
+ + ". Name fields must be consecutive, separated by a ';' like a;b;c;x=3;y=4");
+ }
+ if (adname != null && adname.length() > 0)
+ aliases.add(adname.trim());
+ } else {
+ String advalue = qt.nextToken();
+ if (clause.containsKey(adname)) {
+ if (logger != null && logger.isPedantic())
+ logger
+ .warning("Duplicate attribute/directive name "
+ + adname
+ + " in "
+ + value
+ + ". This attribute/directive will be ignored");
+ }
+ if (advalue == null) {
+ if (logger != null)
+ logger
+ .error("No value after '=' sign for attribute "
+ + adname);
+ advalue = "";
+ }
+ clause.put(adname.trim(), advalue.trim());
+ del = qt.getSeparator();
+ hadAttribute = true;
+ }
+ }
+
+ // Check for duplicate names. The aliases list contains
+ // the list of nams, for each check if it exists. If so,
+ // add a number of "~" to make it unique.
+ for (String clauseName : aliases) {
+ if (result.containsKey(clauseName)) {
+ if (logger != null && logger.isPedantic())
+ logger
+ .warning("Duplicate name "
+ + clauseName
+ + " used in header: '"
+ + clauseName
+ + "'. Duplicate names are specially marked in Bnd with a ~ at the end (which is stripped at printing time).");
+ while (result.containsKey(clauseName))
+ clauseName += "~";
+ }
+ result.put(clauseName, clause);
+ }
+ }
+ } while (del == ',');
+ return result;
+ }
+
+ public static Map<String, String> parseProperties(String input) {
+ return parseProperties(input, null);
+ }
+
+ public static Map<String, String> parseProperties(String input, Reporter logger) {
+ if (input == null || input.trim().length() == 0)
+ return Create.map();
+
+ Map<String, String> result = Create.map();
+ QuotedTokenizer qt = new QuotedTokenizer(input, "=,");
+ char del = ',';
+
+ while (del == ',') {
+ String key = qt.nextToken(",=");
+ String value = "";
+ del = qt.getSeparator();
+ if (del == '=') {
+ value = qt.nextToken(",=");
+ del = qt.getSeparator();
+ }
+ result.put(key, value);
+ }
+ if (del != 0)
+ if ( logger == null )
+ throw new IllegalArgumentException(
+ "Invalid syntax for properties: " + input);
+ else
+ logger.error("Invalid syntax for properties: " + input);
+
+ return result;
+ }
+
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/libg/header/OSGiHeader.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,118 @@
+package aQute.libg.qtokens;
+
+import java.util.*;
+
+import aQute.libg.generics.*;
+
+public class QuotedTokenizer {
+ String string;
+ int index = 0;
+ String separators;
+ boolean returnTokens;
+ boolean ignoreWhiteSpace = true;
+ String peek;
+ char separator;
+
+ public QuotedTokenizer(String string, String separators, boolean returnTokens ) {
+ if ( string == null )
+ throw new IllegalArgumentException("string argument must be not null");
+ this.string = string;
+ this.separators = separators;
+ this.returnTokens = returnTokens;
+ }
+ public QuotedTokenizer(String string, String separators) {
+ this(string,separators,false);
+ }
+
+ public String nextToken(String separators) {
+ separator = 0;
+ if ( peek != null ) {
+ String tmp = peek;
+ peek = null;
+ return tmp;
+ }
+
+ if ( index == string.length())
+ return null;
+
+ StringBuffer sb = new StringBuffer();
+
+ while (index < string.length()) {
+ char c = string.charAt(index++);
+
+ if ( Character.isWhitespace(c)) {
+ if ( index == string.length())
+ break;
+ else {
+ sb.append(c);
+ continue;
+ }
+ }
+
+ if (separators.indexOf(c) >= 0) {
+ if (returnTokens)
+ peek = Character.toString(c);
+ else
+ separator = c;
+ break;
+ }
+
+ switch (c) {
+ case '"' :
+ case '\'' :
+ quotedString(sb, c);
+ break;
+
+ default :
+ sb.append(c);
+ }
+ }
+ String result = sb.toString().trim();
+ if ( result.length()==0 && index==string.length())
+ return null;
+ return result;
+ }
+
+ public String nextToken() {
+ return nextToken(separators);
+ }
+
+ private void quotedString(StringBuffer sb, char c) {
+ char quote = c;
+ while (index < string.length()) {
+ c = string.charAt(index++);
+ if (c == quote)
+ break;
+ if (c == '\\' && index < string.length()
+ && string.charAt(index + 1) == quote)
+ c = string.charAt(index++);
+ sb.append(c);
+ }
+ }
+
+ public String[] getTokens() {
+ return getTokens(0);
+ }
+
+ private String [] getTokens(int cnt){
+ String token = nextToken();
+ if ( token == null )
+ return new String[cnt];
+
+ String result[] = getTokens(cnt+1);
+ result[cnt]=token;
+ return result;
+ }
+
+ public char getSeparator() { return separator; }
+
+ public List<String> getTokenSet() {
+ List<String> list = Create.list();
+ String token = nextToken();
+ while ( token != null ) {
+ list.add(token);
+ token = nextToken();
+ }
+ return list;
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/libg/qtokens/QuotedTokenizer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/Reporter.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/Reporter.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/Reporter.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/Reporter.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,15 @@
+package aQute.libg.reporter;
+
+import java.util.*;
+
+
+public interface Reporter {
+ void error(String s, Object ... args);
+ void warning(String s, Object ... args);
+ void progress(String s, Object ... args);
+ void trace(String s, Object ... args);
+ List<String> getWarnings();
+ List<String> getErrors();
+
+ boolean isPedantic();
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/libg/reporter/Reporter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Replacer.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Replacer.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Replacer.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Replacer.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,5 @@
+package aQute.libg.sed;
+
+public interface Replacer {
+ String process(String line);
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Replacer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Sed.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Sed.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Sed.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Sed.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,82 @@
+package aQute.libg.sed;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+public class Sed {
+ final File file;
+ final Replacer macro;
+ File output;
+
+ final Map<Pattern, String> replacements = new LinkedHashMap<Pattern, String>();
+
+ public Sed(Replacer macro, File file) {
+ assert file.isFile();
+ this.file = file;
+ this.macro = macro;
+ }
+
+ public void setOutput(File f) {
+ output = f;
+ }
+
+ public void replace(String pattern, String replacement) {
+ replacements.put(Pattern.compile(pattern), replacement);
+ }
+
+ public void doIt() throws IOException {
+ BufferedReader brdr = new BufferedReader(new FileReader(file));
+ File out;
+ if (output != null)
+ out = output;
+ else
+ out = new File(file.getAbsolutePath() + ".tmp");
+ File bak = new File(file.getAbsolutePath() + ".bak");
+ PrintWriter pw = new PrintWriter(new FileWriter(out));
+ try {
+ String line;
+ while ((line = brdr.readLine()) != null) {
+ for (Pattern p : replacements.keySet()) {
+ String replace = replacements.get(p);
+ Matcher m = p.matcher(line);
+
+ StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ String tmp = setReferences(m, replace);
+ tmp = macro.process(tmp);
+ m.appendReplacement(sb, Matcher.quoteReplacement(tmp));
+ }
+ m.appendTail(sb);
+
+ line = sb.toString();
+ }
+ pw.println(line);
+ }
+ pw.close();
+ if (output == null) {
+ file.renameTo(bak);
+ out.renameTo(file);
+ }
+ } finally {
+ brdr.close();
+ pw.close();
+ }
+ }
+
+ private String setReferences(Matcher m, String replace) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < replace.length(); i++) {
+ char c = replace.charAt(i);
+ if (c == '$' && i < replace.length() - 1
+ && Character.isDigit(replace.charAt(i + 1))) {
+ int n = replace.charAt(i + 1) - '0';
+ if ( n <= m.groupCount() )
+ sb.append(m.group(n));
+ i++;
+ } else
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/libg/sed/Sed.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/libg/version/Version.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/version/Version.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/version/Version.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/version/Version.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,148 @@
+package aQute.libg.version;
+
+import java.util.regex.*;
+
+public class Version implements Comparable<Version> {
+ final int major;
+ final int minor;
+ final int micro;
+ final String qualifier;
+ public final static String VERSION_STRING = "(\\d+)(\\.(\\d+)(\\.(\\d+)(\\.([-_\\da-zA-Z]+))?)?)?";
+ public final static Pattern VERSION = Pattern
+ .compile(VERSION_STRING);
+ public final static Version LOWEST = new Version();
+ public final static Version HIGHEST = new Version(Integer.MAX_VALUE,
+ Integer.MAX_VALUE,
+ Integer.MAX_VALUE,
+ "\uFFFF");
+
+ public Version() {
+ this(0);
+ }
+
+ public Version(int major, int minor, int micro, String qualifier) {
+ this.major = major;
+ this.minor = minor;
+ this.micro = micro;
+ this.qualifier = qualifier;
+ }
+
+ public Version(int major, int minor, int micro) {
+ this(major, minor, micro, null);
+ }
+
+ public Version(int major, int minor) {
+ this(major, minor, 0, null);
+ }
+
+ public Version(int major) {
+ this(major, 0, 0, null);
+ }
+
+ public Version(String version) {
+ Matcher m = VERSION.matcher(version);
+ if (!m.matches())
+ throw new IllegalArgumentException("Invalid syntax for version: "
+ + version);
+
+ major = Integer.parseInt(m.group(1));
+ if (m.group(3) != null)
+ minor = Integer.parseInt(m.group(3));
+ else
+ minor = 0;
+
+ if (m.group(5) != null)
+ micro = Integer.parseInt(m.group(5));
+ else
+ micro = 0;
+
+ qualifier = m.group(7);
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public int getMicro() {
+ return micro;
+ }
+
+ public String getQualifier() {
+ return qualifier;
+ }
+
+ public int compareTo(Version other) {
+ if (other == this)
+ return 0;
+
+ if (!(other instanceof Version))
+ throw new IllegalArgumentException(
+ "Can only compare versions to versions");
+
+ Version o = (Version) other;
+ if (major != o.major)
+ return major - o.major;
+
+ if (minor != o.minor)
+ return minor - o.minor;
+
+ if (micro != o.micro)
+ return micro - o.micro;
+
+ int c = 0;
+ if (qualifier != null)
+ c = 1;
+ if (o.qualifier != null)
+ c += 2;
+
+ switch (c) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ return -1;
+ }
+ return qualifier.compareTo(o.qualifier);
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(major);
+ sb.append(".");
+ sb.append(minor);
+ sb.append(".");
+ sb.append(micro);
+ if (qualifier != null) {
+ sb.append(".");
+ sb.append(qualifier);
+ }
+ return sb.toString();
+ }
+
+ public boolean equals(Object ot) {
+ if ( ! (ot instanceof Version))
+ return false;
+
+ return compareTo((Version)ot) == 0;
+ }
+
+ public int hashCode() {
+ return major * 97 ^ minor * 13 ^ micro
+ + (qualifier == null ? 97 : qualifier.hashCode());
+ }
+
+ public int get(int i) {
+ switch(i) {
+ case 0 : return major;
+ case 1 : return minor;
+ case 2 : return micro;
+ default:
+ throw new IllegalArgumentException("Version can only get 0 (major), 1 (minor), or 2 (micro)");
+ }
+ }
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/libg/version/Version.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/libg/version/VersionRange.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/libg/version/VersionRange.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/libg/version/VersionRange.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/libg/version/VersionRange.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,85 @@
+package aQute.libg.version;
+
+import java.util.regex.*;
+
+public class VersionRange {
+ Version high;
+ Version low;
+ char start = '[';
+ char end = ']';
+
+ static Pattern RANGE = Pattern.compile("(\\(|\\[)\\s*(" +
+ Version.VERSION_STRING + ")\\s*,\\s*(" +
+ Version.VERSION_STRING + ")\\s*(\\)|\\])");
+
+ public VersionRange(String string) {
+ string = string.trim();
+ Matcher m = RANGE.matcher(string);
+ if (m.matches()) {
+ start = m.group(1).charAt(0);
+ String v1 = m.group(2);
+ String v2 = m.group(10);
+ low = new Version(v1);
+ high = new Version(v2);
+ end = m.group(18).charAt(0);
+ if (low.compareTo(high) > 0)
+ throw new IllegalArgumentException(
+ "Low Range is higher than High Range: " + low + "-" +
+ high);
+
+ } else
+ high = low = new Version(string);
+ }
+
+ public boolean isRange() {
+ return high != low;
+ }
+
+ public boolean includeLow() {
+ return start == '[';
+ }
+
+ public boolean includeHigh() {
+ return end == ']';
+ }
+
+ public String toString() {
+ if (high == low)
+ return high.toString();
+
+ StringBuffer sb = new StringBuffer();
+ sb.append(start);
+ sb.append(low);
+ sb.append(',');
+ sb.append(high);
+ sb.append(end);
+ return sb.toString();
+ }
+
+ public Version getLow() {
+ return low;
+ }
+
+ public Version getHigh() {
+ return high;
+ }
+
+ public boolean includes(Version v) {
+ if ( !isRange() ) {
+ return low.compareTo(v) <=0;
+ }
+ if (includeLow()) {
+ if (v.compareTo(low) < 0)
+ return false;
+ } else if (v.compareTo(low) <= 0)
+ return false;
+
+ if (includeHigh()) {
+ if (v.compareTo(high) > 0)
+ return false;
+ } else if (v.compareTo(high) >= 0)
+ return false;
+
+ return true;
+ }
+}
\ No newline at end of file
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/libg/version/VersionRange.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: felix/trunk/bundleplugin/src/main/java/aQute/scripting/Scripter.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/scripting/Scripter.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/scripting/Scripter.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/scripting/Scripter.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,12 @@
+package aQute.service.scripting;
+
+import java.io.Reader;
+import java.util.Map;
+
+public abstract interface Scripter
+{
+ public static final String MIME_TYPE = "mime.type";
+
+ public abstract Object eval(Map<String, Object> paramMap, Reader paramReader)
+ throws Exception;
+}
Propchange: felix/trunk/bundleplugin/src/main/java/aQute/scripting/Scripter.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundleAllPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundleAllPlugin.java?rev=793527&r1=793526&r2=793527&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundleAllPlugin.java (original)
+++ felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundleAllPlugin.java Mon Jul 13 10:06:47 2009
@@ -24,9 +24,9 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -338,7 +338,7 @@
try
{
- Map instructions = new HashMap();
+ Map instructions = new LinkedHashMap();
instructions.put( Analyzer.IMPORT_PACKAGE, wrapImportPackage );
project.getArtifact().setFile( getFile( artifact ) );
Modified: felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java?rev=793527&r1=793526&r2=793527&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java (original)
+++ felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/BundlePlugin.java Mon Jul 13 10:06:47 2009
@@ -30,9 +30,9 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -167,7 +167,7 @@
*
* @parameter
*/
- private Map instructions = new HashMap();
+ private Map instructions = new LinkedHashMap();
/**
* Use locally patched version for now.
@@ -245,7 +245,7 @@
/* transform directives from their XML form to the expected BND syntax (eg. _include becomes -include) */
protected static Map transformDirectives( Map originalInstructions )
{
- Map transformedInstructions = new HashMap();
+ Map transformedInstructions = new LinkedHashMap();
for ( Iterator i = originalInstructions.entrySet().iterator(); i.hasNext(); )
{
Map.Entry e = ( Map.Entry ) i.next();
@@ -638,7 +638,7 @@
private static Map getProperties( Model projectModel, String prefix )
{
- Map properties = new HashMap();
+ Map properties = new LinkedHashMap();
Method methods[] = Model.class.getDeclaredMethods();
for ( int i = 0; i < methods.length; i++ )
{
@@ -759,7 +759,7 @@
return Collections.EMPTY_LIST;
}
- Collection selectedDependencies = new HashSet( artifacts );
+ Collection selectedDependencies = new LinkedHashSet( artifacts );
DependencyExcluder excluder = new DependencyExcluder( artifacts );
excluder.processHeaders( excludeDependencies );
selectedDependencies.removeAll( excluder.getExcludedArtifacts() );
@@ -905,7 +905,7 @@
private static void addLocalPackages( String sourceDirectory, Analyzer analyzer )
{
- Collection packages = new HashSet();
+ Collection packages = new LinkedHashSet();
if ( sourceDirectory != null && new File( sourceDirectory ).isDirectory() )
{
Modified: felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/DependencyEmbedder.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/DependencyEmbedder.java?rev=793527&r1=793526&r2=793527&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/DependencyEmbedder.java (original)
+++ felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/DependencyEmbedder.java Mon Jul 13 10:06:47 2009
@@ -21,8 +21,8 @@
import java.io.File;
import java.util.Collection;
-import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.Map;
import org.apache.maven.artifact.Artifact;
@@ -67,8 +67,8 @@
{
super( dependencyArtifacts );
- m_inlinedPaths = new HashSet();
- m_embeddedArtifacts = new HashSet();
+ m_inlinedPaths = new LinkedHashSet();
+ m_embeddedArtifacts = new LinkedHashSet();
}
Modified: felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/ManifestPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/ManifestPlugin.java?rev=793527&r1=793526&r2=793527&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/ManifestPlugin.java (original)
+++ felix/trunk/bundleplugin/src/main/java/org/apache/felix/bundleplugin/ManifestPlugin.java Mon Jul 13 10:06:47 2009
@@ -24,8 +24,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -145,7 +145,7 @@
protected Analyzer getAnalyzer( MavenProject project, Jar[] classpath ) throws IOException, MojoExecutionException
{
- return getAnalyzer( project, new HashMap(), new Properties(), classpath );
+ return getAnalyzer( project, new LinkedHashMap(), new Properties(), classpath );
}