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 [4/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/Builder.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Builder.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Builder.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Builder.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,1135 @@
+/* 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 java.util.zip.*;
+
+import aQute.bnd.make.*;
+import aQute.bnd.service.*;
+
+/**
+ * Include-Resource: ( [name '=' ] file )+
+ * 
+ * Private-Package: package-decl ( ',' package-decl )*
+ * 
+ * Export-Package: package-decl ( ',' package-decl )*
+ * 
+ * Import-Package: package-decl ( ',' package-decl )*
+ * 
+ * @version $Revision: 1.17 $
+ */
+public class Builder extends Analyzer {
+    private static final int SPLIT_MERGE_LAST  = 1;
+    private static final int SPLIT_MERGE_FIRST = 2;
+    private static final int SPLIT_ERROR       = 3;
+    private static final int SPLIT_FIRST       = 4;
+    private static final int SPLIT_DEFAULT     = 0;
+
+    private static final File[] EMPTY_FILE = new File[0];
+    
+    List<File>               sourcePath        = new ArrayList<File>();
+    Pattern                  NAME_URL          = Pattern
+                                                       .compile("(.*)(http://.*)");
+
+    Make                     make              = new Make(this);
+
+    public Builder(Processor parent) {
+        super(parent);
+    }
+
+    public Builder() {
+    }
+
+    public Jar build() throws Exception {
+        if (getProperty(NOPE) != null)
+            return null;
+
+        String sub = getProperty(SUB);
+        if (sub != null && sub.trim().length() > 0)
+            error("Specified "
+                    + SUB
+                    + " but calls build() instead of builds() (might be a programmer error)");
+
+        if (getProperty(CONDUIT) != null)
+            error("Specified "
+                    + CONDUIT
+                    + " but calls build() instead of builds() (might be a programmer error");
+
+        dot = new Jar("dot");
+        addClose(dot);
+        try {
+            long modified = Long.parseLong(getProperty("base.modified"));
+            dot.updateModified(modified, "Base modified");
+        } catch (Exception e) {
+        }
+
+        doExpand(dot);
+        doIncludeResources(dot);
+
+        doConditional(dot);
+
+        // NEW!
+        // Check if we override the calculation of the
+        // manifest. We still need to calculated it because
+        // we need to have analyzed the classpath.
+
+        Manifest manifest = calcManifest();
+
+        String mf = getProperty(MANIFEST);
+        if (mf != null) {
+            File mff = getFile(mf);
+            if (mff.isFile()) {
+                try {
+                    InputStream in = new FileInputStream(mff);
+                    manifest = new Manifest(in);
+                    in.close();
+                } catch (Exception e) {
+                    error(MANIFEST + " while reading manifest file", e);
+                }
+            } else {
+                error(MANIFEST + ", no such file " + mf);
+            }
+        }
+
+        if (getProperty(NOMANIFEST) == null)
+            dot.setManifest(manifest);
+        else
+            dot.setNoManifest(true);
+
+        // This must happen after we analyzed so
+        // we know what it is on the classpath
+        addSources(dot);
+        if (getProperty(POM) != null)
+            doPom(dot);
+
+        doVerify(dot);
+
+        if (dot.getResources().isEmpty())
+            error("The JAR is empty");
+
+        dot.updateModified(lastModified(), "Last Modified Processor");
+        dot.setName(getBsn());
+
+        sign(dot);
+        return dot;
+    }
+
+    /**
+     * Sign the jar file.
+     * 
+     * -sign : <alias> [ ';' 'password:=' <password> ] [ ';' 'keystore:='
+     * <keystore> ] [ ';' 'sign-password:=' <pw> ] ( ',' ... )*
+     * 
+     * @return
+     */
+
+    void sign(Jar jar) throws Exception {
+        String signing = getProperty("-sign");
+        if (signing == null)
+            return;
+
+        trace("Signing %s, with %s", getBsn(), signing);
+        List<SignerPlugin> signers = getPlugins(SignerPlugin.class);
+
+        Map<String, Map<String, String>> infos = parseHeader(signing);
+        for (Map.Entry<String, Map<String, String>> entry : infos.entrySet()) {
+            for (SignerPlugin signer : signers) {
+                signer.sign(this, entry.getKey());
+            }
+        }
+    }
+
+    public boolean hasSources() {
+        return isTrue(getProperty(SOURCES));
+    }
+
+    protected String getImportPackages() {
+        String ip = super.getImportPackages();
+        if (ip != null)
+            return ip;
+
+        return "*";
+    }
+
+    private void doConditional(Jar dot) throws IOException {
+        Map<String, Map<String, String>> conditionals = getHeader(CONDITIONAL_PACKAGE);
+        int size;
+        do {
+            size = dot.getDirectories().size();
+            analyze();
+            analyzed = false;
+            Map<String, Map<String, String>> imports = getImports();
+
+            // Match the packages specified in conditionals
+            // against the imports. Any match must become a
+            // Private-Package
+            Map<String, Map<String, String>> filtered = merge(
+                    CONDITIONAL_PACKAGE, conditionals, imports,
+                    new HashSet<String>(), null);
+
+            // Imports can also specify a private import. These
+            // packages must also be copied to the bundle
+            for (Map.Entry<String, Map<String, String>> entry : getImports()
+                    .entrySet()) {
+                String type = entry.getValue().get(IMPORT_DIRECTIVE);
+                if (type != null && type.equals("private"))
+                    filtered.put(entry.getKey(), entry.getValue());
+            }
+
+            // remove existing packages to prevent merge errors
+            filtered.keySet().removeAll(dot.getPackages());
+            doExpand(dot, CONDITIONAL_PACKAGE + " Private imports",
+                    replaceWitInstruction(filtered, CONDITIONAL_PACKAGE), false);
+        } while (dot.getDirectories().size() > size);
+        analyzed = true;
+    }
+
+    /**
+     * Intercept the call to analyze and cleanup versions after we have analyzed
+     * the setup. We do not want to cleanup if we are going to verify.
+     */
+
+    public void analyze() throws IOException {
+        super.analyze();
+        cleanupVersion(imports);
+        cleanupVersion(exports);
+        String version = getProperty(BUNDLE_VERSION);
+        if (version != null)
+            setProperty(BUNDLE_VERSION, cleanupVersion(version));
+    }
+
+    public void cleanupVersion(Map<String, Map<String, String>> mapOfMap) {
+        for (Iterator<Map.Entry<String, Map<String, String>>> e = mapOfMap
+                .entrySet().iterator(); e.hasNext();) {
+            Map.Entry<String, Map<String, String>> entry = e.next();
+            Map<String, String> attributes = entry.getValue();
+            if (attributes.containsKey("version")) {
+                attributes.put("version", cleanupVersion(attributes
+                        .get("version")));
+            }
+        }
+    }
+
+    /**
+     * 
+     */
+    private void addSources(Jar dot) {
+        if (!hasSources())
+            return;
+
+        Set<String> packages = new HashSet<String>();
+
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            getProperties().store(out, "Generated by BND, at " + new Date());
+            dot.putResource("OSGI-OPT/bnd.bnd", new EmbeddedResource(out
+                    .toByteArray(), 0));
+            out.close();
+        } catch (Exception e) {
+            error("Can not embed bnd file in JAR: " + e);
+        }
+
+        for (Iterator<String> cpe = classspace.keySet().iterator(); cpe
+                .hasNext();) {
+            String path = cpe.next();
+            path = path.substring(0, path.length() - ".class".length())
+                    + ".java";
+            String pack = getPackage(path).replace('.', '/');
+            if (pack.length() > 1)
+                pack = pack + "/";
+            boolean found = false;
+            String[] fixed = { "packageinfo", "package.html",
+                    "module-info.java", "package-info.java" };
+            for (Iterator<File> i = getSourcePath().iterator(); i.hasNext();) {
+                File root = i.next();
+                File f = getFile(root, path);
+                if (f.exists()) {
+                    found = true;
+                    if (!packages.contains(pack)) {
+                        packages.add(pack);
+                        File bdir = getFile(root, pack);
+                        for (int j = 0; j < fixed.length; j++) {
+                            File ff = getFile(bdir, fixed[j]);
+                            if (ff.isFile()) {
+                                dot.putResource("OSGI-OPT/src/" + pack
+                                        + fixed[j], new FileResource(ff));
+                            }
+                        }
+                    }
+                    dot
+                            .putResource("OSGI-OPT/src/" + path,
+                                    new FileResource(f));
+                }
+            }
+            if (!found) {
+                for (Jar jar : classpath) {
+                    Resource resource = jar.getResource(path);
+                    if (resource != null) {
+                        dot.putResource("OSGI-OPT/src", resource);
+                    } else {
+                        resource = jar.getResource("OSGI-OPT/src/" + path);
+                        if (resource != null) {
+                            dot.putResource("OSGI-OPT/src", resource);
+                        }
+                    }
+                }
+            }
+            if (getSourcePath().isEmpty())
+                warning("Including sources but " + SOURCEPATH
+                        + " does not contain any source directories ");
+            // TODO copy from the jars where they came from
+        }
+    }
+
+    boolean firstUse = true;
+
+    public Collection<File> getSourcePath() {
+        if (firstUse) {
+            firstUse = false;
+            String sp = getProperty(SOURCEPATH);
+            if (sp != null) {
+                Map<String, Map<String, String>> map = parseHeader(sp);
+                for (Iterator<String> i = map.keySet().iterator(); i.hasNext();) {
+                    String file = i.next();
+                    if (!isDuplicate(file)) {
+                        File f = getFile(file);
+                        if (!f.isDirectory()) {
+                            error("Adding a sourcepath that is not a directory: "
+                                    + f);
+                        } else {
+                            sourcePath.add(f);
+                        }
+                    }
+                }
+            }
+        }
+        return sourcePath;
+    }
+
+    private void doVerify(Jar dot) throws Exception {
+        Verifier verifier = new Verifier(dot, getProperties());
+        verifier.setPedantic(isPedantic());
+
+        // Give the verifier the benefit of our analysis
+        // prevents parsing the files twice
+        verifier.setClassSpace(classspace, contained, referred, uses);
+        verifier.verify();
+        getInfo(verifier);
+    }
+
+    private void doExpand(Jar jar) throws IOException {
+        if (getClasspath().size() == 0
+                && (getProperty(EXPORT_PACKAGE) != null || getProperty(PRIVATE_PACKAGE) != null))
+            warning("Classpath is empty. Private-Package and Export-Package can only expand from the classpath when there is one");
+
+        Map<Instruction, Map<String, String>> privateMap = replaceWitInstruction(
+                getHeader(PRIVATE_PACKAGE), PRIVATE_PACKAGE);
+        Map<Instruction, Map<String, String>> exportMap = replaceWitInstruction(
+                getHeader(EXPORT_PACKAGE), EXPORT_PACKAGE);
+
+        if (isTrue(getProperty(Constants.UNDERTEST))) {
+            privateMap.putAll(replaceWitInstruction(parseHeader(getProperty(
+                    Constants.TESTPACKAGES, "test;presence:=optional")),
+                    TESTPACKAGES));
+        }
+        if (!privateMap.isEmpty())
+            doExpand(jar, "Private-Package, or -testpackages", privateMap, true);
+
+        if (!exportMap.isEmpty()) {
+            Jar exports = new Jar("exports");
+            doExpand(exports, "Export-Package", exportMap, true);
+            jar.addAll(exports);
+            exports.close();
+        }
+
+        if (privateMap.isEmpty() && exportMap.isEmpty() && !isResourceOnly()) {
+            warning("Neither Export-Package, Private-Package, -testpackages is set, therefore no packages will be included");
+        }
+    }
+
+    /**
+     * 
+     * @param jar
+     * @param name
+     * @param instructions
+     */
+    private void doExpand(Jar jar, String name,
+            Map<Instruction, Map<String, String>> instructions,
+            boolean mandatory) {
+        Set<Instruction> superfluous = removeMarkedDuplicates(instructions
+                .keySet());
+
+        for (Iterator<Jar> c = getClasspath().iterator(); c.hasNext();) {
+            Jar now = c.next();
+            doExpand(jar, instructions, now, superfluous);
+        }
+
+        if (mandatory && superfluous.size() > 0) {
+            StringBuffer sb = new StringBuffer();
+            String del = "Instructions in " + name + " that are never used: ";
+            for (Iterator<Instruction> i = superfluous.iterator(); i.hasNext();) {
+                Instruction p = i.next();
+                sb.append(del);
+                sb.append(p.getPattern());
+                del = ", ";
+            }
+            warning(sb.toString());
+        }
+    }
+
+    /**
+     * Iterate over each directory in the class path entry and check if that
+     * directory is a desired package.
+     * 
+     * @param included
+     * @param classpathEntry
+     */
+    private void doExpand(Jar jar,
+            Map<Instruction, Map<String, String>> included, Jar classpathEntry,
+            Set<Instruction> superfluous) {
+
+        loop: for (Map.Entry<String, Map<String, Resource>> directory : classpathEntry
+                .getDirectories().entrySet()) {
+            String path = directory.getKey();
+
+            if (doNotCopy.matcher(getName(path)).matches())
+                continue;
+
+            if (directory.getValue() == null)
+                continue;
+
+            String pack = path.replace('/', '.');
+            Instruction instr = matches(included, pack, superfluous);
+            if (instr != null) {
+                // System.out.println("Pattern match: " + pack + " " +
+                // instr.getPattern() + " " + instr.isNegated());
+                if (!instr.isNegated()) {
+                    Map<String, Resource> contents = directory.getValue();
+
+                    // What to do with split packages? Well if this
+                    // directory already exists, we will check the strategy
+                    // and react accordingly.
+                    boolean overwriteResource = true;
+                    if (jar.hasDirectory(path)) {
+                        Map<String, String> directives = included.get(instr);
+
+                        switch (getSplitStrategy((String) directives
+                                .get(SPLIT_PACKAGE_DIRECTIVE))) {
+                        case SPLIT_MERGE_LAST:
+                            overwriteResource = true;
+                            break;
+
+                        case SPLIT_MERGE_FIRST:
+                            overwriteResource = false;
+                            break;
+
+                        case SPLIT_ERROR:
+                            error(diagnostic(pack, getClasspath(),
+                                    classpathEntry.source));
+                            continue loop;
+
+                        case SPLIT_FIRST:
+                            continue loop;
+
+                        default:
+                            warning(diagnostic(pack, getClasspath(),
+                                    classpathEntry.source));
+                            overwriteResource = false;
+                            break;
+                        }
+                    }
+
+                    jar.addDirectory(contents, overwriteResource);
+
+                    String key = path + "/bnd.info";
+                    Resource r = jar.getResource(key);
+                    if (r != null)
+                        jar.putResource(key, new PreprocessResource(this, r));
+
+                    if (hasSources()) {
+                        String srcPath = "OSGI-OPT/src/" + path;
+                        Map<String, Resource> srcContents = classpathEntry
+                                .getDirectories().get(srcPath);
+                        if (srcContents != null) {
+                            jar.addDirectory(srcContents, overwriteResource);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Analyze the classpath for a split package
+     * 
+     * @param pack
+     * @param classpath
+     * @param source
+     * @return
+     */
+    private String diagnostic(String pack, List<Jar> classpath, File source) {
+        // Default is like merge-first, but with a warning
+        // Find the culprits
+        pack = pack.replace('.', '/');
+        List<Jar> culprits = new ArrayList<Jar>();
+        for (Iterator<Jar> i = classpath.iterator(); i.hasNext();) {
+            Jar culprit = (Jar) i.next();
+            if (culprit.getDirectories().containsKey(pack)) {
+                culprits.add(culprit);
+            }
+        }
+        return "Split package "
+                + pack
+                + "\nUse directive -split-package:=(merge-first|merge-last|error|first) on Export/Private Package instruction to get rid of this warning\n"
+                + "Package found in   " + culprits + "\n"
+                + "Reference from     " + source + "\n" + "Classpath          "
+                + classpath;
+    }
+
+    private int getSplitStrategy(String type) {
+        if (type == null)
+            return SPLIT_DEFAULT;
+
+        if (type.equals("merge-last"))
+            return SPLIT_MERGE_LAST;
+
+        if (type.equals("merge-first"))
+            return SPLIT_MERGE_FIRST;
+
+        if (type.equals("error"))
+            return SPLIT_ERROR;
+
+        if (type.equals("first"))
+            return SPLIT_FIRST;
+
+        error("Invalid strategy for split-package: " + type);
+        return SPLIT_DEFAULT;
+    }
+
+    private Map<Instruction, Map<String, String>> replaceWitInstruction(
+            Map<String, Map<String, String>> header, String type) {
+        Map<Instruction, Map<String, String>> map = newMap();
+        for (Iterator<Map.Entry<String, Map<String, String>>> e = header
+                .entrySet().iterator(); e.hasNext();) {
+            Map.Entry<String, Map<String, String>> entry = e.next();
+            String pattern = entry.getKey();
+            Instruction instr = Instruction.getPattern(pattern);
+            String presence = entry.getValue().get(PRESENCE_DIRECTIVE);
+            if ("optional".equals(presence))
+                instr.setOptional();
+            map.put(instr, entry.getValue());
+        }
+        return map;
+    }
+
+    private Instruction matches(
+            Map<Instruction, Map<String, String>> instructions, String pack,
+            Set<Instruction> superfluousPatterns) {
+        for (Instruction pattern : instructions.keySet()) {
+            if (pattern.matches(pack)) {
+                superfluousPatterns.remove(pattern);
+                return pattern;
+            }
+        }
+        return null;
+    }
+
+    private Map<String, Map<String, String>> getHeader(String string) {
+        if (string == null)
+            return Collections.emptyMap();
+        return parseHeader(getProperty(string));
+    }
+
+    /**
+     * Parse the Bundle-Includes header. Files in the bundles Include header are
+     * included in the jar. The source can be a directory or a file.
+     * 
+     * @throws IOException
+     * @throws FileNotFoundException
+     */
+    private void doIncludeResources(Jar jar) throws Exception {
+        String includes = getProperty("Bundle-Includes");
+        if (includes == null) {
+            includes = getProperty(INCLUDERESOURCE);
+            if (includes == null)
+                includes = getProperty("Include-Resource");
+        } else
+            warning("Please use -includeresource instead of Bundle-Includes");
+
+        if (includes == null)
+            return;
+
+        Map<String, Map<String, String>> clauses = parseHeader(includes);
+
+        for (Iterator<Map.Entry<String, Map<String, String>>> i = clauses
+                .entrySet().iterator(); i.hasNext();) {
+            Map.Entry<String, Map<String, String>> entry = i.next();
+            doIncludeResource(jar, entry.getKey(), entry.getValue());
+        }
+    }
+
+    private void doIncludeResource(Jar jar, String name,
+            Map<String, String> extra) throws ZipException, IOException,
+            Exception {
+        boolean preprocess = false;
+        if (name.startsWith("{") && name.endsWith("}")) {
+            preprocess = true;
+            name = name.substring(1, name.length() - 1).trim();
+        }
+
+        if (name.startsWith("@")) {
+            extractFromJar(jar, name.substring(1));
+        } else
+        /*
+         * NEW
+         */
+        if (extra.containsKey("literal")) {
+            String literal = (String) extra.get("literal");
+            Resource r = new EmbeddedResource(literal.getBytes("UTF-8"), 0);
+            String x = (String) extra.get("extra");
+            if (x != null)
+                r.setExtra(x);
+            jar.putResource(name, r);
+        } else {
+            String source;
+            File sourceFile;
+            String destinationPath;
+
+            String parts[] = name.split("\\s*=\\s*");
+            if (parts.length == 1) {
+                // Just a copy, destination path defined by
+                // source path.
+                source = parts[0];
+                sourceFile = getFile(source);
+                // Directories should be copied to the root
+                // but files to their file name ...
+                if (sourceFile.isDirectory())
+                    destinationPath = "";
+                else
+                    destinationPath = sourceFile.getName();
+            } else {
+                source = parts[1];
+                sourceFile = getFile(source);
+                destinationPath = parts[0];
+                
+                // Handle directives
+                if (sourceFile.isDirectory()) {
+                	String filter = extra.get("filter:");
+            		boolean flatten = isTrue(extra.get("flatten:"));
+            		boolean recursive = true; 
+            		String directive = extra.get("recursive:");
+            		if (directive != null) {
+            			recursive = isTrue(directive);
+            		}
+
+            		InstructionFilter iFilter = null;
+            		if (filter != null) {
+            			iFilter = new InstructionFilter(Instruction.getPattern(filter), recursive);
+            		} else {
+            			iFilter = new InstructionFilter(null, recursive);
+            		}
+                    
+            		destinationPath = checkDestinationPath(destinationPath);
+
+            		File[] files = resolveFiles(sourceFile, iFilter, recursive);
+            		for (File file : files) {
+            			String dp;
+            			if (flatten) {
+	            			if (destinationPath.length() == 0) {
+	            				dp = file.getName();
+	            			} else {
+	                			dp = destinationPath + File.separator + file.getName();
+	            			}
+            			} else {
+            				dp = destinationPath + file.getParentFile().getAbsolutePath().substring(sourceFile.getAbsolutePath().length());
+            				if (dp.length() > 0) {
+            					dp += File.separator + file.getName();
+            				} else {
+            					dp = file.getName();
+            				}
+            			} 
+        				copy(jar, dp, file, preprocess, extra);
+            		}
+            		return;
+                }
+            }
+        	
+            destinationPath = checkDestinationPath(destinationPath);
+
+            if (!sourceFile.exists()) {
+                noSuchFile(jar, name, extra, source, destinationPath);
+            } else
+                copy(jar, destinationPath, sourceFile, preprocess, extra);
+         }
+    }
+    
+    private String checkDestinationPath(String destinationPath) {
+        
+    	// Some people insist on ending a directory with
+        // a slash ... it now also works if you do /=dir
+        if (destinationPath.endsWith("/"))
+            destinationPath = destinationPath.substring(0, destinationPath
+                    .length() - 1);
+        return destinationPath;
+    }
+    
+    private File[] resolveFiles(File dir, FileFilter filter, boolean recursive) {
+    	return resolveFiles(dir, filter, null, recursive);
+    }
+
+    private File[] resolveFiles(File dir, FileFilter filter,  File[] files, boolean recursive) {
+    	if (files == null) {
+    		files = EMPTY_FILE;
+    	}
+    	
+    	if (Analyzer.doNotCopy.matcher(dir.getName()).matches()) {
+    		return files;
+    	}
+    	
+    	File[] fs = dir.listFiles(filter);
+    	for (File file : fs) {
+    		if (file.isDirectory()) {
+    			if (recursive) {
+	    			files = resolveFiles(file, filter, files, recursive);
+    			}
+    		} else {
+				if (files.length == 0) {
+					files = new File[] { file };
+				} else {
+					File[] newFiles = new File[files.length + 1];
+					System.arraycopy(files, 0, newFiles, 0, files.length);
+					newFiles[newFiles.length - 1] = file;
+					files = newFiles;
+				}
+    		}
+    	}
+    	return files;
+    }
+
+    private void noSuchFile(Jar jar, String clause, Map<String, String> extra,
+            String source, String destinationPath) throws Exception {
+        Jar src = getJarFromName(source, "Include-Resource " + source);
+        if (src != null) {
+            JarResource jarResource = new JarResource(src);
+            jar.putResource(destinationPath, jarResource);
+        } else {
+            Resource lastChance = make.process(source);
+            if (lastChance != null) {
+                String x = extra.get("extra");
+                if ( x != null )
+                    lastChance.setExtra(x);
+                jar.putResource(destinationPath, lastChance);
+            } else
+                error("Input file does not exist: " + source);
+        }
+    }
+
+    /**
+     * Extra resources from a Jar and add them to the given jar. The clause is
+     * the
+     * 
+     * @param jar
+     * @param clauses
+     * @param i
+     * @throws ZipException
+     * @throws IOException
+     */
+    private void extractFromJar(Jar jar, String name) throws ZipException,
+            IOException {
+        // Inline all resources and classes from another jar
+        // optionally appended with a modified regular expression
+        // like @zip.jar!/META-INF/MANIFEST.MF
+        int n = name.lastIndexOf("!/");
+        Pattern filter = null;
+        if (n > 0) {
+            String fstring = name.substring(n + 2);
+            name = name.substring(0, n);
+            filter = wildcard(fstring);
+        }
+        Jar sub = getJarFromName(name, "extract from jar");
+        if (sub == null)
+            error("Can not find JAR file " + name);
+        else
+            jar.addAll(sub, filter);
+    }
+
+    private Pattern wildcard(String spec) {
+        StringBuffer sb = new StringBuffer();
+        for (int j = 0; j < spec.length(); j++) {
+            char c = spec.charAt(j);
+            switch (c) {
+            case '.':
+                sb.append("\\.");
+                break;
+
+            case '*':
+                // test for ** (all directories)
+                if (j < spec.length() - 1 && spec.charAt(j + 1) == '*') {
+                    sb.append(".*");
+                    j++;
+                } else
+                    sb.append("[^/]*");
+                break;
+            default:
+                sb.append(c);
+                break;
+            }
+        }
+        String s = sb.toString();
+        try {
+            return Pattern.compile(s);
+        } catch (Exception e) {
+            error("Invalid regular expression on wildcarding: " + spec
+                    + " used *");
+        }
+        return null;
+    }
+
+    private void copy(Jar jar, String path, File from, boolean preprocess,
+            Map<String, String> extra) throws Exception {
+        if (doNotCopy.matcher(from.getName()).matches())
+            return;
+
+        if (from.isDirectory()) {
+            String next = path;
+            if (next.length() != 0)
+                next += '/';
+
+            File files[] = from.listFiles();
+            for (int i = 0; i < files.length; i++) {
+                copy(jar, next + files[i].getName(), files[i], preprocess,
+                        extra);
+            }
+        } else {
+            if (from.exists()) {
+                Resource resource = new FileResource(from);
+                if (preprocess) {
+                    resource = new PreprocessResource(this, resource);
+                }
+                String x = extra.get("extra");
+                if (x != null)
+                    resource.setExtra(x);
+                jar.putResource(path, resource);
+            } else {
+                error("Input file does not exist: " + from);
+            }
+        }
+    }
+
+    private String getName(String where) {
+        int n = where.lastIndexOf('/');
+        if (n < 0)
+            return where;
+
+        return where.substring(n + 1);
+    }
+
+    public void setSourcepath(File[] files) {
+        for (int i = 0; i < files.length; i++)
+            addSourcepath(files[i]);
+    }
+
+    public void addSourcepath(File cp) {
+        if (!cp.exists())
+            warning("File on sourcepath that does not exist: " + cp);
+
+        sourcePath.add(cp);
+    }
+
+    /**
+     * Create a POM reseource for Maven containing as much information as
+     * possible from the manifest.
+     * 
+     * @param output
+     * @param builder
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public void doPom(Jar dot) throws FileNotFoundException, IOException {
+        {
+            Manifest manifest = dot.getManifest();
+            String name = manifest.getMainAttributes().getValue(
+                    Analyzer.BUNDLE_NAME);
+            String description = manifest.getMainAttributes().getValue(
+                    Analyzer.BUNDLE_DESCRIPTION);
+            String docUrl = manifest.getMainAttributes().getValue(
+                    Analyzer.BUNDLE_DOCURL);
+            String version = manifest.getMainAttributes().getValue(
+                    Analyzer.BUNDLE_VERSION);
+            String bundleVendor = manifest.getMainAttributes().getValue(
+                    Analyzer.BUNDLE_VENDOR);
+            ByteArrayOutputStream s = new ByteArrayOutputStream();
+            PrintStream ps = new PrintStream(s);
+            String bsn = manifest.getMainAttributes().getValue(
+                    Analyzer.BUNDLE_SYMBOLICNAME);
+            String licenses = manifest.getMainAttributes().getValue(
+                    BUNDLE_LICENSE);
+
+            if (bsn == null) {
+                error("Can not create POM unless Bundle-SymbolicName is set");
+                return;
+            }
+
+            bsn = bsn.trim();
+            int n = bsn.lastIndexOf('.');
+            if (n <= 0) {
+                error("Can not create POM unless Bundle-SymbolicName contains a .");
+                ps.close();
+                s.close();
+                return;
+            }
+            String groupId = bsn.substring(0, n);
+            String artifactId = bsn.substring(n + 1);
+            ps
+                    .println("<project xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd'>");
+            ps.println("  <modelVersion>4.0.0</modelVersion>");
+            ps.println("  <groupId>" + groupId + "</groupId>");
+
+            n = artifactId.indexOf(';');
+            if (n > 0)
+                artifactId = artifactId.substring(0, n).trim();
+
+            ps.println("  <artifactId>" + artifactId + "</artifactId>");
+            ps.println("  <version>" + version + "</version>");
+            if (description != null) {
+                ps.println("  <description>");
+                ps.print("    ");
+                ps.println(description);
+                ps.println("  </description>");
+            }
+            if (name != null) {
+                ps.print("  <name>");
+                ps.print(name);
+                ps.println("</name>");
+            }
+            if (docUrl != null) {
+                ps.print("  <url>");
+                ps.print(docUrl);
+                ps.println("</url>");
+            }
+
+            if (bundleVendor != null) {
+                Matcher m = NAME_URL.matcher(bundleVendor);
+                String namePart = bundleVendor;
+                String urlPart = null;
+                if (m.matches()) {
+                    namePart = m.group(1);
+                    urlPart = m.group(2);
+                }
+                ps.println("  <organization>");
+                ps.print("    <name>");
+                ps.print(namePart.trim());
+                ps.println("</name>");
+                if (urlPart != null) {
+                    ps.print("    <url>");
+                    ps.print(urlPart.trim());
+                    ps.println("</url>");
+                }
+                ps.println("  </organization>");
+            }
+            if (licenses != null) {
+                ps.println("  <licenses>");
+                Map<String, Map<String, String>> map = parseHeader(licenses);
+                for (Iterator<Map.Entry<String, Map<String, String>>> e = map
+                        .entrySet().iterator(); e.hasNext();) {
+                    Map.Entry<String, Map<String, String>> entry = e.next();
+                    ps.println("    <license>");
+                    Map<String, String> values = entry.getValue();
+                    print(ps, values, "name", "name", (String) values
+                            .get("url"));
+                    print(ps, values, "url", "url", null);
+                    print(ps, values, "distribution", "distribution", "repo");
+                    ps.println("    </license>");
+                }
+                ps.println("  </licenses>");
+            }
+            ps.println("</project>");
+            ps.close();
+            s.close();
+            dot
+                    .putResource("pom.xml", new EmbeddedResource(s
+                            .toByteArray(), 0));
+        }
+    }
+
+    /**
+     * Utility function to print a tag from a map
+     * 
+     * @param ps
+     * @param values
+     * @param string
+     * @param tag
+     * @param object
+     */
+    private void print(PrintStream ps, Map<String, String> values,
+            String string, String tag, String object) {
+        String value = (String) values.get(string);
+        if (value == null)
+            value = object;
+        if (value == null)
+            return;
+        ps.println("    <" + tag + ">" + value.trim() + "</" + tag + ">");
+    }
+
+    public void close() {
+        super.close();
+    }
+
+    /**
+     * Build Multiple jars. If the -sub command is set, we filter the file with
+     * the given patterns.
+     * 
+     * @return
+     * @throws Exception
+     */
+    public Jar[] builds() throws Exception {
+        begin();
+
+        // Are we acting as a conduit for another JAR?
+        String conduit = getProperty(CONDUIT);
+        if (conduit != null) {
+            Map<String, Map<String, String>> map = parseHeader(conduit);
+            Jar[] result = new Jar[map.size()];
+            int n = 0;
+            for (String file : map.keySet()) {
+                Jar c = new Jar(getFile(file));
+                addClose(c);
+                String name = map.get(file).get("name");
+                if (name != null)
+                    c.setName(name);
+
+                result[n++] = c;
+            }
+            return result;
+        }
+
+        // If no -sub property, then reuse this builder object
+        // other wise, build all the sub parts.
+        String sub = getProperty(SUB);
+        if (sub == null) {
+            Jar jar = build();
+            if (jar == null)
+                return new Jar[0];
+
+            return new Jar[] { jar };
+        }
+
+        List<Jar> result = new ArrayList<Jar>();
+
+        // Get the Instruction objects that match the sub header
+        Set<Instruction> subs = replaceWitInstruction(parseHeader(sub), SUB)
+                .keySet();
+
+        // Get the member files of this directory
+        List<File> members = new ArrayList<File>(Arrays.asList(getBase()
+                .listFiles()));
+
+        getProperties().remove(SUB);
+        // For each member file
+        nextFile: while (members.size() > 0) {
+
+            File file = members.remove(0);
+            if (file.equals(getPropertiesFile()))
+                continue nextFile;
+
+            for (Iterator<Instruction> i = subs.iterator(); i.hasNext();) {
+
+                Instruction instruction = i.next();
+                if (instruction.matches(file.getName())) {
+
+                    if (!instruction.isNegated()) {
+
+                        Builder builder = null;
+                        try {
+                            builder = getSubBuilder();
+                            addClose(builder);
+                            builder.setProperties(file);
+                            builder.setProperty(SUB, "");
+                            // Recursively build
+                            // TODO
+                            Jar jar = builder.build();
+                            jar.setName(builder.getBsn());
+                            result.add(jar);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                            error("Sub Building " + file, e);
+                        }
+                        if (builder != null)
+                            getInfo(builder, file.getName() + ": ");
+                    }
+
+                    // Because we matched (even though we could be negated)
+                    // we skip any remaining searches
+                    continue nextFile;
+                }
+            }
+        }
+        setProperty(SUB, sub);
+        return result.toArray(new Jar[result.size()]);
+    }
+
+    public Builder getSubBuilder() throws Exception {
+        Builder builder = new Builder(this);
+        builder.setBase(getBase());
+
+        for (Jar file : getClasspath()) {
+            builder.addClasspath(file);
+        }
+
+        return builder;
+    }
+
+    /**
+     * A macro to convert a maven version to an OSGi version
+     */
+
+    public String _maven_version(String args[]) {
+        if (args.length > 2)
+            error("${maven_version} macro receives too many arguments "
+                    + Arrays.toString(args));
+        else if (args.length < 2)
+            error("${maven_version} macro has no arguments, use ${maven_version;1.2.3-SNAPSHOT}");
+        else {
+            return cleanupVersion(args[1]);
+        }
+        return null;
+    }
+
+    public String _permissions(String args[]) throws IOException {
+        StringBuilder sb = new StringBuilder();
+
+        for (String arg : args) {
+            if ("packages".equals(arg) || "all".equals(arg)) {
+                for (String imp : getImports().keySet()) {
+                    if (!imp.startsWith("java.")) {
+                        sb.append("(org.osgi.framework.PackagePermission \"");
+                        sb.append(imp);
+                        sb.append("\" \"import\")\r\n");
+                    }
+                }
+                for (String exp : getExports().keySet()) {
+                    sb.append("(org.osgi.framework.PackagePermission \"");
+                    sb.append(exp);
+                    sb.append("\" \"export\")\r\n");
+                }
+            } else if ("admin".equals(arg) || "all".equals(arg)) {
+                sb.append("(org.osgi.framework.AdminPermission)");
+            } else if ("permissions".equals(arg))
+                ;
+            else
+                error("Invalid option in ${permissions}: %s", arg);
+        }
+        return sb.toString();
+    }
+
+    public void removeBundleSpecificHeaders() {
+        Set<String> set = new HashSet<String>(Arrays
+                .asList(BUNDLE_SPECIFIC_HEADERS));
+        setForceLocal(set);
+    }
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Builder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ClassDataCollector.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ClassDataCollector.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ClassDataCollector.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ClassDataCollector.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,11 @@
+package aQute.lib.osgi;
+
+public interface ClassDataCollector {
+    void classBegin(int access, String name);
+    void extendsClass(String name);
+    void implementsInterfaces(String name[]);
+    void field(int access, String descriptor);
+    void method(int access, String descriptor);
+    void addReference(String token);
+    void classEnd();
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/ClassDataCollector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Clazz.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Clazz.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Clazz.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Clazz.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,832 @@
+/* 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.nio.*;
+import java.util.*;
+
+public class Clazz {
+    public static enum QUERY {
+        IMPLEMENTS, EXTENDS, IMPORTS, NAMED, ANY, VERSION
+    };
+
+    static protected class Assoc {
+        Assoc(byte tag, int a, int b) {
+            this.tag = tag;
+            this.a = a;
+            this.b = b;
+        }
+
+        byte tag;
+        int  a;
+        int  b;
+    }
+
+    final static byte                SkipTable[] = { 0, // 0 non existent
+            -1, // 1 CONSTANT_utf8 UTF 8, handled in
+            // method
+            -1, // 2
+            4, // 3 CONSTANT_Integer
+            4, // 4 CONSTANT_Float
+            8, // 5 CONSTANT_Long (index +=2!)
+            8, // 6 CONSTANT_Double (index +=2!)
+            -1, // 7 CONSTANT_Class
+            2, // 8 CONSTANT_String
+            4, // 9 CONSTANT_FieldRef
+            4, // 10 CONSTANT_MethodRef
+            4, // 11 CONSTANT_InterfaceMethodRef
+            4, // 12 CONSTANT_NameAndType
+                                                 };
+
+    String                           className;
+    Object                           pool[];
+    int                              intPool[];
+    Map<String, Map<String, String>> imports     = new HashMap<String, Map<String, String>>();
+    String                           path;
+
+    // static String type = "([BCDFIJSZ\\[]|L[^<>]+;)";
+    // static Pattern descriptor = Pattern.compile("\\(" + type + "*\\)(("
+    // + type + ")|V)");
+    int                              minor       = 0;
+    int                              major       = 0;
+
+    String                           sourceFile;
+    Set<String>                      xref;
+    Set<Integer>                     classes;
+    Set<Integer>                     descriptors;
+    int                              forName     = 0;
+    int                              class$      = 0;
+    String[]                         interfaces;
+    String                           zuper;
+    ClassDataCollector               cd          = new ClassDataCollector() {
+                                                     public void addReference(
+                                                             String token) {
+                                                     }
+
+                                                     public void classBegin(
+                                                             int access,
+                                                             String name) {
+                                                     }
+
+                                                     public void classEnd() {
+                                                     }
+
+                                                     public void extendsClass(
+                                                             String name) {
+                                                     }
+
+                                                     public void field(
+                                                             int access,
+                                                             String descriptor) {
+                                                     }
+
+                                                     public void implementsInterfaces(
+                                                             String[] name) {
+                                                     }
+
+                                                     public void method(
+                                                             int access,
+                                                             String descriptor) {
+                                                     }
+                                                 };
+
+    public Clazz(String path) {
+        this.path = path;
+    }
+
+    public Clazz(String path, InputStream in) throws IOException {
+        this.path = path;
+        DataInputStream din = new DataInputStream(in);
+        parseClassFile(din);
+        din.close();
+    }
+
+    Set<String> parseClassFile(DataInputStream in) throws IOException {
+
+        xref = new HashSet<String>();
+        classes = new HashSet<Integer>();
+        descriptors = new HashSet<Integer>();
+
+        boolean crawl = false; // Crawl the byte code
+        int magic = in.readInt();
+        if (magic != 0xCAFEBABE)
+            throw new IOException("Not a valid class file (no CAFEBABE header)");
+
+        minor = in.readUnsignedShort(); // minor version
+        major = in.readUnsignedShort(); // major version
+        int count = in.readUnsignedShort();
+        pool = new Object[count];
+        intPool = new int[count];
+
+        process: for (int poolIndex = 1; poolIndex < count; poolIndex++) {
+            byte tag = in.readByte();
+            switch (tag) {
+            case 0:
+                break process;
+            case 1:
+                constantUtf8(in, poolIndex);
+                break;
+
+            // For some insane optimization reason are
+            // the long and the double two entries in the
+            // constant pool. See 4.4.5
+            case 5:
+                constantLong(in, poolIndex);
+                poolIndex++;
+                break;
+
+            case 6:
+                constantDouble(in, poolIndex);
+                poolIndex++;
+                break;
+
+            case 7:
+                constantClass(in, poolIndex);
+                break;
+
+            case 8:
+                constantString(in, poolIndex);
+                break;
+
+            case 10: // Method ref
+                methodRef(in, poolIndex);
+                break;
+
+            // Name and Type
+            case 12:
+                nameAndType(in, poolIndex, tag);
+                break;
+
+            // We get the skip count for each record type
+            // from the SkipTable. This will also automatically
+            // abort when
+            default:
+                if (tag == 2)
+                    throw new IOException("Invalid tag " + tag);
+                in.skipBytes(SkipTable[tag]);
+                break;
+            }
+        }
+
+        pool(pool, intPool);
+        /*
+         * Parse after the constant pool, code thanks to Hans Christian
+         * Falkenberg
+         */
+
+        int access_flags = in.readUnsignedShort(); // access
+        int this_class = in.readUnsignedShort();
+        className = (String) pool[intPool[this_class]];
+        cd.classBegin(access_flags, className);
+
+        try {
+
+            int super_class = in.readUnsignedShort();
+            zuper = (String) pool[intPool[super_class]];
+            if (zuper != null) {
+                addReference(zuper);
+                cd.extendsClass(zuper);
+            }
+
+            int interfacesCount = in.readUnsignedShort();
+            if (interfacesCount > 0) {
+                interfaces = new String[interfacesCount];
+                for (int i = 0; i < interfacesCount; i++)
+                    interfaces[i] = (String) pool[intPool[in
+                            .readUnsignedShort()]];
+                cd.implementsInterfaces(interfaces);
+            }
+
+            int fieldsCount = in.readUnsignedShort();
+            for (int i = 0; i < fieldsCount; i++) {
+                access_flags = in.readUnsignedShort(); // skip access flags
+                int name_index = in.readUnsignedShort();
+                int descriptor_index = in.readUnsignedShort();
+
+                // Java prior to 1.5 used a weird
+                // static variable to hold the com.X.class
+                // result construct. If it did not find it
+                // it would create a variable class$com$X
+                // that would be used to hold the class
+                // object gotten with Class.forName ...
+                // Stupidly, they did not actively use the
+                // class name for the field type, so bnd
+                // would not see a reference. We detect
+                // this case and add an artificial descriptor
+                String name = pool[name_index].toString(); // name_index
+                if (name.startsWith("class$")) {
+                    crawl = true;
+                }
+                cd.field(access_flags, pool[descriptor_index].toString());
+                descriptors.add(new Integer(descriptor_index));
+                doAttributes(in, false);
+            }
+
+            //
+            // Check if we have to crawl the code to find
+            // the ldc(_w) <string constant> invokestatic Class.forName
+            // if so, calculate the method ref index so we
+            // can do this efficiently
+            //
+            if (crawl) {
+                forName = findMethod("java/lang/Class", "forName",
+                        "(Ljava/lang/String;)Ljava/lang/Class;");
+                class$ = findMethod(className, "class$",
+                        "(Ljava/lang/String;)Ljava/lang/Class;");
+            }
+
+            //
+            // Handle the methods
+            //
+            int methodCount = in.readUnsignedShort();
+            for (int i = 0; i < methodCount; i++) {
+                access_flags = in.readUnsignedShort();
+                /* int name_index = */in.readUnsignedShort();
+                int descriptor_index = in.readUnsignedShort();
+                // String s = (String) pool[name_index];
+                descriptors.add(new Integer(descriptor_index));
+                if ( pool[descriptor_index ] == null ) {
+                    System.out.println("Value in pool=null, descriptor_index=" +descriptor_index);
+                }
+                cd.method(access_flags, pool[descriptor_index].toString());
+                doAttributes(in, crawl);
+            }
+
+            doAttributes(in, false);
+
+            //
+            // Now iterate over all classes we found and
+            // parse those as well. We skip duplicates
+            //
+
+            for (Iterator<Integer> e = classes.iterator(); e.hasNext();) {
+                int class_index = e.next().intValue();
+                doClassReference((String) pool[class_index]);
+            }
+
+            //
+            // Parse all the descriptors we found
+            //
+
+            for (Iterator<Integer> e = descriptors.iterator(); e.hasNext();) {
+                Integer index = e.next();
+                String prototype = (String) pool[index.intValue()];
+                if (prototype != null)
+                    parseDescriptor(prototype);
+                else
+                    System.err.println("Unrecognized descriptor: " + index);
+            }
+            Set<String> xref = this.xref;
+            reset();
+            return xref;
+        } finally {
+            cd.classEnd();
+        }
+    }
+
+    protected void pool(Object[] pool, int[] intPool) {
+    }
+
+    /**
+     * @param in
+     * @param poolIndex
+     * @param tag
+     * @throws IOException
+     */
+    protected void nameAndType(DataInputStream in, int poolIndex, byte tag)
+            throws IOException {
+        int name_index = in.readUnsignedShort();
+        int descriptor_index = in.readUnsignedShort();
+        descriptors.add(new Integer(descriptor_index));
+        pool[poolIndex] = new Assoc(tag, name_index, descriptor_index);
+    }
+
+    /**
+     * @param in
+     * @param poolIndex
+     * @param tag
+     * @throws IOException
+     */
+    private void methodRef(DataInputStream in, int poolIndex)
+            throws IOException {
+        int class_index = in.readUnsignedShort();
+        int name_and_type_index = in.readUnsignedShort();
+        pool[poolIndex] = new Assoc((byte) 10, class_index, name_and_type_index);
+    }
+
+    /**
+     * @param in
+     * @param poolIndex
+     * @throws IOException
+     */
+    private void constantString(DataInputStream in, int poolIndex)
+            throws IOException {
+        int string_index = in.readUnsignedShort();
+        intPool[poolIndex] = string_index;
+    }
+
+    /**
+     * @param in
+     * @param poolIndex
+     * @throws IOException
+     */
+    protected void constantClass(DataInputStream in, int poolIndex)
+            throws IOException {
+        int class_index = in.readUnsignedShort();
+        classes.add(new Integer(class_index));
+        intPool[poolIndex] = class_index;
+    }
+
+    /**
+     * @param in
+     * @throws IOException
+     */
+    protected void constantDouble(DataInputStream in, int poolIndex)
+            throws IOException {
+        in.skipBytes(8);
+    }
+
+    /**
+     * @param in
+     * @throws IOException
+     */
+    protected void constantLong(DataInputStream in, int poolIndex)
+            throws IOException {
+        in.skipBytes(8);
+    }
+
+    /**
+     * @param in
+     * @param poolIndex
+     * @throws IOException
+     */
+    protected void constantUtf8(DataInputStream in, int poolIndex)
+            throws IOException {
+        // CONSTANT_Utf8
+
+        String name = in.readUTF();
+        xref.add(name);
+        pool[poolIndex] = name;
+    }
+
+    /**
+     * Find a method reference in the pool that points to the given class,
+     * methodname and descriptor.
+     * 
+     * @param clazz
+     * @param methodname
+     * @param descriptor
+     * @return index in constant pool
+     */
+    private int findMethod(String clazz, String methodname, String descriptor) {
+        for (int i = 1; i < pool.length; i++) {
+            if (pool[i] instanceof Assoc) {
+                Assoc methodref = (Assoc) pool[i];
+                if (methodref.tag == 10) {
+                    // Method ref
+                    int class_index = methodref.a;
+                    int class_name_index = intPool[class_index];
+                    if (clazz.equals(pool[class_name_index])) {
+                        int name_and_type_index = methodref.b;
+                        Assoc name_and_type = (Assoc) pool[name_and_type_index];
+                        if (name_and_type.tag == 12) {
+                            // Name and Type
+                            int name_index = name_and_type.a;
+                            int type_index = name_and_type.b;
+                            if (methodname.equals(pool[name_index])) {
+                                if (descriptor.equals(pool[type_index])) {
+                                    return i;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return -1;
+    }
+
+    private void doClassReference(String next) {
+        if (next != null) {
+            String normalized = normalize(next);
+            if (normalized != null) {
+                cd.addReference(next);
+                String pack = getPackage(normalized);
+                packageReference(pack);
+            }
+        } else
+            throw new IllegalArgumentException("Invalid class, parent=");
+    }
+
+    /**
+     * Called for each attribute in the class, field, or method.
+     * 
+     * @param in
+     *            The stream
+     * @throws IOException
+     */
+    private void doAttributes(DataInputStream in, boolean crawl)
+            throws IOException {
+        int attributesCount = in.readUnsignedShort();
+        for (int j = 0; j < attributesCount; j++) {
+            // skip name CONSTANT_Utf8 pointer
+            doAttribute(in, crawl);
+        }
+    }
+
+    /**
+     * Process a single attribute, if not recognized, skip it.
+     * 
+     * @param in
+     *            the data stream
+     * @throws IOException
+     */
+    private void doAttribute(DataInputStream in, boolean crawl)
+            throws IOException {
+        int attribute_name_index = in.readUnsignedShort();
+        String attributeName = (String) pool[attribute_name_index];
+        long attribute_length = in.readInt();
+        attribute_length &= 0xFFFFFFFF;
+        if ("RuntimeVisibleAnnotations".equals(attributeName))
+            doAnnotations(in);
+        else if ("RuntimeVisibleParameterAnnotations".equals(attributeName))
+            doParameterAnnotations(in);
+        else if ("SourceFile".equals(attributeName))
+            doSourceFile(in);
+        else if ("Code".equals(attributeName) && crawl)
+            doCode(in);
+//        else if ("Signature".equals(attributeName))
+//            doSignature(in);
+        else {
+            if (attribute_length > 0x7FFFFFFF) {
+                throw new IllegalArgumentException("Attribute > 2Gb");
+            }
+            in.skipBytes((int) attribute_length);
+        }
+    }
+
+    /**
+     * Handle a signature
+     * 
+     * <pre>
+     * Signature_attribute { 
+     *     u2 attribute_name_index; 
+     *     u4 attribute_length; 
+     *     u2 signature_index; 
+     *     } 
+     * </pre>
+     */
+
+//    void doSignature(DataInputStream in) throws IOException {
+//        /*int attribute_length =*/ in.readInt();
+//        int signature_index = in.readUnsignedShort();
+//        String signature = (String) pool[signature_index];        
+//    }
+
+    /**
+     * <pre>
+     * Code_attribute {
+     * 		u2 attribute_name_index;
+     * 		u4 attribute_length;
+     * 		u2 max_stack;
+     * 		u2 max_locals;
+     * 		u4 code_length;
+     * 		u1 code[code_length];
+     * 		u2 exception_table_length;
+     * 		{    	u2 start_pc;
+     * 		      	u2 end_pc;
+     * 		      	u2  handler_pc;
+     * 		      	u2  catch_type;
+     * 		}	exception_table[exception_table_length];
+     * 		u2 attributes_count;
+     * 		attribute_info attributes[attributes_count];
+     * 	}
+     * </pre>
+     * 
+     * @param in
+     * @param pool
+     * @throws IOException
+     */
+    private void doCode(DataInputStream in) throws IOException {
+        /* int max_stack = */in.readUnsignedShort();
+        /* int max_locals = */in.readUnsignedShort();
+        int code_length = in.readInt();
+        byte code[] = new byte[code_length];
+        in.readFully(code);
+        crawl(code);
+        int exception_table_length = in.readUnsignedShort();
+        in.skipBytes(exception_table_length * 8);
+        doAttributes(in, false);
+    }
+
+    /**
+     * We must find Class.forName references ...
+     * 
+     * @param code
+     */
+    protected void crawl(byte[] code) {
+        ByteBuffer bb = ByteBuffer.wrap(code);
+        bb.order(ByteOrder.BIG_ENDIAN);
+        int lastReference = -1;
+
+        while (bb.remaining() > 0) {
+            int instruction = 0xFF & bb.get();
+            switch (instruction) {
+            case OpCodes.ldc:
+                lastReference = 0xFF & bb.get();
+                break;
+
+            case OpCodes.ldc_w:
+                lastReference = 0xFFFF & bb.getShort();
+                break;
+
+            case OpCodes.invokestatic:
+                int methodref = 0xFFFF & bb.getShort();
+                if ((methodref == forName || methodref == class$)
+                        && lastReference != -1
+                        && pool[intPool[lastReference]] instanceof String) {
+                    String clazz = (String) pool[intPool[lastReference]];
+                    doClassReference(clazz.replace('.', '/'));
+                }
+                break;
+
+            case OpCodes.tableswitch:
+                // Skip to place divisible by 4
+                while ((bb.position() & 0x3) != 0)
+                    bb.get();
+                /* int deflt = */
+                bb.getInt();
+                int low = bb.getInt();
+                int high = bb.getInt();
+                bb.position(bb.position() + (high - low + 1) * 4);
+                lastReference = -1;
+                break;
+
+            case OpCodes.lookupswitch:
+                // Skip to place divisible by 4
+                while ((bb.position() & 0x3) != 0)
+                    bb.get();
+                /* deflt = */
+                bb.getInt();
+                int npairs = bb.getInt();
+                bb.position(bb.position() + npairs * 8);
+                lastReference = -1;
+                break;
+
+            default:
+                lastReference = -1;
+                bb.position(bb.position() + OpCodes.OFFSETS[instruction]);
+            }
+        }
+    }
+
+    private void doSourceFile(DataInputStream in) throws IOException {
+        int sourcefile_index = in.readUnsignedShort();
+        this.sourceFile = pool[sourcefile_index].toString();
+    }
+
+    private void doParameterAnnotations(DataInputStream in) throws IOException {
+        int num_parameters = in.readUnsignedByte();
+        for (int p = 0; p < num_parameters; p++) {
+            int num_annotations = in.readUnsignedShort(); // # of annotations
+            for (int a = 0; a < num_annotations; a++) {
+                doAnnotation(in);
+            }
+        }
+    }
+
+    private void doAnnotations(DataInputStream in) throws IOException {
+        int num_annotations = in.readUnsignedShort(); // # of annotations
+        for (int a = 0; a < num_annotations; a++) {
+            doAnnotation(in);
+        }
+    }
+
+    private void doAnnotation(DataInputStream in) throws IOException {
+        int type_index = in.readUnsignedShort();
+        descriptors.add(new Integer(type_index));
+        int num_element_value_pairs = in.readUnsignedShort();
+        for (int v = 0; v < num_element_value_pairs; v++) {
+            /* int element_name_index = */in.readUnsignedShort();
+            doElementValue(in);
+        }
+    }
+
+    private void doElementValue(DataInputStream in) throws IOException {
+        int tag = in.readUnsignedByte();
+        switch (tag) {
+        case 'B':
+        case 'C':
+        case 'D':
+        case 'F':
+        case 'I':
+        case 'J':
+        case 'S':
+        case 'Z':
+        case 's':
+            /* int const_value_index = */
+            in.readUnsignedShort();
+            break;
+
+        case 'e':
+            int type_name_index = in.readUnsignedShort();
+            descriptors.add(new Integer(type_name_index));
+            /* int const_name_index = */
+            in.readUnsignedShort();
+            break;
+
+        case 'c':
+            int class_info_index = in.readUnsignedShort();
+            descriptors.add(new Integer(class_info_index));
+            break;
+
+        case '@':
+            doAnnotation(in);
+            break;
+
+        case '[':
+            int num_values = in.readUnsignedShort();
+            for (int i = 0; i < num_values; i++) {
+                doElementValue(in);
+            }
+            break;
+
+        default:
+            throw new IllegalArgumentException(
+                    "Invalid value for Annotation ElementValue tag " + tag);
+        }
+    }
+
+    void packageReference(String pack) {
+        if (pack.indexOf('<') >= 0)
+            System.out.println("Oops: " + pack);
+        if (!imports.containsKey(pack))
+            imports.put(pack, new LinkedHashMap<String, String>());
+    }
+
+    public void parseDescriptor(String prototype) {
+        if (prototype.startsWith("("))
+            parseMethodDescriptor(prototype);
+        else
+            addReference(prototype);
+    }
+
+    void parseMethodDescriptor(String prototype) {
+        int last = prototype.indexOf(')');
+        if (last < 0)
+            throw new IllegalArgumentException(
+                    "Invalid method descriptor in class file: " + className
+                            + " " + prototype);
+
+        for (int i = 1; i < last; i++) {
+            if (prototype.charAt(i) == 'L') {
+                int next = prototype.indexOf(';', i);
+                addReference(prototype.substring(i, next));
+                i = next;
+            }
+        }
+        addReference(prototype.substring(last + 1));
+    }
+
+    private void addReference(String token) {
+        cd.addReference(token);
+        while (token.startsWith("["))
+            token = token.substring(1);
+
+        if (token.startsWith("L")) {
+            String clazz = normalize(token.substring(1));
+            if (clazz.startsWith("java/"))
+                return;
+            String pack = getPackage(clazz);
+            packageReference(pack);
+        }
+    }
+
+    static String normalize(String s) {
+        if (s.startsWith("[L"))
+            return normalize(s.substring(2));
+        if (s.startsWith("["))
+            if (s.length() == 2)
+                return null;
+            else
+                return normalize(s.substring(1));
+        if (s.endsWith(";"))
+            return normalize(s.substring(0, s.length() - 1));
+        return s + ".class";
+    }
+
+    public static String getPackage(String clazz) {
+        int n = clazz.lastIndexOf('/');
+        if (n < 0)
+            return ".";
+        return clazz.substring(0, n).replace('/', '.');
+    }
+
+    public Map<String, Map<String, String>> getReferred() {
+        return imports;
+    }
+
+    String getClassName() {
+        return className;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public Set<String> xref(InputStream in) throws IOException {
+        DataInputStream din = new DataInputStream(in);
+        Set<String> set = parseClassFile(din);
+        din.close();
+        return set;
+    }
+
+    public String getSourceFile() {
+        return sourceFile;
+    }
+
+    /**
+     * .class construct for different compilers
+     * 
+     * sun 1.1 Detect static variable class$com$acme$MyClass 1.2 " 1.3 " 1.4 "
+     * 1.5 ldc_w (class) 1.6 "
+     * 
+     * eclipse 1.1 class$0, ldc (string), invokestatic Class.forName 1.2 " 1.3 "
+     * 1.5 ldc (class) 1.6 "
+     * 
+     * 1.5 and later is not an issue, sun pre 1.5 is easy to detect the static
+     * variable that decodes the class name. For eclipse, the class$0 gives away
+     * we have a reference encoded in a string.
+     * compilerversions/compilerversions.jar contains test versions of all
+     * versions/compilers.
+     */
+
+    public void reset() {
+        pool = null;
+        intPool = null;
+        xref = null;
+        classes = null;
+        descriptors = null;
+    }
+
+    public boolean is(QUERY query, Instruction instr,
+            Map<String, Clazz> classspace) {
+        switch (query) {
+        case ANY:
+            return true;
+
+        case NAMED:
+            if (instr.matches(getClassName()))
+                return !instr.isNegated();
+            return false;
+
+        case VERSION:
+            String v = major + "/" + minor;
+            if (instr.matches(v))
+                return !instr.isNegated();
+            return false;
+
+        case IMPLEMENTS:
+            for (int i = 0; interfaces != null && i < interfaces.length; i++) {
+                if (instr.matches(interfaces[i]))
+                    return !instr.isNegated();
+            }
+            break;
+        case EXTENDS:
+            if (zuper == null)
+                return false;
+
+            if (instr.matches(zuper))
+                return !instr.isNegated();
+            break;
+
+        case IMPORTS:
+            for (String imp : imports.keySet()) {
+                if (instr.matches(imp.replace('.', '/')))
+                    return !instr.isNegated();
+            }
+        }
+
+        if (zuper == null || classspace == null)
+            return false;
+
+        Clazz clazz = classspace.get(zuper);
+        if (clazz == null)
+            return false;
+
+        return clazz.is(query, instr, classspace);
+    }
+
+    public String toString() {
+        return getFQN();
+    }
+
+    public String getFQN() {
+        return getClassName().replace('/', '.');
+    }
+
+    public void setClassDataCollector(ClassDataCollector cd) {
+        this.cd = cd;
+    }
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Clazz.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Constants.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Constants.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Constants.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Constants.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,197 @@
+package aQute.lib.osgi;
+
+import java.util.*;
+import java.util.regex.*;
+
+public interface Constants {
+    /*
+     * Defined in OSGi
+     */
+    /**
+     * @syntax Bundle-ActivationPolicy ::= policy ( ’;’ directive )* policy ::=
+     *         ’lazy’
+     */
+    String               BUNDLE_ACTIVATION_POLICY                  = "Bundle-ActivationPolicy";
+    String               BUNDLE_ACTIVATOR                          = "Bundle-Activator";
+    String               BUNDLE_BLUEPRINT                          = "Bundle-Copyright";
+    String               BUNDLE_CATEGORY                           = "Bundle-Category";
+    String               BUNDLE_CLASSPATH                          = "Bundle-ClassPath";
+    String               BUNDLE_CONTACTADDRESS                     = "Bundle-ContactAddress";
+    String               BUNDLE_COPYRIGHT                          = "Bundle-Copyright";
+    String               BUNDLE_DESCRIPTION                        = "Bundle-Description";
+    String               BUNDLE_DOCURL                             = "Bundle-DocURL";
+    String               BUNDLE_ICON                               = "Bundle-Icon";
+    String               BUNDLE_LICENSE                            = "Bundle-License";
+    String               BUNDLE_LOCALIZATION                       = "Bundle-Localization";
+    String               BUNDLE_MANIFESTVERSION                    = "Bundle-ManifestVersion";
+    String               BUNDLE_NAME                               = "Bundle-Name";
+    String               BUNDLE_NATIVECODE                         = "Bundle-NativeCode";
+    String               BUNDLE_REQUIREDEXECUTIONENVIRONMENT       = "Bundle-RequiredExecutionEnvironment";
+    String               BUNDLE_SYMBOLICNAME                       = "Bundle-SymbolicName";
+    String               BUNDLE_UPDATELOCATION                     = "Bundle-UpdateLocation";
+    String               BUNDLE_VENDOR                             = "Bundle-Vendor";
+    String               BUNDLE_VERSION                            = "Bundle-Version";
+    String               DYNAMICIMPORT_PACKAGE                     = "DynamicImport-Package";
+    String               EXPORT_PACKAGE                            = "Export-Package";
+    String               EXPORT_SERVICE                            = "Export-Service";
+    String               FRAGMENT_HOST                             = "Fragment-Host";
+    String               IMPORT_PACKAGE                            = "Import-Package";
+    String               IMPORT_SERVICE                            = "Import-Service";
+    String               REQUIRE_BUNDLE                            = "Require-Bundle";
+    String               SERVICE_COMPONENT                         = "Service-Component";
+
+    String               PRIVATE_PACKAGE                           = "Private-Package";
+    String               IGNORE_PACKAGE                            = "Ignore-Package";
+    String               INCLUDE_RESOURCE                          = "Include-Resource";
+    String               CONDITIONAL_PACKAGE                       = "Conditional-Package";
+    String               BND_LASTMODIFIED                          = "Bnd-LastModified";
+    String               CREATED_BY                                = "Created-By";
+    String               TOOL                                      = "Tool";
+    String               TESTCASES                                 = "Test-Cases";
+
+    String               headers[]                                 = {
+            BUNDLE_ACTIVATOR, BUNDLE_CONTACTADDRESS, BUNDLE_COPYRIGHT,
+            BUNDLE_DESCRIPTION, BUNDLE_DOCURL, BUNDLE_LOCALIZATION,
+            BUNDLE_NATIVECODE, BUNDLE_VENDOR, BUNDLE_VERSION, BUNDLE_LICENSE,
+            BUNDLE_CLASSPATH, SERVICE_COMPONENT, EXPORT_PACKAGE,
+            IMPORT_PACKAGE, BUNDLE_LOCALIZATION, BUNDLE_MANIFESTVERSION,
+            BUNDLE_NAME, BUNDLE_NATIVECODE,
+            BUNDLE_REQUIREDEXECUTIONENVIRONMENT, BUNDLE_SYMBOLICNAME,
+            BUNDLE_VERSION, FRAGMENT_HOST, PRIVATE_PACKAGE, IGNORE_PACKAGE,
+            INCLUDE_RESOURCE, REQUIRE_BUNDLE, IMPORT_SERVICE, EXPORT_SERVICE,
+            CONDITIONAL_PACKAGE, BND_LASTMODIFIED, TESTCASES      };
+
+    String               BUILDPATH                                 = "-buildpath";
+    String               BUMPPOLICY                                = "-bumppolicy";
+    String               CONDUIT                                   = "-conduit";
+    String               DEPENDSON                                 = "-dependson";
+    String               DEPLOYREPO                                = "-deployrepo";
+    String               DONOTCOPY                                 = "-donotcopy";
+    String               DEBUG                                     = "-debug";
+    String               EXPORT_CONTENTS                           = "-exportcontents";
+    String               FAIL_OK                                   = "-failok";
+    String               INCLUDE                                   = "-include";
+    String               INCLUDERESOURCE                           = "-includeresource";
+    String               MAKE                                      = "-make";
+    String               MANIFEST                                  = "-manifest";
+    String               NOEXTRAHEADERS                            = "-noextraheaders";
+    String               NOMANIFEST                                = "-nomanifest";
+    String               NOUSES                                    = "-nouses";
+    String               NOPE                                      = "-nope";
+    String               PEDANTIC                                  = "-pedantic";
+    String               PLUGIN                                    = "-plugin";
+    String               POM                                       = "-pom";
+    String               RELEASEREPO                               = "-releaserepo";
+    String               REMOVE_HEADERS                            = "-removeheaders";
+    String               RESOURCEONLY                              = "-resourceonly";
+    String               SOURCES                                   = "-sources";
+    String               SOURCEPATH                                = "-sourcepath";
+    String               SUB                                       = "-sub";
+    String               RUNPROPERTIES                             = "-runproperties";
+    String               RUNSYSTEMPACKAGES                         = "-runsystempackages";
+    String               RUNBUNDLES                                = "-runbundles";
+    String               RUNPATH                                   = "-runpath";
+    String               RUNVM                                     = "-runvm";
+
+    String               REPORTNEWER                               = "-reportnewer";
+    String               SIGN                                      = "-sign";
+    String               TESTPACKAGES                              = "-testpackages";
+    String               TESTREPORT                                = "-testreport";
+    String               TESTBUNDLES                               = "-testbundles";
+    String               UNDERTEST                                 = "-undertest";
+    String               VERBOSE                                   = "-verbose";
+    String               VERSIONPOLICY                             = "-versionpolicy";
+
+    // Deprecated
+    String               CLASSPATH                                 = "-classpath";
+
+    String               options[]                                 = {
+            BUILDPATH, BUMPPOLICY, CONDUIT, CLASSPATH, DEPENDSON, DONOTCOPY,
+            EXPORT_CONTENTS, FAIL_OK, INCLUDE, INCLUDERESOURCE, MAKE, MANIFEST,
+            NOEXTRAHEADERS, NOUSES, NOPE, PEDANTIC, PLUGIN, POM,
+            REMOVE_HEADERS, RESOURCEONLY, SOURCES, SOURCEPATH, SOURCES,
+            SOURCEPATH, SUB, RUNBUNDLES, RUNPATH, RUNSYSTEMPACKAGES,
+            RUNPROPERTIES, REPORTNEWER, UNDERTEST, TESTBUNDLES, TESTPACKAGES,
+            TESTREPORT, VERBOSE, NOMANIFEST, DEPLOYREPO, RELEASEREPO };
+
+    // Ignore bundle specific headers. These bundles do not make
+    // a lot of sense to inherit
+    String[]             BUNDLE_SPECIFIC_HEADERS                   = new String[] {
+            INCLUDE_RESOURCE, BUNDLE_ACTIVATOR, BUNDLE_CLASSPATH, BUNDLE_NAME,
+            BUNDLE_NATIVECODE, BUNDLE_SYMBOLICNAME, IMPORT_PACKAGE,
+            EXPORT_PACKAGE, DYNAMICIMPORT_PACKAGE, FRAGMENT_HOST,
+            REQUIRE_BUNDLE, PRIVATE_PACKAGE, EXPORT_CONTENTS, TESTCASES,
+            NOMANIFEST                                            };
+
+    char                 DUPLICATE_MARKER                          = '~';
+
+    String               SPLIT_PACKAGE_DIRECTIVE                   = "-split-package:";
+    String               IMPORT_DIRECTIVE                          = "-import:";
+    String               NO_IMPORT_DIRECTIVE                       = "-noimport:";
+    String               REMOVE_ATTRIBUTE_DIRECTIVE                = "-remove-attribute:";
+
+    String               USES_DIRECTIVE                            = "uses:";
+    String               MANDATORY_DIRECTIVE                       = "mandatory:";
+    String               INCLUDE_DIRECTIVE                         = "include:";
+    String               EXCLUDE_DIRECTIVE                         = "exclude:";
+    String               PRESENCE_DIRECTIVE                        = "presence:";
+    String               SINGLETON_DIRECTIVE                       = "singleton:";
+    String               EXTENSION_DIRECTIVE                       = "extension:";
+    String               VISIBILITY_DIRECTIVE                      = "visibility:";
+    String               FRAGMENT_ATTACHMENT_DIRECTIVE             = "fragment-attachment:";
+    String               RESOLUTION_DIRECTIVE                      = "resolution:";
+    String               PATH_DIRECTIVE                            = "path:";
+    String               SIZE_ATTRIBUTE                            = "size";
+    String               LINK_ATTRIBUTE                            = "link";
+    String               NAME_ATTRIBUTE                            = "name";
+    String               DESCRIPTION_ATTRIBUTE                     = "description";
+    String               OSNAME_ATTRIBUTE                          = "osname";
+    String               OSVERSION_ATTRIBUTE                       = "osversion";
+    String               PROCESSOR_ATTRIBUTE                       = "processor";
+    String               LANGUAGE_ATTRIBUTE                        = "language";
+    String               SELECTION_FILTER_ATTRIBUTE                = "selection-filter";
+    String               BLUEPRINT_WAIT_FOR_DEPENDENCIES_ATTRIBUTE = "blueprint.wait-for-dependencies";
+    String               BLUEPRINT_TIMEOUT_ATTRIBUTE               = "blueprint.timeout";
+    String               VERSION_ATTRIBUTE                         = "version";
+    String               BUNDLE_SYMBOLIC_NAME_ATTRIBUTE            = "bundle-symbolic-name";
+    String               BUNDLE_VERSION_ATTRIBUTE                  = "bundle-version";
+
+    String               KEYSTORE_LOCATION_DIRECTIVE               = "keystore:";
+    String               KEYSTORE_PROVIDER_DIRECTIVE               = "provider:";
+    String               KEYSTORE_PASSWORD_DIRECTIVE               = "password:";
+    String               SIGN_PASSWORD_DIRECTIVE                   = "sign-password:";
+
+    String               NONE                                      = "none";
+
+    String               directives[]                              = {
+            SPLIT_PACKAGE_DIRECTIVE, NO_IMPORT_DIRECTIVE, IMPORT_DIRECTIVE,
+            RESOLUTION_DIRECTIVE, INCLUDE_DIRECTIVE, USES_DIRECTIVE,
+            EXCLUDE_DIRECTIVE, KEYSTORE_LOCATION_DIRECTIVE,
+            KEYSTORE_PROVIDER_DIRECTIVE, KEYSTORE_PASSWORD_DIRECTIVE,
+            SIGN_PASSWORD_DIRECTIVE,
+
+                                                                   // TODO
+                                                                   };
+
+    String               USES_USES                                 = "<<USES>>";
+    String               CURRENT_USES                              = "@uses";
+    String               IMPORT_REFERENCE                          = "reference";
+    String               IMPORT_PRIVATE                            = "private";
+    String[]             importDirectives                          = {
+            IMPORT_REFERENCE, IMPORT_PRIVATE                      };
+
+    static final Pattern VALID_PROPERTY_TYPES                      = Pattern
+                                                                           .compile("(String|Long|Double|Float|Integer|Byte|Character|Boolean|Short)");
+
+    String               DEFAULT_BND_EXTENSION                     = ".bnd";
+    String               DEFAULT_JAR_EXTENSION                     = ".jar";
+    String               DEFAULT_BAR_EXTENSION                     = ".bar";
+    String[]             METAPACKAGES                              = {
+            "META-INF", "OSGI-INF", "OSGI-OPT"                    };
+
+    int                  STRATEGY_HIGHEST                          = 1;
+    int                  STRATEGY_LOWEST                           = -1;
+
+    String               CURRENT_VERSION                           = "@";
+    String               CURRENT_PACKAGE                           = "@package";
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/Constants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/EmbeddedResource.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/EmbeddedResource.java?rev=793527&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/EmbeddedResource.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/EmbeddedResource.java Mon Jul 13 10:06:47 2009
@@ -0,0 +1,88 @@
+/* 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.zip.*;
+
+public class EmbeddedResource implements Resource {
+	byte	data[];
+	long 	lastModified;
+	String	extra;
+
+	public EmbeddedResource(byte data[], long lastModified) {
+		this.data = data;
+		this.lastModified = lastModified;
+	}
+
+	public InputStream openInputStream() throws FileNotFoundException {
+		return new ByteArrayInputStream(data);
+	}
+
+	public void write(OutputStream out) throws IOException {
+		out.write(data);
+	}
+
+	public String toString() {
+		return ":" + data.length + ":";
+	}
+
+	public static void build(Jar jar, InputStream in, long lastModified) throws IOException {
+		ZipInputStream jin = new ZipInputStream(in);
+		ZipEntry entry = jin.getNextEntry();
+		while (entry != null) {
+			if (!entry.isDirectory()) {
+				byte data[] = collect(jin);
+				jar.putResource(entry.getName(), new EmbeddedResource(data, lastModified), true);
+			}
+			entry = jin.getNextEntry();
+		}
+		jin.close();
+	}
+
+	/**
+	 * Convenience method to turn an inputstream into a byte array. The method
+	 * uses a recursive algorithm to minimize memory usage.
+	 * 
+	 * @param in stream with data
+	 * @param offset where we are in the stream
+	 * @returns byte array filled with data
+	 */
+    static byte[] collect(InputStream in) throws IOException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        copy(in,out);
+        return out.toByteArray();
+    }
+
+    static void copy(InputStream in, OutputStream out) throws IOException {
+        int available = in.available();
+        if ( available <= 10000)
+            available = 64000;
+        byte [] buffer = new byte[available];
+        int size;
+        while ( (size=in.read(buffer))>0)
+            out.write(buffer,0,size);
+    }
+
+	public long lastModified() {
+		return lastModified;
+	}
+
+	public static void build(Jar sub, Resource resource) throws IOException {
+			InputStream in = resource.openInputStream();
+			build(sub,in, resource.lastModified());
+			in.close();
+	}
+
+	public String getExtra() {
+		return extra;
+	}
+
+	public void setExtra(String extra) {
+		this.extra = extra;
+	}
+
+	public long size() {
+	    return data.length;
+	}
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/lib/osgi/EmbeddedResource.java
------------------------------------------------------------------------------
    svn:eol-style = native