Search in sources :

Example 1 with PackageRef

use of aQute.bnd.osgi.Descriptors.PackageRef in project felix by apache.

the class BlueprintPlugin method analyzeJar.

public boolean analyzeJar(Analyzer analyzer) throws Exception {
    String mode = analyzer.getProperty("service_mode");
    if (mode == null) {
        mode = "service";
    }
    transformer.setParameter("nsh_interface", analyzer.getProperty("nsh_interface") != null ? analyzer.getProperty("nsh_interface") : "");
    transformer.setParameter("nsh_namespace", analyzer.getProperty("nsh_namespace") != null ? analyzer.getProperty("nsh_namespace") : "");
    Set<String> headers = Create.set();
    String bpHeader = analyzer.getProperty("Bundle-Blueprint", "OSGI-INF/blueprint");
    Map<String, ? extends Map<String, String>> map = Processor.parseHeader(bpHeader, null);
    bpHeader = "";
    for (String root : map.keySet()) {
        Jar jar = analyzer.getJar();
        Map<String, Resource> dir = jar.getDirectories().get(root);
        if (dir == null || dir.isEmpty()) {
            Resource resource = jar.getResource(root);
            if (resource != null) {
                process(analyzer, root, resource, headers);
                if (bpHeader.length() > 0) {
                    bpHeader += ",";
                }
                bpHeader += root;
            }
            continue;
        }
        for (Map.Entry<String, Resource> entry : dir.entrySet()) {
            String path = entry.getKey();
            Resource resource = entry.getValue();
            if (PATHS.matcher(path).matches()) {
                process(analyzer, path, resource, headers);
                if (bpHeader.length() > 0) {
                    bpHeader += ",";
                }
                bpHeader += path;
            }
        }
    }
    if (!map.isEmpty()) {
        analyzer.setProperty("Bundle-Blueprint", bpHeader);
    }
    // Group and analyze
    Set<String> caps = Create.set();
    Set<String> reqs = Create.set();
    Map<String, Set<Clause>> hdrs = Create.map();
    for (String str : headers) {
        int idx = str.indexOf(':');
        if (idx < 0) {
            analyzer.warning((new StringBuilder("Error analyzing services in blueprint resource: ")).append(str).toString());
            continue;
        }
        String h = str.substring(0, idx).trim();
        String v = str.substring(idx + 1).trim();
        Clause[] hc = parseHeader(v);
        // Convert generic caps/reqs
        if ("Import-Service".equals(h)) {
            if (!"service".equals(mode)) {
                Clause clause = hc[0];
                String multiple = clause.getDirective("multiple");
                String avail = clause.getDirective("availability");
                String filter = clause.getAttribute("filter");
                StringBuilder sb = new StringBuilder();
                sb.append("osgi.service;effective:=active;");
                if ("optional".equals(avail)) {
                    sb.append("resolution:=optional;");
                }
                if ("true".equals(multiple)) {
                    sb.append("cardinality:=multiple;");
                }
                if (filter == null) {
                    filter = "(" + Constants.OBJECTCLASS + "=" + clause.getName() + ")";
                } else if (!filter.startsWith("(") && !filter.endsWith(")")) {
                    filter = "(&(" + Constants.OBJECTCLASS + "=" + clause.getName() + ")(" + filter + "))";
                } else {
                    filter = "(&(" + Constants.OBJECTCLASS + "=" + clause.getName() + ")" + filter + ")";
                }
                sb.append("filter:=\"").append(filter).append("\"");
                reqs.add(sb.toString());
            } else if (!"generic".equals(mode)) {
                Set<Clause> clauses = hdrs.get(h);
                if (clauses == null) {
                    clauses = new HashSet<Clause>();
                    hdrs.put(h, clauses);
                }
                clauses.addAll(Arrays.asList(hc));
            }
        } else if ("Export-Service".equals(h)) {
            if (!"service".equals(mode)) {
                StringBuilder sb = new StringBuilder();
                sb.append("osgi.service;effective:=active;objectClass");
                if (hc.length > 1) {
                    sb.append(":List<String>=\"");
                } else {
                    sb.append("=\"");
                }
                for (int i = 0; i < hc.length; i++) {
                    if (i > 0) {
                        sb.append(",");
                    }
                    sb.append(hc[i].getName());
                }
                sb.append("\"");
                for (int i = 0; i < hc[0].getAttributes().length; i++) {
                    sb.append(";");
                    sb.append(hc[0].getAttributes()[i].getName());
                    sb.append("=\"");
                    sb.append(hc[0].getAttributes()[i].getValue());
                    sb.append("\"");
                }
                caps.add(sb.toString());
            } else if (!"generic".equals(mode)) {
                Set<Clause> clauses = hdrs.get(h);
                if (clauses == null) {
                    clauses = new HashSet<Clause>();
                    hdrs.put(h, clauses);
                }
                clauses.addAll(Arrays.asList(hc));
            }
        } else {
            Set<Clause> clauses = hdrs.get(h);
            if (clauses == null) {
                clauses = new HashSet<Clause>();
                hdrs.put(h, clauses);
            }
            clauses.addAll(Arrays.asList(hc));
        }
    }
    if (!caps.isEmpty()) {
        StringBuilder sb = new StringBuilder();
        String header = analyzer.getProperty("Provide-Capability");
        if (header != null) {
            sb.append(header);
        }
        for (String cap : caps) {
            if (sb.length() > 0) {
                sb.append(",");
            }
            sb.append(cap);
        }
        analyzer.setProperty("Provide-Capability", sb.toString());
    }
    if (!reqs.isEmpty()) {
        StringBuilder sb = new StringBuilder();
        String header = analyzer.getProperty("Require-Capability");
        if (header != null) {
            sb.append(header);
        }
        for (String req : reqs) {
            if (sb.length() > 0) {
                sb.append(",");
            }
            sb.append(req);
        }
        analyzer.setProperty("Require-Capability", sb.toString());
    }
    // Merge
    for (String header : hdrs.keySet()) {
        if ("Import-Class".equals(header) || "Import-Package".equals(header)) {
            Set<Clause> newAttr = hdrs.get(header);
            for (Clause a : newAttr) {
                String pkg = a.getName();
                if ("Import-Class".equals(header)) {
                    int n = a.getName().lastIndexOf('.');
                    if (n > 0) {
                        pkg = pkg.subSequence(0, n).toString();
                    } else {
                        continue;
                    }
                }
                PackageRef pkgRef = analyzer.getPackageRef(pkg);
                if (!analyzer.getReferred().containsKey(pkgRef)) {
                    Attrs attrs = analyzer.getReferred().put(pkgRef);
                    for (Attribute attribute : a.getAttributes()) {
                        attrs.put(attribute.getName(), attribute.getValue());
                    }
                }
            }
        } else {
            Set<String> merge = Create.set();
            String org = analyzer.getProperty(header);
            if (org != null && !org.isEmpty()) {
                for (Clause clause : parseHeader(org)) {
                    merge.add(clause.toString());
                }
            }
            for (Clause clause : hdrs.get(header)) {
                merge.add(clause.toString());
            }
            StringBuilder sb = new StringBuilder();
            for (String clause : merge) {
                if (sb.length() > 0) {
                    sb.append(",");
                }
                sb.append(clause);
            }
            analyzer.setProperty(header, sb.toString());
        }
    }
    return false;
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) Attribute(org.apache.felix.utils.manifest.Attribute) Resource(aQute.bnd.osgi.Resource) Attrs(aQute.bnd.header.Attrs) Jar(aQute.bnd.osgi.Jar) Clause(org.apache.felix.utils.manifest.Clause) PackageRef(aQute.bnd.osgi.Descriptors.PackageRef) Map(java.util.Map) HashSet(java.util.HashSet)

