*/
private RelationDeclaration parseRelation(Element element, ComponentDeclaration component, boolean isContextual) {
/*
* Get the reference to the target of the relation if specified
*/
ResolvableReference targetDef = parseResolvableReference(component.getName(), element, false);
/*
* All dependencies have an optional identifier and multiplicity
* specification, as well as an optional source kind and target kind
*/
String id = parseString(component.getName(), element, ATT_NAME, false);
boolean isOverride = isContextual && element.getName().equals(OVERRIDE);
boolean isMultiple = parseBoolean(component.getName(), element, ATT_MULTIPLE, false, false);
String sourceName = parseString(component.getName(), element, ATT_SOURCE, isContextual && !isOverride);
ComponentKind sourceKind = parseKind(component.getName(), element, ATT_SOURCE_KIND, isContextual && !isOverride, null);
ComponentKind targetKind = parseKind(component.getName(), element, ATT_TARGET_KIND, false, null);
/*
* For atomic components, dependency declarations may optionally have a number of nested instrumentation declarations.
*
* These are parsed first, as a number of attributes of the relation that are not explicitly declared can be inferred
* from the instrumentation metadata.
*/
List<RequirerInstrumentation> instrumentations = new ArrayList<RequirerInstrumentation>();
if (component instanceof AtomicImplementationDeclaration) {
AtomicImplementationDeclaration atomic = (AtomicImplementationDeclaration) component;
/*
* Optionally, as a shortcut, a single injection may be specified
* directly as an attribute of the relation
*/
RequirerInstrumentation directInstrumentation = parseRelationInstrumentation(element, atomic, false);
if (directInstrumentation != null) {
instrumentations.add(directInstrumentation);
}
for (Element instrumentation : optional(element.getElements())) {
/*
* ignore elements that are not from APAM
*/
if (!isApamDefinition(instrumentation)) {
continue;
}
/*
* Accept only resource references
*/
String resourceKind = instrumentation.getName();
if (!(INTERFACE.equals(resourceKind) || MESSAGE.equals(resourceKind)
|| PACKAGE.equals(resourceKind))) {
continue;
}
instrumentations.add(parseRelationInstrumentation(instrumentation, atomic, true));
}
}
/*
* If no ID was explicitly specified, but a single instrumentation was declared the the name of the field or
* method becomes the ID of the relation.
*/
if (id == null && instrumentations.size() == 1) {
id = instrumentations.get(0).getName();
}
/*
* If no target was explicitly specified, sometimes we can infer it from the instrumentation metadata.
*/
if (!instrumentations.isEmpty() && (targetDef == null || targetKind == null)) {
ComponentKind inferredKind = null;
ResolvableReference inferredTarget = null;
for (RequirerInstrumentation instrumentation : instrumentations) {
String javaType = instrumentation.getRequiredResource().getJavaType();
ComponentKind candidateKind = null;
ResolvableReference candidateTarget = null;
if (ComponentKind.COMPONENT.isAssignableTo(javaType)) {
candidateKind = null;
candidateTarget = null;
} else if (ComponentKind.SPECIFICATION.isAssignableTo(javaType)) {