FELIX-3794 : Use DS specification version per component
FELIX-3815 : Maven SCR Plugin does not correctly set specVersion to 1.1 if bind method with two parameters are used (OSGi Comp 4.2 $112.3.1)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1437411 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
index 17e3823..dfa5e99 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
@@ -162,6 +162,7 @@
desc.getSource());
} else {
final ComponentContainer container = this.createComponent(desc, iLog);
+
if (container.getComponentDescription().getSpecVersion() != null) {
if ( specVersion == null ) {
specVersion = container.getComponentDescription().getSpecVersion();
@@ -178,6 +179,12 @@
logger.debug("Setting used spec version to " + specVersion);
}
}
+ } else {
+ if ( this.options.getSpecVersion() != null ) {
+ container.getComponentDescription().setSpecVersion(options.getSpecVersion());
+ } else {
+ container.getComponentDescription().setSpecVersion(SpecVersion.VERSION_1_0);
+ }
}
processedContainers.add(container);
}
@@ -190,64 +197,16 @@
this.logger.debug("Generating descriptor for spec version: " + specVersion);
options.setSpecVersion(specVersion);
- final DescriptionContainer module = new DescriptionContainer(this.options);
-
// before we can validate we should check the references for bind/unbind method
// in order to create them if possible
if ( this.options.isGenerateAccessors() ) {
-
- for (final ComponentContainer container : processedContainers) {
- for (final ReferenceDescription ref : container.getReferences().values()) {
- // if this is a field with a single cardinality,
- // we look for the bind/unbind methods
- // and create them if they are not availabe
- if (ref.getStrategy() != ReferenceStrategy.LOOKUP && ref.getField() != null
- && ref.getField().getDeclaringClass().getName().equals(container.getClassDescription().getDescribedClass().getName())
- && (ref.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY || ref.getCardinality() == ReferenceCardinality.MANDATORY_UNARY)) {
-
- final String bindValue = ref.getBind();
- final String unbindValue = ref.getUnbind();
- final String name = ref.getName();
- final String type = ref.getInterfaceName();
-
- boolean createBind = false;
- boolean createUnbind = false;
-
- // Only create method if no bind name has been specified
- if (bindValue == null && Validator.findMethod(this.project, this.options, container.getClassDescription(), ref, "bind") == null) {
- // create bind method
- createBind = true;
- }
- if (unbindValue == null && Validator.findMethod(this.project, this.options, container.getClassDescription(), ref, "unbind") == null) {
- // create unbind method
- createUnbind = true;
- }
- if (createBind || createUnbind) {
- // logging
- if ( createBind && createUnbind ) {
- this.logger.debug("Generating bind and unbind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
- } else if ( createBind ) {
- this.logger.debug("Generating bind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
- } else {
- this.logger.debug("Generating unbind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
-
- }
- ClassModifier.addMethods(container.getClassDescription().getDescribedClass().getName(),
- name,
- ref.getField().getName(),
- type,
- createBind,
- createUnbind,
- this.project.getClassLoader(),
- this.project.getClassesDirectory(),
- this.logger);
- }
- }
- }
+ for(final ComponentContainer container : processedContainers) {
+ this.generateMethods(container);
}
}
// now validate
+ final DescriptionContainer module = new DescriptionContainer(this.options);
for (final ComponentContainer container : processedContainers) {
final int errorCount = iLog.getNumberOfErrors();
@@ -274,6 +233,55 @@
return result;
}
+ private void generateMethods(final ComponentContainer container) throws SCRDescriptorException {
+ for (final ReferenceDescription ref : container.getReferences().values()) {
+ // if this is a field with a single cardinality,
+ // we look for the bind/unbind methods
+ // and create them if they are not availabe
+ if (ref.getStrategy() != ReferenceStrategy.LOOKUP && ref.getField() != null
+ && ref.getField().getDeclaringClass().getName().equals(container.getClassDescription().getDescribedClass().getName())
+ && (ref.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY || ref.getCardinality() == ReferenceCardinality.MANDATORY_UNARY)) {
+
+ final String bindValue = ref.getBind();
+ final String unbindValue = ref.getUnbind();
+ final String name = ref.getName();
+ final String type = ref.getInterfaceName();
+
+ boolean createBind = false;
+ boolean createUnbind = false;
+
+ // Only create method if no bind name has been specified
+ if (bindValue == null && Validator.findMethod(this.project, this.options, container.getClassDescription(), ref, "bind") == null) {
+ // create bind method
+ createBind = true;
+ }
+ if (unbindValue == null && Validator.findMethod(this.project, this.options, container.getClassDescription(), ref, "unbind") == null) {
+ // create unbind method
+ createUnbind = true;
+ }
+ if (createBind || createUnbind) {
+ // logging
+ if ( createBind && createUnbind ) {
+ this.logger.debug("Generating bind and unbind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
+ } else if ( createBind ) {
+ this.logger.debug("Generating bind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
+ } else {
+ this.logger.debug("Generating unbind method for " + name + " in " + container.getClassDescription().getDescribedClass().getName());
+
+ }
+ ClassModifier.addMethods(container.getClassDescription().getDescribedClass().getName(),
+ name,
+ ref.getField().getName(),
+ type,
+ createBind,
+ createUnbind,
+ this.project.getClassLoader(),
+ this.project.getClassesDirectory(),
+ this.logger);
+ }
+ }
+ }
+ }
/**
* Create the SCR objects based on the descriptions
*/
@@ -281,6 +289,8 @@
final IssueLog iLog) {
final ComponentDescription componentDesc = desc.getDescription(ComponentDescription.class);
+ final SpecVersion intitialComponentSpecVersion = componentDesc.getSpecVersion();
+
// configuration pid in 1.2
if ( componentDesc.getConfigurationPid() != null && !componentDesc.getConfigurationPid().equals(componentDesc.getName())) {
componentDesc.setSpecVersion(SpecVersion.VERSION_1_2);
@@ -388,6 +398,12 @@
container.getProperties().put(org.osgi.framework.Constants.SERVICE_PID, pid);
}
+ // check if component has spec version configured but requires a higher one
+ if ( intitialComponentSpecVersion != null && componentDesc.getSpecVersion().ordinal() > intitialComponentSpecVersion.ordinal() ) {
+ iLog.addError("Component " + container + " requires spec version " + container.getComponentDescription().getSpecVersion().name()
+ + " but component is configured to use version " + intitialComponentSpecVersion.name(),
+ desc.getSource());
+ }
return container;
}
@@ -546,6 +562,7 @@
/**
* Process reference directives
+ * @throws SCRDescriptorException
*/
private void processReferences(final ClassDescription current,
final ComponentContainer component) {
@@ -562,6 +579,25 @@
}
this.testReference(current, component.getReferences(), rd, component.getClassDescription() == current);
+
+ // check for method signature
+ try {
+ final Validator.MethodResult bindMethod = Validator.findMethod(this.project, this.options, current, rd,
+ rd.getBind() == null ? "bind" : rd.getBind());
+ if ( bindMethod != null ) {
+ component.getComponentDescription().setSpecVersion(bindMethod.requiredSpecVersion);
+ }
+
+ final Validator.MethodResult unbindMethod = Validator.findMethod(this.project, this.options, current, rd,
+ rd.getUnbind() == null ? "unbind" : rd.getUnbind());
+ if ( unbindMethod != null ) {
+ component.getComponentDescription().setSpecVersion(unbindMethod.requiredSpecVersion);
+ }
+
+ } catch (final SCRDescriptorException sde) {
+ // this happens only if a class not found exception occurs, so we can ignore this at this point!
+ }
+
}
}
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/Validator.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/Validator.java
index 5267b23..1eff278 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/Validator.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/Validator.java
@@ -496,8 +496,8 @@
private String validateMethod(final ReferenceDescription ref, final String methodName, final boolean componentIsAbstract)
throws SCRDescriptorException {
- final Method method = findMethod(this.project, this.options, this.container.getClassDescription(), ref, methodName);
- if (method == null) {
+ final MethodResult result = findMethod(this.project, this.options, this.container.getClassDescription(), ref, methodName);
+ if (result == null) {
if (!componentIsAbstract) {
this.logError(ref,
"Missing method " + methodName + " for reference "
@@ -508,14 +508,19 @@
// method needs to be protected for 1.0
if (this.options.getSpecVersion() == SpecVersion.VERSION_1_0) {
- if (Modifier.isPublic(method.getModifiers())) {
- this.logWarn(ref, "Method " + method.getName() + " should be declared protected");
- } else if (!Modifier.isProtected(method.getModifiers())) {
- this.logError(ref, "Method " + method.getName() + " has wrong qualifier, public or protected required");
+ if (Modifier.isPublic(result.method.getModifiers())) {
+ this.logWarn(ref, "Method " + result.method.getName() + " should be declared protected");
+ } else if (!Modifier.isProtected(result.method.getModifiers())) {
+ this.logError(ref, "Method " + result.method.getName() + " has wrong qualifier, public or protected required");
return null;
}
}
- return method.getName();
+
+ if (this.options.getSpecVersion().ordinal() < result.requiredSpecVersion.ordinal() ) {
+ this.logError(ref, "Method declaration for '" + result.method.getName() + "' requires version "
+ + result.requiredSpecVersion + " or newer");
+ }
+ return result.method.getName();
}
private static final String TYPE_SERVICE_REFERENCE = "org.osgi.framework.ServiceReference";
@@ -535,12 +540,22 @@
return null;
}
- public static Method findMethod(final Project project,
+ public static final class MethodResult {
+ public Method method;
+ public SpecVersion requiredSpecVersion;
+ }
+
+ /**
+ * Find the method and the required spec version
+ * @throws SCRDescriptorException If the class can't be found
+ */
+ public static MethodResult findMethod(final Project project,
final Options options,
final ClassDescription cd,
final ReferenceDescription ref,
final String methodName)
throws SCRDescriptorException {
+ SpecVersion requiredVersion = SpecVersion.VERSION_1_0;
try {
final Class<?>[] sig = new Class<?>[] { project.getClassLoader().loadClass(TYPE_SERVICE_REFERENCE) };
final Class<?>[] sig2 = new Class<?>[] { project.getClassLoader().loadClass(ref.getInterfaceName()) };
@@ -551,8 +566,9 @@
Method method = getMethod(cd, realMethodName, sig);
if (method == null) {
method = getMethod(cd, realMethodName, sig2);
- if (method == null && options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
+ if (method == null && (options.getSpecVersion() == null || options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal()) ) {
method = getMethod(cd, realMethodName, sig3);
+ requiredVersion = SpecVersion.VERSION_1_1;
}
}
@@ -572,8 +588,9 @@
}
if (method == null) {
method = getMethod(cd, realMethodName, sig2);
- if (method == null && options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
+ if (method == null && (options.getSpecVersion() == null || options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal()) ) {
method = getMethod(cd, realMethodName, sig3);
+ requiredVersion = SpecVersion.VERSION_1_1;
}
}
@@ -585,12 +602,17 @@
}
if (method == null) {
method = getMethod(cd, realMethodName, sig2);
- if (method == null && options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
+ if (method == null && (options.getSpecVersion() == null || options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal()) ) {
method = getMethod(cd, realMethodName, sig3);
+ requiredVersion = SpecVersion.VERSION_1_1;
}
}
- return method;
+ final MethodResult result = new MethodResult();
+ result.method = method;
+ result.requiredSpecVersion = requiredVersion;
+
+ return result;
} catch (final ClassNotFoundException cnfe) {
throw new SCRDescriptorException("Unable to load class!", cnfe);
}
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
index 1ae4d3a..155398c 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
@@ -764,7 +764,9 @@
final List<String> fileNames = new ArrayList<String>();
if ( options.isGenerateSeparateDescriptors() ) {
+ final SpecVersion globalVersion = module.getOptions().getSpecVersion();
for(final ComponentContainer component : components ) {
+ module.getOptions().setSpecVersion(component.getComponentDescription().getSpecVersion());
final File file = new File(descriptorDir, component.getClassDescription().getDescribedClass().getName() + ".xml");
try {
ComponentDescriptorIO.generateXML(module, Collections.singletonList(component), file, logger);
@@ -777,6 +779,7 @@
}
fileNames.add(PARENT_NAME + '/' + file.getName());
}
+ module.getOptions().setSpecVersion(globalVersion);
} else {
if (descriptorFile == null) {
throw new SCRDescriptorFailureException("Descriptor file name must not be empty.");