Example 2 with PackageRef

use of aQute.bnd.osgi.Descriptors.PackageRef in project felix by apache.

the class BundlePlugin method addLocalPackages.

private static void addLocalPackages(File outputDirectory, Analyzer analyzer) throws IOException {
    Packages packages = new Packages();
    if (outputDirectory != null && outputDirectory.isDirectory()) {
        // scan classes directory for potential packages
        DirectoryScanner scanner = new DirectoryScanner();
        scanner.setBasedir(outputDirectory);
        scanner.setIncludes(new String[] { "**/*.class" });
        scanner.addDefaultExcludes();
        scanner.scan();
        String[] paths = scanner.getIncludedFiles();
        for (int i = 0; i < paths.length; i++) {
            packages.put(analyzer.getPackageRef(getPackageName(paths[i])));
        }
    }
    Packages exportedPkgs = new Packages();
    Packages privatePkgs = new Packages();
    boolean noprivatePackages = "!*".equals(analyzer.getProperty(Analyzer.PRIVATE_PACKAGE));
    for (PackageRef pkg : packages.keySet()) {
        // mark all source packages as private by default (can be overridden by export list)
        privatePkgs.put(pkg);
        // we can't export the default package (".") and we shouldn't export internal packages
        String fqn = pkg.getFQN();
        if (noprivatePackages || !(".".equals(fqn) || fqn.contains(".internal") || fqn.contains(".impl"))) {
            exportedPkgs.put(pkg);
        }
    }
    Properties properties = analyzer.getProperties();
    String exported = properties.getProperty(Analyzer.EXPORT_PACKAGE);
    if (exported == null) {
        if (!properties.containsKey(Analyzer.EXPORT_CONTENTS)) {
            // no -exportcontents overriding the exports, so use our computed list
            for (Attrs attrs : exportedPkgs.values()) {
                attrs.put(Constants.SPLIT_PACKAGE_DIRECTIVE, "merge-first");
            }
            properties.setProperty(Analyzer.EXPORT_PACKAGE, Processor.printClauses(exportedPkgs));
        } else {
            // leave Export-Package empty (but non-null) as we have -exportcontents
            properties.setProperty(Analyzer.EXPORT_PACKAGE, "");
        }
    } else if (exported.indexOf(LOCAL_PACKAGES) >= 0) {
        String newExported = StringUtils.replace(exported, LOCAL_PACKAGES, Processor.printClauses(exportedPkgs));
        properties.setProperty(Analyzer.EXPORT_PACKAGE, newExported);
    }
    String internal = properties.getProperty(Analyzer.PRIVATE_PACKAGE);
    if (internal == null) {
        if (!privatePkgs.isEmpty()) {
            for (Attrs attrs : privatePkgs.values()) {
                attrs.put(Constants.SPLIT_PACKAGE_DIRECTIVE, "merge-first");
            }
            properties.setProperty(Analyzer.PRIVATE_PACKAGE, Processor.printClauses(privatePkgs));
        } else {
            // if there are really no private packages then use "!*" as this will keep the Bnd Tool happy
            properties.setProperty(Analyzer.PRIVATE_PACKAGE, "!*");
        }
    } else if (internal.indexOf(LOCAL_PACKAGES) >= 0) {
        String newInternal = StringUtils.replace(internal, LOCAL_PACKAGES, Processor.printClauses(privatePkgs));
        properties.setProperty(Analyzer.PRIVATE_PACKAGE, newInternal);
    }
}
Also used : Packages(aQute.bnd.osgi.Packages) DirectoryScanner(org.codehaus.plexus.util.DirectoryScanner) Attrs(aQute.bnd.header.Attrs) PackageRef(aQute.bnd.osgi.Descriptors.PackageRef) Properties(java.util.Properties)

