All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aQute.lib.osgi.Builder Maven / Gradle / Ivy

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.20 $
 */
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                  sourcePath        = new ArrayList();
    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 :  [ ';' 'password:='  ] [ ';' 'keystore:='
     *  ] [ ';' 'sign-password:='  ] ( ',' ... )*
     * 
     * @return
     */

    void sign(Jar jar) throws Exception {
        String signing = getProperty("-sign");
        if (signing == null)
            return;

        trace("Signing %s, with %s", getBsn(), signing);
        List signers = getPlugins(SignerPlugin.class);

        Map> infos = parseHeader(signing);
        for (Map.Entry> 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> conditionals = getHeader(CONDITIONAL_PACKAGE);
        if ( conditionals.isEmpty() )
            return;
        
        int size;
        do {
            size = dot.getDirectories().size();
            analyze();
            analyzed = false;
            Map> imports = getImports();

            // Match the packages specified in conditionals
            // against the imports. Any match must become a
            // Private-Package
            Map> filtered = merge(
                    CONDITIONAL_PACKAGE, conditionals, imports,
                    new HashSet(), null);

            // Imports can also specify a private import. These
            // packages must also be copied to the bundle
            for (Map.Entry> 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> mapOfMap) {
        for (Iterator>> e = mapOfMap
                .entrySet().iterator(); e.hasNext();) {
            Map.Entry> entry = e.next();
            Map attributes = entry.getValue();
            if (attributes.containsKey("version")) {
                attributes.put("version", cleanupVersion(attributes
                        .get("version")));
            }
        }
    }

    /**
     * 
     */
    private void addSources(Jar dot) {
        if (!hasSources())
            return;

        Set packages = new HashSet();

        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 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 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 getSourcePath() {
        if (firstUse) {
            firstUse = false;
            String sp = getProperty(SOURCEPATH);
            if (sp != null) {
                Map> map = parseHeader(sp);
                for (Iterator 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> privateMap = replaceWitInstruction(
                getHeader(PRIVATE_PACKAGE), PRIVATE_PACKAGE);
        Map> 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> instructions,
            boolean mandatory) {
        Set superfluous = removeMarkedDuplicates(instructions
                .keySet());

        for (Iterator 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 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> included, Jar classpathEntry,
            Set superfluous) {

        loop: for (Map.Entry> 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 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 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 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 classpath, File source) {
        // Default is like merge-first, but with a warning
        // Find the culprits
        pack = pack.replace('.', '/');
        List culprits = new ArrayList();
        for (Iterator 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 Instruction matches(
            Map> instructions, String pack,
            Set superfluousPatterns) {
        for (Instruction pattern : instructions.keySet()) {
            if (pattern.matches(pack)) {
                superfluousPatterns.remove(pattern);
                return pattern;
            }
        }
        return null;
    }

    private Map> 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> clauses = parseHeader(includes);

        for (Iterator>> i = clauses
                .entrySet().iterator(); i.hasNext();) {
            Map.Entry> entry = i.next();
            doIncludeResource(jar, entry.getKey(), entry.getValue());
        }
    }

    private void doIncludeResource(Jar jar, String name,
            Map 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 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 directories
                if (sourceFile.isDirectory()) {
                    destinationPath = doResourceDirectory(jar, extra,
                            preprocess, sourceFile, destinationPath);
                    return;
                }
            }

            //destinationPath = checkDestinationPath(destinationPath);

            if (!sourceFile.exists()) {
                noSuchFile(jar, name, extra, source, destinationPath);
            } else
                copy(jar, destinationPath, sourceFile, preprocess, extra);
        }
    }

    private String doResourceDirectory(Jar jar, Map extra,
            boolean preprocess, File sourceFile, String destinationPath)
            throws Exception {
        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.getName();
                }
            } else {
                dp = destinationPath
                        + file.getParentFile().getAbsolutePath()
                                .substring(
                                        sourceFile
                                                .getAbsolutePath()
                                                .length()).replace('\\','/');
                if (dp.length() > 0) {
                    dp += "/" + file.getName();
                } else {
                    dp = file.getName();
                }
            }
            copy(jar, dp, file, preprocess, extra);
        }
        return destinationPath;
    }

    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 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 extra) throws Exception {
        if (doNotCopy.matcher(from.getName()).matches())
            return;

        if (from.isDirectory()) {
            String next = path;
            if (next.length() != 0 && ! next.endsWith("/"))
                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);
                if ( path.endsWith("/"))
                    path = path + from.getName();
                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("");
            ps.println("  4.0.0");
            ps.println("  " + groupId + "");

            n = artifactId.indexOf(';');
            if (n > 0)
                artifactId = artifactId.substring(0, n).trim();

            ps.println("  " + artifactId + "");
            ps.println("  " + version + "");
            if (description != null) {
                ps.println("  ");
                ps.print("    ");
                ps.println(description);
                ps.println("  ");
            }
            if (name != null) {
                ps.print("  ");
                ps.print(name);
                ps.println("");
            }
            if (docUrl != null) {
                ps.print("  ");
                ps.print(docUrl);
                ps.println("");
            }

            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("  ");
                ps.print("    ");
                ps.print(namePart.trim());
                ps.println("");
                if (urlPart != null) {
                    ps.print("    ");
                    ps.print(urlPart.trim());
                    ps.println("");
                }
                ps.println("  ");
            }
            if (licenses != null) {
                ps.println("  ");
                Map> map = parseHeader(licenses);
                for (Iterator>> e = map
                        .entrySet().iterator(); e.hasNext();) {
                    Map.Entry> entry = e.next();
                    ps.println("    ");
                    Map 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("    ");
                }
                ps.println("  ");
            }
            ps.println("");
            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 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() + "");
    }

    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> 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 result = new ArrayList();

        // Get the Instruction objects that match the sub header
        Set subs = replaceWitInstruction(parseHeader(sub), SUB)
                .keySet();

        // Get the member files of this directory
        List members = new ArrayList(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 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 set = new HashSet(Arrays
                .asList(BUNDLE_SPECIFIC_HEADERS));
        setForceLocal(set);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy