use of org.apache.felix.scrplugin.description.PropertyDescription in project sling by apache.
the class SlingHealthCheckProcessor method generatePropertyDescriptor.
/** Generates a property descriptor of type {@link PropertyType} */
private void generatePropertyDescriptor(final ClassAnnotation cad, final ClassDescription classDescription, final boolean metatype, final String propertyName, final String propertyDescriptorName, PropertyType propertyType, String label, String description, boolean isArray) {
final PropertyDescription pd = new PropertyDescription(cad);
pd.setName(propertyDescriptorName);
pd.setLabel(label);
pd.setDescription(description);
pd.setType(propertyType);
if (isArray) {
final String[] values = (String[]) cad.getValue(propertyName);
pd.setMultiValue(values);
pd.setUnbounded(PropertyUnbounded.ARRAY);
pd.setCardinality(Integer.MAX_VALUE);
} else {
final Object propertyVal = cad.getValue(propertyName);
String pdValue = (propertyVal instanceof String) ? (String) propertyVal : propertyVal != null ? propertyVal.toString() : null;
pd.setValue(pdValue);
pd.setUnbounded(PropertyUnbounded.DEFAULT);
}
if (!metatype) {
pd.setPrivate(true);
}
classDescription.add(pd);
}
use of org.apache.felix.scrplugin.description.PropertyDescription in project felix by apache.
the class DSAnnotationProcessor method createComponent.
/**
* Create a component description.
*
* @param cad The component annotation for the class.
* @param scannedClass The scanned class.
*/
private ComponentDescription createComponent(final ClassAnnotation cad, final ClassDescription describedClass, final ScannedClass scannedClass) throws SCRDescriptorException {
final ComponentDescription component = new ComponentDescription(cad);
describedClass.add(component);
// Although not defined in the spec, we support abstract classes.
final boolean classIsAbstract = Modifier.isAbstract(scannedClass.getClass().getModifiers());
component.setAbstract(classIsAbstract);
// name
component.setName(cad.getStringValue("name", scannedClass.getScannedClass().getName()));
// services
final List<String> listedInterfaces = new ArrayList<String>();
if (cad.hasValue("service")) {
final String[] interfaces = (String[]) cad.getValue("service");
if (interfaces != null) {
for (final String t : interfaces) {
listedInterfaces.add(t);
}
}
} else {
// scan directly implemented interfaces
this.searchInterfaces(listedInterfaces, scannedClass.getScannedClass());
}
if (listedInterfaces.size() > 0) {
final ServiceDescription serviceDesc = new ServiceDescription(cad);
describedClass.add(serviceDesc);
for (final String name : listedInterfaces) {
serviceDesc.addInterface(name);
}
serviceDesc.setServiceFactory(cad.getBooleanValue("servicefactory", false));
}
// factory
component.setFactory(cad.getStringValue("factory", null));
// enabled
if (cad.getValue("enabled") != null) {
component.setEnabled(cad.getBooleanValue("enabled", true));
}
// immediate
if (cad.getValue("immediate") != null) {
component.setImmediate(cad.getBooleanValue("immediate", false));
}
// property
final String[] property = (String[]) cad.getValue("property");
if (property != null) {
// TODO - what do we do if the value is invalid?
for (final String propDef : property) {
final int pos = propDef.indexOf('=');
if (pos != -1) {
final String prefix = propDef.substring(0, pos);
final String value = propDef.substring(pos + 1);
final int typeSep = prefix.indexOf(':');
final String key = (typeSep == -1 ? prefix : prefix.substring(0, typeSep));
final String type = (typeSep == -1 ? PropertyType.String.name() : prefix.substring(typeSep + 1));
final PropertyType propType = PropertyType.valueOf(type);
// FELIX-4159 : check if this is a multi value prop
final List<PropertyDescription> existingProps = describedClass.getDescriptions(PropertyDescription.class);
PropertyDescription found = null;
for (final PropertyDescription current : existingProps) {
if (current.getName().equals(key)) {
found = current;
break;
}
}
if (found == null) {
final PropertyDescription pd = new PropertyDescription(cad);
describedClass.add(pd);
pd.setName(key);
pd.setValue(value);
pd.setType(propType);
pd.setUnbounded(PropertyUnbounded.DEFAULT);
} else {
if (propType != found.getType()) {
throw new SCRDescriptorException("Multi value property '" + key + "' has different types: " + found.getType() + " & " + propType, describedClass.getSource());
}
if (found.getValue() != null) {
final String[] values = new String[2];
values[0] = found.getValue();
values[1] = value;
found.setMultiValue(values);
} else {
final String[] oldValues = found.getMultiValue();
final String[] newValues = new String[oldValues.length + 1];
System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
newValues[oldValues.length] = value;
found.setMultiValue(newValues);
}
}
}
}
}
// xmlns
if (cad.getValue("xmlns") != null) {
final SpecVersion spec = SpecVersion.fromNamespaceUrl(cad.getValue("xmlns").toString());
if (spec == null) {
throw new SCRDescriptorException("Unknown xmlns attribute value: " + cad.getValue("xmlns"), describedClass.getSource());
}
component.setSpecVersion(spec);
}
// configuration policy
component.setConfigurationPolicy(ComponentConfigurationPolicy.valueOf(cad.getEnumValue("configurationPolicy", ComponentConfigurationPolicy.OPTIONAL.name())));
// configuration pid
Object configPid = cad.getValue("configurationPid");
if (configPid instanceof String) {
component.setConfigurationPid((String) configPid);
} else if (configPid instanceof String[] && ((String[]) configPid).length == 1) {
component.setConfigurationPid(((String[]) configPid)[0]);
} else {
component.setConfigurationPid(null);
}
component.setCreatePid(false);
// no inheritance
component.setInherit(false);
return component;
}
use of org.apache.felix.scrplugin.description.PropertyDescription in project felix by apache.
the class SCRDescriptorGenerator method processGlobalProperties.
/**
* Add global properties (if not already defined in the component)
*/
private void processGlobalProperties(final ClassDescription desc, final Map<String, PropertyDescription> allProperties) {
// apply pre configured global properties
if (this.options.getProperties() != null) {
for (final Map.Entry<String, String> entry : this.options.getProperties().entrySet()) {
final String propName = entry.getKey();
final String value = entry.getValue();
// check if the service already provides this property
if (value != null && !allProperties.containsKey(propName)) {
final PropertyDescription p = new PropertyDescription(null);
p.setName(propName);
p.setValue(value);
p.setType(PropertyType.String);
allProperties.put(propName, p);
}
}
}
}
use of org.apache.felix.scrplugin.description.PropertyDescription in project felix by apache.
the class Validator method validate.
/**
* Validate the component description. If errors occur a message is added to
* the issues list, warnings can be added to the warnings list.
*/
public void validate() throws SCRDescriptorException {
final ComponentDescription component = this.container.getComponentDescription();
// nothing to check if this is ignored
if (!component.isCreateDs()) {
return;
}
final int currentIssueCount = iLog.getNumberOfErrors();
// if the component is abstract, we do not validate everything
if (!component.isAbstract()) {
// if configuration pid is set and different from name, we need 1.2
if (component.getConfigurationPid() != null && !component.getConfigurationPid().equals(component.getName()) && options.getSpecVersion().ordinal() < SpecVersion.VERSION_1_2.ordinal()) {
this.logError(component, "Different configuration pid requires " + SpecVersion.VERSION_1_2.getName() + " or higher.");
}
// ensure non-abstract, public class
if (!Modifier.isPublic(this.container.getClassDescription().getDescribedClass().getModifiers())) {
this.logError(component, "Class must be public: " + this.container.getClassDescription().getDescribedClass().getName());
}
if (Modifier.isAbstract(this.container.getClassDescription().getDescribedClass().getModifiers()) || this.container.getClassDescription().getDescribedClass().isInterface()) {
this.logError(component, "Class must be concrete class (not abstract or interface) : " + this.container.getClassDescription().getDescribedClass().getName());
}
// no errors so far, let's continue
if (iLog.getNumberOfErrors() == currentIssueCount) {
final String activateName = component.getActivate() == null ? "activate" : component.getActivate();
final String deactivateName = component.getDeactivate() == null ? "deactivate" : component.getDeactivate();
// check activate and deactivate methods
this.checkLifecycleMethod(activateName, true, component.getActivate() != null);
this.checkLifecycleMethod(deactivateName, false, component.getDeactivate() != null);
if (component.getModified() != null) {
if (this.options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal()) {
this.checkLifecycleMethod(component.getModified(), true, true);
} else {
this.logError(component, "If modified version is specified, spec version must be " + SpecVersion.VERSION_1_1.name() + " or higher : " + component.getModified());
}
}
// ensure public default constructor
boolean constructorFound = true;
Constructor<?>[] constructors = this.container.getClassDescription().getDescribedClass().getDeclaredConstructors();
for (int i = 0; constructors != null && i < constructors.length; i++) {
// if public default, succeed
if (Modifier.isPublic(constructors[i].getModifiers()) && (constructors[i].getParameterTypes() == null || constructors[i].getParameterTypes().length == 0)) {
constructorFound = true;
break;
}
// non-public/non-default constructor found, must have
// explicit
constructorFound = false;
}
if (!constructorFound) {
this.logError(component, "Class must have public default constructor: " + this.container.getClassDescription().getDescribedClass().getName());
}
// verify properties
for (final PropertyDescription prop : this.container.getProperties().values()) {
this.validateProperty(prop);
}
// verify service
boolean isServiceFactory = false;
if (this.container.getServiceDescription() != null) {
if (this.container.getServiceDescription().getInterfaces().size() == 0) {
this.logError(component, "Service interface information is missing!");
}
this.validateService(this.container.getServiceDescription());
isServiceFactory = this.container.getServiceDescription().isServiceFactory();
}
// serviceFactory must not be true for immediate of component factory
if (isServiceFactory && component.getImmediate() != null && component.getImmediate().booleanValue() && component.getFactory() != null) {
this.logError(component, "Component must not be a ServiceFactory, if immediate and/or component factory: " + this.container.getClassDescription().getDescribedClass().getName());
}
// immediate must not be true for component factory
if (component.getImmediate() != null && component.getImmediate().booleanValue() && component.getFactory() != null) {
this.logError(component, "Component must not be immediate if component factory: " + this.container.getClassDescription().getDescribedClass().getName());
}
}
// additional check for metatype (FELIX-4035)
if (this.container.getMetatypeContainer() != null) {
if (this.container.getMetatypeContainer().getProperties().size() == 0) {
this.logError(component, "Component is defined to generate metatype information, however no properties or only private properties have been " + "defined; in case no properties or only private properties are wanted, consider to use 'metatype=false'");
}
}
if (iLog.getNumberOfErrors() == currentIssueCount) {
// verify references
for (final ReferenceDescription ref : this.container.getReferences().values()) {
this.validateReference(ref, component.isAbstract());
}
}
}
}
use of org.apache.felix.scrplugin.description.PropertyDescription in project felix by apache.
the class SCRAnnotationProcessor method createProperties.
/**
* Create properties descriptions
*
* @throws SCRDescriptorException
* @throws SCRDescriptorFailureException
*/
private void createProperties(final List<? extends ScannedAnnotation> descs, final ClassDescription describedClass) throws SCRDescriptorFailureException, SCRDescriptorException {
for (final ScannedAnnotation ad : descs) {
final PropertyDescription prop = new PropertyDescription(ad);
// check for field annotation
final FieldAnnotation fieldAnnotation;
if (ad instanceof FieldAnnotation) {
fieldAnnotation = (FieldAnnotation) ad;
} else {
fieldAnnotation = null;
}
// Detect values from annotation
String type = null;
String[] values = null;
int index = 0;
while (type == null && index < PROPERTY_VALUE_PROCESSING.length) {
final String propType = PROPERTY_VALUE_PROCESSING[index];
final String propName = PROPERTY_VALUE_PROCESSING[index + 1];
final Object propValue = ad.getValue(propName);
if (propValue != null && propValue.getClass().isArray()) {
type = propType;
values = new String[Array.getLength(propValue)];
for (int i = 0; i < values.length; i++) {
values[i] = Array.get(propValue, i).toString();
}
}
index += 2;
}
String name = ad.getStringValue("name", null);
if (values != null) {
prop.setType(PropertyType.valueOf(type));
if (values.length == 1) {
prop.setValue(values[0]);
} else {
prop.setMultiValue(values);
}
if (name == null) {
final Object value = fieldAnnotation.getAnnotatedFieldValue();
if (value != null) {
name = value.toString();
}
}
} else if (fieldAnnotation != null) {
// Detect values from field
if (name != null) {
final Object value = fieldAnnotation.getAnnotatedFieldValue();
if (value != null) {
if (value.getClass().isArray()) {
final String[] newValues = new String[Array.getLength(value)];
for (int i = 0; i < newValues.length; i++) {
newValues[i] = Array.get(value, i).toString();
}
prop.setMultiValue(newValues);
prop.setType(PropertyType.from(fieldAnnotation.getAnnotatedField().getType().getComponentType()));
} else {
prop.setType(PropertyType.from(value.getClass()));
prop.setValue(value.toString());
}
}
} else {
if (Modifier.isStatic(fieldAnnotation.getAnnotatedField().getModifiers())) {
final Object value = fieldAnnotation.getAnnotatedFieldValue();
if (value != null) {
name = value.toString();
}
} else {
// non static, no name, no value (FELIX-4393)
name = fieldAnnotation.getAnnotatedField().getName();
final Object value = fieldAnnotation.getAnnotatedFieldValue();
if (value != null) {
if (value.getClass().isArray()) {
final String[] newValues = new String[Array.getLength(value)];
for (int i = 0; i < newValues.length; i++) {
newValues[i] = Array.get(value, i).toString();
}
prop.setMultiValue(newValues);
prop.setType(PropertyType.from(fieldAnnotation.getAnnotatedField().getType().getComponentType()));
} else {
prop.setType(PropertyType.from(value.getClass()));
prop.setValue(value.toString());
}
}
}
}
}
prop.setName(name);
prop.setLabel(ad.getStringValue("label", null));
prop.setDescription(ad.getStringValue("description", null));
// check type
if (prop.getType() == null) {
prop.setType(PropertyType.String);
}
// private
if (ad.getValue("propertyPrivate") != null) {
prop.setPrivate(ad.getBooleanValue("propertyPrivate", false));
}
// cardinality handling
final PropertyUnbounded pu = PropertyUnbounded.valueOf(ad.getEnumValue("unbounded", PropertyUnbounded.DEFAULT.name()));
prop.setUnbounded(pu);
if (pu == PropertyUnbounded.DEFAULT) {
prop.setCardinality(ad.getIntegerValue("cardinality", 0));
if (prop.getMultiValue() != null && prop.getCardinality() == 0) {
prop.setUnbounded(PropertyUnbounded.ARRAY);
}
} else {
prop.setCardinality(0);
}
if (prop.getValue() != null) {
if (prop.getUnbounded() == PropertyUnbounded.ARRAY || prop.getUnbounded() == PropertyUnbounded.VECTOR) {
prop.setMultiValue(new String[] { prop.getValue() });
} else if (prop.getCardinality() < -1 || prop.getCardinality() > 1) {
prop.setMultiValue(new String[] { prop.getValue() });
}
}
// options
final ScannedAnnotation[] options = (ScannedAnnotation[]) ad.getValue("options");
if (options != null) {
final List<String> propertyOptions = new ArrayList<String>();
for (final ScannedAnnotation po : options) {
propertyOptions.add(po.getStringValue("name", ""));
propertyOptions.add(po.getStringValue("value", ""));
}
prop.setOptions(propertyOptions.toArray(new String[propertyOptions.size()]));
}
describedClass.add(prop);
}
}
Aggregations