added support for annotated adapter services
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@912251 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/AdapterService.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/AdapterService.java
new file mode 100644
index 0000000..7ff1016
--- /dev/null
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/AdapterService.java
@@ -0,0 +1,61 @@
+/*
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.felix.dm.annotation.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates an Adapater Service. The adapter will be applied to any service that
+ * matches the implemented interface and filter. For each matching service
+ * an adapter will be created based on the adapter implementation class.
+ * The adapter will be registered with the specified interface and existing properties
+ * from the original service plus any extra properties you supply here.
+ * It will also inherit all dependencies, and if you declare the original
+ * service as a member it will be injected.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface AdapterService
+{
+ /**
+ * Returns the adapter service interface . By default, the directly implemented interface is used.
+ * @return The service interface to apply the adapter to.
+ */
+ Class<?> adapterService() default Object.class;
+
+ /**
+ * The adapter service properites. They will be added to the adapted service properties.
+ * @return additional properties to use with the adapter service registration
+ */
+ Param[] adapterProperties() default {};
+
+ /**
+ * The adapted service interface
+ */
+ Class<?> adapteeService();
+
+ /**
+ * the filter condition to use with the adapted service interface.
+ * @return the filter condition to use with the adapted ervice interface
+ */
+ String adapteeFilter() default "";
+}
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
index a4a4da5..1be5b58 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
@@ -29,6 +29,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.felix.dm.annotation.api.AdapterService;
import org.apache.felix.dm.annotation.api.AspectService;
import org.apache.felix.dm.annotation.api.Composition;
import org.apache.felix.dm.annotation.api.ConfigurationDependency;
@@ -70,6 +71,8 @@
+ Properties.class.getName().replace('.', '/') + ";";
private final static String A_ASPECT_SERVICE = "L"
+ AspectService.class.getName().replace('.', '/') + ";";
+ private final static String A_ADAPTER_SERVICE = "L"
+ + AdapterService.class.getName().replace('.', '/') + ";";
private Reporter m_reporter;
private String m_className;
@@ -104,6 +107,7 @@
{
Service,
AspectService,
+ AdapterService,
ServiceDependency,
TemporalServiceDependency,
ConfigurationDependency,
@@ -133,7 +137,11 @@
pid,
propagate,
updated,
- timeout
+ timeout,
+ adapterService,
+ adapterProperties,
+ adapteeService,
+ adapteeFilter
};
/**
@@ -348,6 +356,10 @@
{
parseAspectService(annotation);
}
+ else if (annotation.getName().equals(A_ADAPTER_SERVICE))
+ {
+ parseAdapterService(annotation);
+ }
else if (annotation.getName().equals(A_INIT))
{
checkMethod(m_voidMethodPattern);
@@ -574,12 +586,23 @@
private void parseAspectService(Annotation annotation)
{
Info info = new Info(EntryTypes.AspectService);
- m_infos.add(info);
+ m_infos.add(info);
// Register previously parsed Init/Start/Stop/Destroy/Composition annotations
addInitStartStopDestroyCompositionParams(info);
- // Parse Service interface.
+ // Parse service filter
+ String filter = annotation.get(Params.filter.toString());
+ Verifier.verifyFilter(filter, 0);
+ info.addParam(Params.filter, filter);
+
+ // Generate Aspect Implementation
+ info.addParam(Params.impl, m_className);
+
+ // Parse Aspect properties.
+ parseParameters(annotation, Params.properties, info);
+
+ // Parse service interface this aspect is applying to
Object service = annotation.get(Params.service.toString());
if (service == null) {
if (m_interfaces == null)
@@ -593,23 +616,94 @@
"the service attribute has not been set and the class " + m_className + " implements more than one interface");
}
- service = m_interfaces[0];
+ info.addParam(Params.service, m_interfaces[0]);
+ } else
+ {
+ checkClassImplements(annotation, Params.service);
+ info.addClassParam(annotation, Params.service, null);
}
- info.addClassParam(annotation, Params.service, service.toString());
-
- // Parse service filter
- String filter = annotation.get(Params.filter.toString());
- Verifier.verifyFilter(filter, 0);
- info.addParam(Params.filter, filter);
-
- // Generate Aspect Implementation
- info.addParam(Params.impl, m_className);
-
- // Parse Aspect properties.
- parseParameters(annotation, Params.properties, info);
}
/**
+ * Parses an AspectService annotation.
+ * @param annotation
+ */
+ private void parseAdapterService(Annotation annotation)
+ {
+ Info info = new Info(EntryTypes.AdapterService);
+ m_infos.add(info);
+
+ // Register previously parsed Init/Start/Stop/Destroy/Composition annotations
+ addInitStartStopDestroyCompositionParams(info);
+
+ // Generate Adapter Implementation
+ info.addParam(Params.impl, m_className);
+
+ // Parse adaptee filter
+ String adapteeFilter = annotation.get(Params.adapteeFilter.toString());
+ if (adapteeFilter != null)
+ {
+ Verifier.verifyFilter(adapteeFilter, 0);
+ info.addParam(Params.adapteeFilter, adapteeFilter);
+ }
+
+ // Parse the mandatory adapted service interface.
+ info.addClassParam(annotation, Params.adapteeService, null);
+
+ // Parse Adapter properties.
+ parseParameters(annotation, Params.adapterProperties, info);
+
+ // Parse the optional adapter service (use directed implemented interface by default).
+ Object adapterService = annotation.get(Params.adapterService.toString());
+ if (adapterService == null) {
+ if (m_interfaces == null)
+ {
+ throw new IllegalStateException("Invalid AdapterService annotation: " +
+ "the adapterService attribute has not been set and the class " + m_className +
+ " does not implement any interfaces");
+ }
+ if (m_interfaces.length != 1)
+ {
+ throw new IllegalStateException("Invalid AdapterService annotation: " +
+ "the adapterService attribute has not been set and the class " + m_className +
+ " implements more than one interface");
+ }
+
+ info.addParam(Params.adapterService, m_interfaces[0]);
+ } else
+ {
+ checkClassImplements(annotation, Params.adapterService);
+ info.addClassParam(annotation, Params.adapterService, null);
+ }
+ }
+
+ /**
+ * Checks if an annotation attribute references an implemented interface.
+ * @param annotation the parsed annotation
+ * @param attribute an annotation attribute that references an interface this class must
+ * implement.
+ */
+ private void checkClassImplements(Annotation annotation, Params attribute)
+ {
+ String iface = annotation.get(attribute.toString());
+ iface = parseClass(iface, m_classPattern, 1);
+
+ if (m_interfaces != null)
+ {
+ for (String implemented : m_interfaces)
+ {
+ if (implemented.equals(iface))
+ {
+ return;
+ }
+ }
+ }
+
+ throw new IllegalArgumentException("Class " + m_className + " does not implement the "
+ + iface + " interface.");
+ }
+
+ /**
* Parses a Param annotation (which represents a list of key-value pari).
* @param annotation the annotation where the Param annotation is defined
* @param attribute the attribute name which is of Param type
@@ -719,7 +813,7 @@
}
// We must have at least a Service or an AspectService annotation.
- checkServiceDeclared(EntryTypes.Service, EntryTypes.AspectService);
+ checkServiceDeclared(EntryTypes.Service, EntryTypes.AspectService, EntryTypes.AdapterService);
StringBuilder sb = new StringBuilder();
sb.append("Parsed annotation for class ");