/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.aries.blueprint.plugin.model;
import org.apache.aries.blueprint.plugin.handlers.Handlers;
import org.apache.aries.blueprint.plugin.spi.CustomDependencyAnnotationHandler;
import org.apache.aries.blueprint.plugin.spi.NamedLikeHandler;
import org.apache.aries.blueprint.plugin.spi.XmlWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import static org.apache.aries.blueprint.plugin.model.AnnotationHelper.findName;
import static org.apache.aries.blueprint.plugin.model.NamingHelper.getBeanName;
class Property implements Comparable<Property>, XmlWriter {
public final String name;
public final String ref;
public final String value;
final boolean isField;
private Property(String name, String ref, String value, boolean isField) {
this.name = name;
this.ref = ref;
this.value = value;
this.isField = isField;
}
static Property create(BlueprintRegistry blueprintRegistry, Field field) {
if (needsInject(field)) {
String value = AnnotationHelper.findValue(field.getAnnotations());
if (value != null) {
return new Property(field.getName(), null, value, true);
}
String ref = getForcedRefName(field);
String refFromCustomeDependencyHandler = getRefFromCustomDependencyHandlers(blueprintRegistry, field, ref);
if (refFromCustomeDependencyHandler != null) {
ref = refFromCustomeDependencyHandler;
}
if (ref != null) {
return new Property(field.getName(), ref, null, true);
}
BeanRef matching = blueprintRegistry.getMatching(new BeanTemplate(field));
ref = (matching == null) ? getDefaultRefName(field) : matching.id;
return new Property(field.getName(), ref, null, true);
} else {
// Field is not a property
return null;
}
}
private static String getRefFromCustomDependencyHandlers(BlueprintRegistry blueprintRegistry, AnnotatedElement annotatedElement, String ref) {
for (CustomDependencyAnnotationHandler customDependencyAnnotationHandler : Handlers.CUSTOM_DEPENDENCY_ANNOTATION_HANDLERS) {
Annotation annotation = (Annotation) AnnotationHelper.findAnnotation(annotatedElement.getAnnotations(), customDependencyAnnotationHandler.getAnnotation());
if (annotation != null) {
String generatedRef = customDependencyAnnotationHandler.handleDependencyAnnotation(annotatedElement, ref, blueprintRegistry);
if (generatedRef != null) {
return generatedRef;
}
}
}
return null;
}
static Property create(BlueprintRegistry blueprintRegistry, Method method) {
String propertyName = resolveProperty(method);
if (propertyName == null) {
return null;
}
String value = AnnotationHelper.findValue(method.getAnnotations());
if (value != null) {
return new Property(propertyName, null, value, false);
}
if (needsInject(method)) {
String ref = getForcedRefName(method);
if (ref == null) {
ref = findName(method.getParameterAnnotations()[0]);
}
String refFromCustomeDependencyHandler = getRefFromCustomDependencyHandlers(blueprintRegistry, method, ref);
if (refFromCustomeDependencyHandler != null) {
ref = refFromCustomeDependencyHandler;
}
if (ref != null) {
return new Property(propertyName, ref, null, false);
}
for (CustomDependencyAnnotationHandler customDependencyAnnotationHandler : Handlers.CUSTOM_DEPENDENCY_ANNOTATION_HANDLERS) {
Annotation annotation = (Annotation) AnnotationHelper.findAnnotation(method.getParameterAnnotations()[0], customDependencyAnnotationHandler.getAnnotation());
if (annotation != null) {
String generatedRef = customDependencyAnnotationHandler.handleDependencyAnnotation(method.getParameterTypes()[0], annotation, ref, blueprintRegistry);
if (generatedRef != null) {
ref = generatedRef;
break;
}
}
}
if (ref != null) {
return new Property(propertyName, ref, null, false);
}
BeanTemplate template = new BeanTemplate(method);
BeanRef matching = blueprintRegistry.getMatching(template);
ref = (matching == null) ? getBeanName(method.getParameterTypes()[0]) : matching.id;
return new Property(propertyName, ref, null, false);
}
return null;
}
private static String resolveProperty(Method method) {
if (method.getParameterTypes().length != 1) {
return null;
}
String propertyName = method.getName().substring(3);
return makeFirstLetterLower(propertyName);
}
/**
* Assume it is defined in another manually created blueprint context with default name
*
* @param field
* @return
*/
private static String getDefaultRefName(Field field) {
return getBeanName(field.getType());
}
private static String getForcedRefName(Field field) {
return getForcedRefName(field.getType(), field);
}
private static String getForcedRefName(Method method) {
return getForcedRefName(method.getParameterTypes()[0], method);
}
private static String getForcedRefName(Class<?> clazz, AnnotatedElement annotatedElement) {
for (NamedLikeHandler namedLikeHandler : Handlers.NAMED_LIKE_HANDLERS) {
if (annotatedElement.getAnnotation(namedLikeHandler.getAnnotation()) != null) {
String name = namedLikeHandler.getName(clazz, annotatedElement);
if (name != null) {
return name;
}
}
}
return null;
}
private static boolean needsInject(AnnotatedElement annotatedElement) {
for (Class injectDependencyAnnotation : AnnotationHelper.injectDependencyAnnotations) {
if (annotatedElement.getAnnotation(injectDependencyAnnotation) != null) {
return true;
}
}
return false;
}
@Override
public int compareTo(Property other) {
return name.compareTo(other.name);
}
private static String makeFirstLetterLower(String name) {
return name.substring(0, 1).toLowerCase() + name.substring(1, name.length());
}
@Override
public void write(XMLStreamWriter writer) throws XMLStreamException {
writer.writeEmptyElement("property");
writer.writeAttribute("name", name);
if (ref != null) {
writer.writeAttribute("ref", ref);
} else if (value != null) {
writer.writeAttribute("value", value);
}
}
}