Example 3 with PackageRef

use of aQute.bnd.osgi.Descriptors.PackageRef in project bnd by bndtools.

the class Analyzer method filter.

/**
	 * Merge the attributes of two maps, where the first map can contain
	 * wildcarded names. The idea is that the first map contains instructions
	 * (for example *) with a set of attributes. These patterns are matched
	 * against the found packages in actual. If they match, the result is set
	 * with the merged set of attributes. It is expected that the instructions
	 * are ordered so that the instructor can define which pattern matches
	 * first. Attributes in the instructions override any attributes from the
	 * actual.<br/>
	 * A pattern is a modified regexp so it looks like globbing. The * becomes a
	 * .* just like the ? becomes a .?. '.' are replaced with \\. Additionally,
	 * if the pattern starts with an exclamation mark, it will remove that
	 * matches for that pattern (- the !) from the working set. So the following
	 * patterns should work:
	 * <ul>
	 * <li>com.foo.bar</li>
	 * <li>com.foo.*</li>
	 * <li>com.foo.???</li>
	 * <li>com.*.[^b][^a][^r]</li>
	 * <li>!com.foo.* (throws away any match for com.foo.*)</li>
	 * </ul>
	 * Enough rope to hang the average developer I would say.
	 * 
	 * @param instructions the instructions with patterns.
	 * @param source the actual found packages, contains no duplicates
	 * @return Only the packages that were filtered by the given instructions
	 */
