use of aQute.bnd.osgi.Clazz.MethodDef in project bnd by bndtools.
the class HeaderReader method getNamespace.
/**
* Check if we need to use the v1.1 namespace (or later).
*
* @param info
* @param cd TODO
* @param descriptors TODO
*/
private void getNamespace(Map<String, String> info, ComponentDef cd, Map<String, MethodDef> descriptors) {
String namespace = info.get(COMPONENT_NAMESPACE);
if (namespace != null) {
cd.xmlns = namespace;
}
String version = info.get(COMPONENT_VERSION);
if (version != null) {
try {
Version v = new Version(version);
cd.updateVersion(v);
} catch (Exception e) {
error("version: specified on component header but not a valid version: %s", version);
return;
}
}
for (String key : info.keySet()) {
if (SET_COMPONENT_DIRECTIVES_1_2.contains(key)) {
cd.updateVersion(AnnotationReader.V1_2);
return;
}
}
for (ReferenceDef rd : cd.references.values()) {
if (rd.updated != null) {
cd.updateVersion(AnnotationReader.V1_2);
return;
}
}
// among other things this picks up any specified lifecycle methods
for (String key : info.keySet()) {
if (SET_COMPONENT_DIRECTIVES_1_1.contains(key)) {
cd.updateVersion(AnnotationReader.V1_1);
return;
}
}
for (String lifecycle : LIFECYCLE_METHODS) {
// lifecycle methods were not specified.... check for non 1.0
// signatures.
MethodDef test = descriptors.get(lifecycle);
if (descriptors.containsKey(lifecycle) && (!(test.isPublic() || test.isProtected()) || rateLifecycle(test, "deactivate".equals(lifecycle) ? allowedDeactivate : allowed) > 1)) {
cd.updateVersion(AnnotationReader.V1_1);
return;
}
}
}
use of aQute.bnd.osgi.Clazz.MethodDef in project bnd by bndtools.
the class AnnotationReader method doDeactivate.
/**
*
*/
protected void doDeactivate() {
String methodDescriptor = member.getDescriptor().toString();
DeclarativeServicesAnnotationError details = new DeclarativeServicesAnnotationError(className.getFQN(), member.getName(), methodDescriptor, ErrorType.DEACTIVATE_SIGNATURE_ERROR);
if (!(member instanceof MethodDef)) {
analyzer.error("Deactivate annotation on a field %s.%s", clazz, member.getDescriptor()).details(details);
return;
}
boolean hasMapReturnType = false;
Matcher m = LIFECYCLEDESCRIPTORDS10.matcher(methodDescriptor);
if ("deactivate".equals(member.getName()) && m.matches()) {
component.deactivate = member.getName();
hasMapReturnType = m.group(3) != null;
if (!member.isProtected())
component.updateVersion(V1_1);
} else {
m = DEACTIVATEDESCRIPTORDS11.matcher(methodDescriptor);
if (m.matches()) {
component.deactivate = member.getName();
component.updateVersion(V1_1);
hasMapReturnType = m.group(8) != null;
} else {
m = DEACTIVATEDESCRIPTORDS13.matcher(methodDescriptor);
if (m.matches()) {
component.deactivate = member.getName();
component.updateVersion(V1_3);
hasMapReturnType = m.group(6) != null;
processAnnotationArguments(methodDescriptor, details);
} else
analyzer.error("Deactivate method for %s descriptor %s is not acceptable.", clazz, member.getDescriptor()).details(details);
}
}
checkMapReturnType(hasMapReturnType, details);
}
use of aQute.bnd.osgi.Clazz.MethodDef in project bnd by bndtools.
the class AnnotationReader method doReference.
/**
* @param reference @Reference proxy backed by raw.
* @param raw @Reference contents
* @throws Exception
*/
protected void doReference(Reference reference, Annotation raw) throws Exception {
ReferenceDef def;
if (member == null)
def = new ReferenceDef(finder);
else if (referencesByMember.containsKey(member))
def = referencesByMember.get(member);
else {
def = new ReferenceDef(finder);
referencesByMember.put(member, def);
}
def.className = className.getFQN();
def.name = reference.name();
def.bind = reference.bind();
def.unbind = reference.unbind();
def.updated = reference.updated();
def.field = reference.field();
def.fieldOption = reference.fieldOption();
def.cardinality = reference.cardinality();
def.policy = reference.policy();
def.policyOption = reference.policyOption();
def.scope = reference.scope();
// Check if we have a target, this must be a filter
def.target = reference.target();
DeclarativeServicesAnnotationError details = getDetails(def, ErrorType.REFERENCE);
if (def.target != null) {
String error = Verifier.validateFilter(def.target);
if (error != null)
analyzer.error("Invalid target filter %s for %s: %s", def.target, def.name, error).details(getDetails(def, ErrorType.INVALID_TARGET_FILTER));
}
String annoService = null;
TypeRef annoServiceTR = raw.get("service");
if (annoServiceTR != null)
annoService = annoServiceTR.getFQN();
if (member != null) {
if (member instanceof MethodDef) {
def.bindDescriptor = member.getDescriptor().toString();
if (!member.isProtected())
def.updateVersion(V1_1);
def.bind = member.getName();
if (def.name == null) {
Matcher m = BINDNAME.matcher(member.getName());
if (m.matches())
def.name = m.group(2);
else
analyzer.error("Invalid name for bind method %s", member.getName()).details(getDetails(def, ErrorType.INVALID_REFERENCE_BIND_METHOD_NAME));
}
def.service = determineReferenceType(def.bindDescriptor, def, annoService, member.getSignature());
if (def.service == null)
analyzer.error("In component %s, method %s, cannot recognize the signature of the descriptor: %s", component.effectiveName(), def.name, member.getDescriptor());
} else if (member instanceof FieldDef) {
def.updateVersion(V1_3);
def.field = member.getName();
if (def.name == null)
def.name = def.field;
if (def.policy == null && member.isVolatile())
def.policy = ReferencePolicy.DYNAMIC;
String sig = member.getSignature();
if (sig == null)
// no generics, the descriptor will be the class name.
sig = member.getDescriptor().toString();
String[] sigs = sig.split("[<;>]");
int sigLength = sigs.length;
int index = 0;
boolean isCollection = false;
if ("Ljava/util/Collection".equals(sigs[index]) || "Ljava/util/List".equals(sigs[index])) {
index++;
isCollection = true;
}
// Along with determining the FieldCollectionType, the following
// code positions index to read the service type.
FieldCollectionType fieldCollectionType = null;
if (sufficientGenerics(index, sigLength, def, sig)) {
if ("Lorg/osgi/framework/ServiceReference".equals(sigs[index])) {
if (sufficientGenerics(index++, sigLength, def, sig)) {
fieldCollectionType = FieldCollectionType.reference;
}
} else if ("Lorg/osgi/service/component/ComponentServiceObjects".equals(sigs[index])) {
if (sufficientGenerics(index++, sigLength, def, sig)) {
fieldCollectionType = FieldCollectionType.serviceobjects;
}
} else if ("Ljava/util/Map".equals(sigs[index])) {
if (sufficientGenerics(index++, sigLength, def, sig)) {
fieldCollectionType = FieldCollectionType.properties;
}
} else if ("Ljava/util/Map$Entry".equals(sigs[index]) && sufficientGenerics(index++ + 5, sigLength, def, sig)) {
if ("Ljava/util/Map".equals(sigs[index++]) && "Ljava/lang/String".equals(sigs[index++])) {
if ("Ljava/lang/Object".equals(sigs[index]) || "+Ljava/lang/Object".equals(sigs[index])) {
fieldCollectionType = FieldCollectionType.tuple;
// ;>;
index += 3;
} else if ("*".equals(sigs[index])) {
fieldCollectionType = FieldCollectionType.tuple;
// >;
index += 2;
} else {
// no idea what service might
index = sigLength;
// be.
}
}
} else {
fieldCollectionType = FieldCollectionType.service;
}
}
if (isCollection) {
if (def.cardinality == null)
def.cardinality = ReferenceCardinality.MULTIPLE;
def.fieldCollectionType = fieldCollectionType;
}
if (def.policy == ReferencePolicy.DYNAMIC && (def.cardinality == ReferenceCardinality.MULTIPLE || def.cardinality == ReferenceCardinality.AT_LEAST_ONE) && member.isFinal()) {
if (def.fieldOption == FieldOption.REPLACE)
analyzer.error("In component %s, collection type field: %s is final and dynamic but marked with 'replace' fieldOption. Changing this to 'update'.", className, def.field).details(getDetails(def, ErrorType.DYNAMIC_FINAL_FIELD_WITH_REPLACE));
def.fieldOption = FieldOption.UPDATE;
}
if (annoService == null && index < sigs.length) {
annoService = sigs[index].substring(1).replace('/', '.');
}
def.service = annoService;
if (def.service == null)
analyzer.error("In component %s, method %s, cannot recognize the signature of the descriptor: %s", component.effectiveName(), def.name, member.getDescriptor()).details(details);
}
// end field
} else {
// not a member
def.service = annoService;
if (def.name == null) {
analyzer.error("Name must be supplied for a @Reference specified in the @Component annotation. Service: %s", def.service).details(getDetails(def, ErrorType.MISSING_REFERENCE_NAME));
return;
}
}
if (component.references.containsKey(def.name))
analyzer.error("In component %s, multiple references with the same name: %s. Previous def: %s, this def: %s", className, component.references.get(def.name), def.service, "").details(getDetails(def, ErrorType.MULTIPLE_REFERENCES_SAME_NAME));
else
component.references.put(def.name, def);
}
use of aQute.bnd.osgi.Clazz.MethodDef in project bnd by bndtools.
the class JavaElement method classElement.
/**
* Calculate the class element. This requires parsing the class file and
* finding all the methods that were added etc. The parsing will take super
* interfaces and super classes into account. For this reason it maintains a
* queue of classes/interfaces to parse.
*
* @param analyzer
* @param clazz
* @param infos
* @throws Exception
*/
Element classElement(final Clazz clazz) throws Exception {
Element e = cache.get(clazz);
if (e != null)
return e;
final Set<Element> members = Create.set();
final Set<MethodDef> methods = Create.set();
final Set<Clazz.FieldDef> fields = Create.set();
final MultiMap<Clazz.Def, Element> annotations = new MultiMap<Clazz.Def, Element>();
final TypeRef name = clazz.getClassName();
final String fqn = name.getFQN();
final String shortName = name.getShortName();
// Check if this clazz is actually a provider or not
// providers must be listed in the exported package in the
// PROVIDER_TYPE directive.
Instructions matchers = providerMatcher.get(name.getPackageRef());
boolean p = matchers != null && matchers.matches(shortName);
final AtomicBoolean provider = new AtomicBoolean(p);
//
// Check if we already had this clazz in the cache
//
// for super classes
Element before = cache.get(clazz);
if (before != null)
return before;
clazz.parseClassFileWithCollector(new ClassDataCollector() {
boolean memberEnd;
Clazz.FieldDef last;
@Override
public void version(int minor, int major) {
javas.add(Clazz.JAVA.getJava(major, minor));
}
@Override
public void method(MethodDef defined) {
if ((defined.isProtected() || defined.isPublic())) {
last = defined;
methods.add(defined);
} else {
last = null;
}
}
@Override
public void deprecated() {
if (memberEnd)
clazz.setDeprecated(true);
else if (last != null)
last.setDeprecated(true);
}
@Override
public void field(Clazz.FieldDef defined) {
if (defined.isProtected() || defined.isPublic()) {
last = defined;
fields.add(defined);
} else
last = null;
}
@Override
public void constant(Object o) {
if (last != null) {
// Must be accessible now
last.setConstant(o);
}
}
@Override
public void extendsClass(TypeRef name) throws Exception {
String comment = null;
if (!clazz.isInterface())
comment = inherit(members, name);
Clazz c = analyzer.findClass(name);
if ((c == null || c.isPublic()) && !name.isObject())
members.add(new Element(EXTENDS, name.getFQN(), null, MICRO, MAJOR, comment));
}
@Override
public void implementsInterfaces(TypeRef[] names) throws Exception {
// ignore type reordering
Arrays.sort(names);
for (TypeRef name : names) {
String comment = null;
if (clazz.isInterface() || clazz.isAbstract())
comment = inherit(members, name);
members.add(new Element(IMPLEMENTS, name.getFQN(), null, MINOR, MAJOR, comment));
}
}
/**
*/
Set<Element> OBJECT = Create.set();
public String inherit(final Set<Element> members, TypeRef name) throws Exception {
if (name.isObject()) {
if (OBJECT.isEmpty()) {
Clazz c = analyzer.findClass(name);
if (c == null) {
// available
return null;
}
Element s = classElement(c);
for (Element child : s.children) {
if (INHERITED.contains(child.type)) {
String n = child.getName();
if (child.type == METHOD) {
if (n.startsWith("<init>") || "getClass()".equals(child.getName()) || n.startsWith("wait(") || n.startsWith("notify(") || n.startsWith("notifyAll("))
continue;
}
if (isStatic(child))
continue;
OBJECT.add(child);
}
}
}
members.addAll(OBJECT);
} else {
Clazz c = analyzer.findClass(name);
if (c == null) {
return inherit(members, analyzer.getTypeRef("java/lang/Object"));
}
Element s = classElement(c);
for (Element child : s.children) {
if (isStatic(child))
continue;
if (INHERITED.contains(child.type) && !child.name.startsWith("<")) {
members.add(child);
}
}
}
return null;
}
private boolean isStatic(Element child) {
boolean isStatic = child.get("static") != null;
return isStatic;
}
/**
* Deprecated annotations and Provider/Consumer Type (both bnd and
* OSGi) are treated special. Other annotations are turned into a
* tree. Starting with ANNOTATED, and then properties. A property is
* a PROPERTY property or an ANNOTATED property if it is an
* annotation. If it is an array, the key is suffixed with the
* index.
*
* <pre>
* public @interface Outer { Inner[] value(); }
* public @interface Inner { String[] value(); } @Outer(
* { @Inner("1","2"}) } class Xyz {} ANNOTATED Outer
* (CHANGED/CHANGED) ANNOTATED Inner (CHANGED/CHANGED) PROPERTY
* value.0=1 (CHANGED/CHANGED) PROPERTY value.1=2 (CHANGED/CHANGED)
* </pre>
*/
@Override
public void annotation(Annotation annotation) {
if (Deprecated.class.getName().equals(annotation.getName().getFQN())) {
if (memberEnd)
clazz.setDeprecated(true);
else if (last != null)
last.setDeprecated(true);
return;
}
Element e = annotatedToElement(annotation);
if (memberEnd) {
members.add(e);
//
// Check for the provider/consumer. We use strings because
// these are not officially
// released yet
//
String name = annotation.getName().getFQN();
if ("aQute.bnd.annotation.ProviderType".equals(name) || "org.osgi.annotation.versioning.ProviderType".equals(name)) {
provider.set(true);
} else if ("aQute.bnd.annotation.ConsumerType".equals(name) || "org.osgi.annotation.versioning.ConsumerType".equals(name)) {
provider.set(false);
}
} else if (last != null)
annotations.add(last, e);
}
/*
* Return an ANNOTATED element for this annotation. An ANNOTATED
* element contains either PROPERTY children or ANNOTATED children.
*/
private Element annotatedToElement(Annotation annotation) {
Collection<Element> properties = Create.set();
for (String key : annotation.keySet()) {
addAnnotationMember(properties, key, annotation.get(key));
}
return new Element(ANNOTATED, annotation.getName().getFQN(), properties, CHANGED, CHANGED, null);
}
/*
* This method detects 3 cases: An Annotation, which means it
* creates a new child ANNOTATED element, an array, which means it
* will repeat recursively but suffixes the key with the index, or a
* simple value which is turned into a string.
*/
private void addAnnotationMember(Collection<Element> properties, String key, Object member) {
if (member instanceof Annotation) {
properties.add(annotatedToElement((Annotation) member));
} else if (member.getClass().isArray()) {
int l = Array.getLength(member);
for (int i = 0; i < l; i++) {
addAnnotationMember(properties, key + "." + i, Array.get(member, i));
}
} else {
StringBuilder sb = new StringBuilder();
sb.append(key);
sb.append('=');
if (member instanceof String) {
sb.append("'");
sb.append(member);
sb.append("'");
} else
sb.append(member);
properties.add(new Element(PROPERTY, sb.toString(), null, CHANGED, CHANGED, null));
}
}
@Override
public void innerClass(TypeRef innerClass, TypeRef outerClass, String innerName, int innerClassAccessFlags) throws Exception {
Clazz clazz = analyzer.findClass(innerClass);
if (clazz != null)
clazz.setInnerAccess(innerClassAccessFlags);
if (Modifier.isProtected(innerClassAccessFlags) || Modifier.isPublic(innerClassAccessFlags))
return;
notAccessible.add(innerClass);
}
@Override
public void memberEnd() {
memberEnd = true;
}
});
// This is the heart of the semantic versioning. If we
// add or remove a method from an interface then
Delta add;
Delta remove;
Type type;
if (clazz.isInterface())
if (clazz.isAnnotation())
type = ANNOTATION;
else
type = INTERFACE;
else if (clazz.isEnum())
type = ENUM;
else
type = CLASS;
if (type == INTERFACE) {
if (provider.get()) {
// Adding a method for a provider is not an issue
// because it must be aware of the changes
add = MINOR;
// Removing a method influences consumers since they
// tend to call this guy.
remove = MAJOR;
} else {
// Adding a method is a major change
// because the consumer has to implement it
// or the provider will call a non existent
// method on the consumer
add = MAJOR;
// Removing a method is not an issue for
// providers, however, consumers could potentially
// call through this interface :-(
remove = MAJOR;
}
} else {
// Adding a method to a class can never do any harm
// except when the class is extended and the new
// method clashes with the new method. That is
// why API classes in general should be final, at
// least not extended by consumers.
add = MINOR;
// Removing it will likely hurt consumers
remove = MAJOR;
}
for (MethodDef m : methods) {
if (m.isSynthetic()) {
// Ignore synthetic methods
continue;
}
Collection<Element> children = annotations.get(m);
if (children == null)
children = new HashSet<Element>();
access(children, m.getAccess(), m.isDeprecated(), provider.get());
// in a final class.
if (clazz.isFinal())
children.remove(FINAL);
children.add(getReturn(m.getType()));
if (clazz.isInterface() && !m.isAbstract()) {
//
// We have a Java 8 default method!
// Such a method is always a minor update
//
add = MINOR;
}
String signature = m.getName() + toString(m.getPrototype());
Element member = new Element(METHOD, signature, children, add, provider.get() && !m.isPublic() ? MINOR : remove, null);
if (!members.add(member)) {
members.remove(member);
members.add(member);
}
}
for (Clazz.FieldDef f : fields) {
if (f.isSynthetic()) {
// Ignore synthetic fields
continue;
}
Collection<Element> children = annotations.get(f);
if (children == null)
children = new HashSet<Element>();
// Fields can have a constant value, this is a new element
if (f.getConstant() != null) {
children.add(new Element(CONSTANT, f.getConstant().toString(), null, CHANGED, CHANGED, null));
}
access(children, f.getAccess(), f.isDeprecated(), provider.get());
children.add(getReturn(f.getType()));
Element member = new Element(FIELD, f.getName(), children, MINOR, provider.get() && !f.isPublic() ? MINOR : MAJOR, null);
if (!members.add(member)) {
members.remove(member);
members.add(member);
}
}
access(members, clazz.getAccess(), clazz.isDeprecated(), provider.get());
// And make the result
Element s = new Element(type, fqn, members, MINOR, MAJOR, null);
cache.put(clazz, s);
return s;
}
use of aQute.bnd.osgi.Clazz.MethodDef in project bnd by bndtools.
the class CoverageResource method write.
@Override
public void write(OutputStream out) throws IOException {
try {
Map<MethodDef, List<MethodDef>> table = getCrossRef(testsuite, service);
Tag coverage = toTag(table);
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out, Constants.DEFAULT_CHARSET));
try {
coverage.print(0, pw);
} finally {
pw.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Aggregations