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