Packages filter(Instructions instructions, Packages source, Set<Instruction> nomatch) {
    Packages result = new Packages();
    List<PackageRef> refs = new ArrayList<PackageRef>(source.keySet());
    Collections.sort(refs);
    List<Instruction> filters = new ArrayList<Instruction>(instructions.keySet());
    if (nomatch == null)
        nomatch = Create.set();
    for (Instruction instruction : filters) {
        boolean match = false;
        for (Iterator<PackageRef> i = refs.iterator(); i.hasNext(); ) {
            PackageRef packageRef = i.next();
            if (packageRef.isMetaData()) {
                // no use checking it again
                i.remove();
                continue;
            }
            String packageName = packageRef.getFQN();
            if (instruction.matches(packageName)) {
                match = true;
                if (!instruction.isNegated()) {
                    result.merge(packageRef, instruction.isDuplicate(), source.get(packageRef), instructions.get(instruction));
                }
                // Can never match again for another pattern
                i.remove();
            }
        }
        if (!match && !instruction.isAny())
            nomatch.add(instruction);
    }
    for (Iterator<Instruction> i = nomatch.iterator(); i.hasNext(); ) {
        Instruction instruction = i.next();
        // #252, we should not be negated to make it a constant
        if (instruction.isLiteral() && !instruction.isNegated()) {
            result.merge(getPackageRef(instruction.getLiteral()), true, instructions.get(instruction));
            i.remove();
            continue;
        }
        // the !package will never match anymore.
        if (instruction.isNegated()) {
            i.remove();
            continue;
        }
        // an error
        if (instruction.isOptional()) {
            i.remove();
            continue;
        }
    // boolean matched = false;
    // Set<PackageRef> prefs = new HashSet<PackageRef>(result.keySet());
    // for (PackageRef ref : prefs) {
    // if (instruction.matches(ref.getFQN())) {
    // result.merge(ref, true, source.get(ref),
    // instructions.get(instruction));
    // matched = true;
    // }
    // }
    // if (matched)
    // i.remove();
    }
    return result;
}
Also used : ArrayList(java.util.ArrayList) PackageRef(aQute.bnd.osgi.Descriptors.PackageRef)

Example 4 with PackageRef

use of aQute.bnd.osgi.Descriptors.PackageRef in project bnd by bndtools.

the class Analyzer method doUses.

/**
	 * Add the uses clauses. This method iterates over the exports and cal
	 * 
	 * @param exports
	 * @param uses
	 * @throws MojoExecutionException
	 */
void doUses(Packages exports, Map<PackageRef, List<PackageRef>> uses, Packages imports) {
    if (isTrue(getProperty(NOUSES)))
        return;
    for (Iterator<PackageRef> i = exports.keySet().iterator(); i.hasNext(); ) {
        PackageRef packageRef = i.next();
        String packageName = packageRef.getFQN();
        setProperty(CURRENT_PACKAGE, packageName);
        try {
            doUses(packageRef, exports, uses, imports);
        } finally {
            unsetProperty(CURRENT_PACKAGE);
        }
    }
}
Also used : PackageRef(aQute.bnd.osgi.Descriptors.PackageRef)

Example 5 with PackageRef

use of aQute.bnd.osgi.Descriptors.PackageRef in project bnd by bndtools.

the class Analyzer method analyze.

/**
	 * Calculates the data structures for generating a manifest.
	 * 
	 * @throws IOException
	 */
