aQute.bnd.component.DSAnnotations Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of biz.aQute.bndlib Show documentation
Show all versions of biz.aQute.bndlib Show documentation
bndlib: A Swiss Army Knife for OSGi
package aQute.bnd.component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.osgi.service.component.annotations.ReferenceCardinality;
import aQute.bnd.header.Attrs;
import aQute.bnd.header.OSGiHeader;
import aQute.bnd.header.Parameters;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Clazz;
import aQute.bnd.osgi.Constants;
import aQute.bnd.osgi.Descriptors;
import aQute.bnd.osgi.Instruction;
import aQute.bnd.osgi.Instructions;
import aQute.bnd.osgi.Processor;
import aQute.bnd.service.AnalyzerPlugin;
import aQute.bnd.version.Version;
import aQute.bnd.xmlattribute.XMLAttributeFinder;
import aQute.lib.strings.Strings;
/**
* Analyze the class space for any classes that have an OSGi annotation for DS.
*/
public class DSAnnotations implements AnalyzerPlugin {
public enum Options {
inherit, felixExtensions, extender, nocapabilities, norequirements
};
public boolean analyzeJar(Analyzer analyzer) throws Exception {
Parameters header = OSGiHeader.parseHeader(analyzer.getProperty(Constants.DSANNOTATIONS, "*"));
if (header.size() == 0)
return false;
Parameters optionsHeader = OSGiHeader.parseHeader(analyzer.getProperty(Constants.DSANNOTATIONS_OPTIONS));
EnumSet options = EnumSet.noneOf(Options.class);
for (String s : optionsHeader.keySet()) {
try {
options.add(Options.valueOf(s));
} catch (IllegalArgumentException e) {
analyzer.error("Unrecognized %s value %s, expected values are %s", Constants.DSANNOTATIONS_OPTIONS, s,
EnumSet.allOf(Options.class));
}
}
// obsolete but backwards compatible, use the options instead
if (Processor.isTrue(analyzer.getProperty("-dsannotations-inherit")))
options.add(Options.inherit);
if (Processor.isTrue(analyzer.getProperty("-ds-felix-extensions")))
options.add(Options.felixExtensions);
Instructions instructions = new Instructions(header);
Collection list = analyzer.getClassspace().values();
String sc = analyzer.getProperty(Constants.SERVICE_COMPONENT);
List names = new ArrayList();
if (sc != null && sc.trim().length() > 0)
names.add(sc);
TreeSet provides = new TreeSet();
TreeSet requires = new TreeSet();
Version maxVersion = AnnotationReader.V1_0;
XMLAttributeFinder finder = new XMLAttributeFinder(analyzer);
for (Clazz c : list) {
for (Instruction instruction : instructions.keySet()) {
if (instruction.matches(c.getFQN())) {
if (instruction.isNegated())
break;
ComponentDef definition = AnnotationReader.getDefinition(c, analyzer, options, finder);
if (definition != null) {
definition.sortReferences();
definition.prepare(analyzer);
String name = "OSGI-INF/"
+ analyzer.validResourcePath(definition.name, "Invalid component name") + ".xml";
names.add(name);
analyzer.getJar().putResource(name, new TagResource(definition.getTag()));
if (definition.service != null && !options.contains(Options.nocapabilities)) {
String[] objectClass = new String[definition.service.length];
for (int i = 0; i < definition.service.length; i++) {
Descriptors.TypeRef tr = definition.service[i];
objectClass[i] = tr.getFQN();
}
Arrays.sort(objectClass);
addServiceCapability(objectClass, provides);
}
if (!options.contains(Options.norequirements)) {
MergedRequirement serviceReqMerge = new MergedRequirement("osgi.service");
for (ReferenceDef ref : definition.references.values()) {
addServiceRequirement(ref, serviceReqMerge);
}
requires.addAll(serviceReqMerge.toStringList());
}
maxVersion = ComponentDef.max(maxVersion, definition.version);
}
}
}
}
if (options.contains(Options.extender) || maxVersion.compareTo(AnnotationReader.V1_3) >= 0) {
maxVersion = ComponentDef.max(maxVersion, AnnotationReader.V1_3);
addExtenderRequirement(requires, maxVersion);
}
sc = Processor.append(names.toArray(new String[0]));
analyzer.setProperty(Constants.SERVICE_COMPONENT, sc);
updateHeader(analyzer, Constants.REQUIRE_CAPABILITY, requires);
updateHeader(analyzer, Constants.PROVIDE_CAPABILITY, provides);
return false;
}
private void addServiceCapability(String[] objectClass, Set provides) {
if (objectClass.length > 0) {
Parameters p = new Parameters();
Attrs a = new Attrs();
StringBuilder sb = new StringBuilder();
String sep = "";
for (String oc : objectClass) {
sb.append(sep).append(oc);
sep = ",";
}
a.put("objectClass:List", sb.toString());
p.put("osgi.service", a);
String s = p.toString();
provides.add(s);
}
}
private void addServiceRequirement(ReferenceDef ref, MergedRequirement requires) {
String objectClass = ref.service;
ReferenceCardinality cardinality = ref.cardinality;
boolean optional = cardinality == ReferenceCardinality.OPTIONAL || cardinality == ReferenceCardinality.MULTIPLE;
boolean multiple = cardinality == ReferenceCardinality.MULTIPLE
|| cardinality == ReferenceCardinality.AT_LEAST_ONE;
String filter = "(objectClass=" + objectClass + ")";
requires.put(filter, "active", optional, multiple);
}
private void addExtenderRequirement(Set requires, Version version) {
Version next = new Version(version.getMajor() + 1);
Parameters p = new Parameters();
Attrs a = new Attrs();
a.put(Constants.FILTER_DIRECTIVE,
"\"(&(osgi.extender=osgi.component)(version>=" + version + ")(!(version>=" + next + ")))\"");
p.put("osgi.extender", a);
String s = p.toString();
requires.add(s);
}
/**
* Updates specified header, sorting and removing duplicates. Destroys
* contents of set parameter.
*
* @param analyzer
* @param name header name
* @param set values to add to header; contents are not preserved.
*/
private void updateHeader(Analyzer analyzer, String name, TreeSet set) {
if (!set.isEmpty()) {
String value = analyzer.getProperty(name);
if (value != null) {
Parameters p = OSGiHeader.parseHeader(value);
for (Map.Entry entry : p.entrySet()) {
StringBuilder sb = new StringBuilder(entry.getKey());
if (entry.getValue() != null) {
sb.append(";");
entry.getValue().append(sb);
}
set.add(sb.toString());
}
}
String header = Strings.join(set);
analyzer.setProperty(name, header);
}
}
@Override
public String toString() {
return "DSAnnotations";
}
}