public void analyze() throws Exception {
    if (!analyzed) {
        analyzed = true;
        uses.clear();
        apiUses.clear();
        classspace.clear();
        classpathExports.clear();
        contracts.clear();
        packagesVisited.clear();
        // Parse all the class in the
        // the jar according to the OSGi bcp
        analyzeBundleClasspath();
        for (Jar current : getClasspath()) {
            getManifestInfoFromClasspath(current, classpathExports, contracts);
            Manifest m = current.getManifest();
            if (m == null)
                for (String dir : current.getDirectories().keySet()) {
                    learnPackage(current, "", getPackageRef(dir), classpathExports);
                }
        }
        // Handle the bundle activator
        String s = getProperty(BUNDLE_ACTIVATOR);
        if (s != null && !s.isEmpty()) {
            activator = getTypeRefFromFQN(s);
            referTo(activator);
            logger.debug("activator {} {}", s, activator);
        }
        // Conditional packages
        doConditionalPackages();
        // Execute any plugins
        // TODO handle better reanalyze
        doPlugins();
        //
        for (Clazz c : classspace.values()) {
            ees.add(c.getFormat());
        }
        if (since(About._2_3)) {
            try (ClassDataCollectors cds = new ClassDataCollectors(this)) {
                List<ClassParser> parsers = getPlugins(ClassParser.class);
                for (ClassParser cp : parsers) {
                    cds.add(cp.getClassDataCollector(this));
                }
                //
                // built ins
                //
                cds.add(annotationHeaders = new AnnotationHeaders(this));
                for (Clazz c : classspace.values()) {
                    cds.parse(c);
                }
            }
        }
        referred.keySet().removeAll(contained.keySet());
        //
        // EXPORTS
        //
        {
            Set<Instruction> unused = Create.set();
            Instructions filter = new Instructions(getExportPackage());
            filter.append(getExportContents());
            exports = filter(filter, contained, unused);
            if (!unused.isEmpty()) {
                warning("Unused " + Constants.EXPORT_PACKAGE + " instructions: %s ", unused).header(Constants.EXPORT_PACKAGE).context(unused.iterator().next().input);
            }
            // See what information we can find to augment the
            // exports. I.e. look on the classpath
            augmentExports(exports);
        }
        //
        // IMPORTS
        // Imports MUST come after exports because we use information from
        // the exports
        //
        {
            // Add all exports that do not have an -noimport: directive
            // to the imports.
            Packages referredAndExported = new Packages(referred);
            referredAndExported.putAll(doExportsToImports(exports));
            removeDynamicImports(referredAndExported);
            // Remove any Java references ... where are the closures???
            for (Iterator<PackageRef> i = referredAndExported.keySet().iterator(); i.hasNext(); ) {
                if (i.next().isJava())
                    i.remove();
            }
            Set<Instruction> unused = Create.set();
            String h = getProperty(IMPORT_PACKAGE);
            if (// If not set use a default
            h == null)
                h = "*";
            if (isPedantic() && h.trim().length() == 0)
                warning("Empty " + Constants.IMPORT_PACKAGE + " header");
            Instructions filter = new Instructions(h);
            imports = filter(filter, referredAndExported, unused);
            if (!unused.isEmpty()) {
                // We ignore the end wildcard catch
                if (!(unused.size() == 1 && unused.iterator().next().toString().equals("*")))
                    warning("Unused " + Constants.IMPORT_PACKAGE + " instructions: %s ", unused).header(Constants.IMPORT_PACKAGE).context(unused.iterator().next().input);
            }
            // See what information we can find to augment the
            // imports. I.e. look in the exports
            augmentImports(imports, exports);
        }
        //
        // USES
        //
        // Add the uses clause to the exports
        // brave,
        boolean api = true;
        // lets see
        doUses(exports, api ? apiUses : uses, imports);
        //
        // Verify that no exported package has a reference to a private
        // package
        // This can cause a lot of harm.
        // TODO restrict the check to public API only, but even then
        // exported packages
        // should preferably not refer to private packages.
        //
        Set<PackageRef> privatePackages = getPrivates();
        for (Iterator<PackageRef> p = privatePackages.iterator(); p.hasNext(); ) if (p.next().isJava())
            p.remove();
        for (PackageRef exported : exports.keySet()) {
            List<PackageRef> used = uses.get(exported);
            if (used != null) {
                Set<PackageRef> privateReferences = new HashSet<PackageRef>(apiUses.get(exported));
                privateReferences.retainAll(privatePackages);
                if (!privateReferences.isEmpty())
                    msgs.Export_Has_PrivateReferences_(exported, privateReferences.size(), privateReferences);
            }
        }
        //
        if (referred.containsKey(Descriptors.DEFAULT_PACKAGE)) {
            error("The default package '.' is not permitted by the " + Constants.IMPORT_PACKAGE + " syntax.%n" + " This can be caused by compile errors in Eclipse because Eclipse creates%n" + "valid class files regardless of compile errors.%n" + "The following package(s) import from the default package %s", uses.transpose().get(Descriptors.DEFAULT_PACKAGE));
        }
    }
}
Also used : SortedSet(java.util.SortedSet) EnumSet(java.util.EnumSet) Set(java.util.Set) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) Manifest(java.util.jar.Manifest) Iterator(java.util.Iterator) PackageRef(aQute.bnd.osgi.Descriptors.PackageRef) ClassParser(aQute.bnd.service.classparser.ClassParser) HashSet(java.util.HashSet)

Aggregations

PackageRef (aQute.bnd.osgi.Descriptors.PackageRef)40 Attrs (aQute.bnd.header.Attrs)18 Analyzer (aQute.bnd.osgi.Analyzer)9 Clazz (aQute.bnd.osgi.Clazz)8 Map (java.util.Map)8 Parameters (aQute.bnd.header.Parameters)7 TypeRef (aQute.bnd.osgi.Descriptors.TypeRef)7 MultiMap (aQute.lib.collections.MultiMap)7 HashSet (java.util.HashSet)7 TreeSet (java.util.TreeSet)7 Manifest (java.util.jar.Manifest)7 Jar (aQute.bnd.osgi.Jar)6 Resource (aQute.bnd.osgi.Resource)6 Descriptors (aQute.bnd.osgi.Descriptors)5 ClassDataCollector (aQute.bnd.osgi.ClassDataCollector)4 File (java.io.File)4 FileInputStream (java.io.FileInputStream)4 InputStream (java.io.InputStream)4 HashMap (java.util.HashMap)4 Entry (java.util.Map.Entry)4