You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cl...@apache.org on 2013/09/30 11:34:36 UTC
svn commit: r1527496 [2/2] - in /felix/trunk/ipojo/runtime:
core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/
core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apa...
Added: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java?rev=1527496&view=auto
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java (added)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java Mon Sep 30 09:34:36 2013
@@ -0,0 +1,465 @@
+/*
+ * 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.ipojo.handlers.dependency;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.DependencyModel;
+import org.osgi.framework.ServiceReference;
+
+import java.util.*;
+
+/**
+ * Utility class checking the configuration of a dependency.
+ */
+public class DependencyConfigurationChecker {
+
+ public static void ensure(Dependency dependency, Element metadata, PojoMetadata manipulation) throws
+ ConfigurationException {
+ ensureThatAtLeastOneInjectionIsSpecified(dependency);
+ ensureThatTheFieldIsInComponentClass(dependency, manipulation);
+ ensureThatTheConstructorParameterIsCoherent(dependency, manipulation);
+ ensureThatCallbacksAreCoherent(dependency, manipulation);
+ deduceAggregationFromTheInjectionPoints(dependency, manipulation);
+ deduceTheServiceSpecification(dependency, manipulation);
+ checkTheServiceUnavailableAction(dependency, metadata);
+ checkTheConsistencyOfTheFromAttribute(dependency, metadata);
+ disableProxyForInconsistentTypes(dependency);
+ }
+
+ /**
+ * Disables the proxy settings for types that does not support it: Vector, Array, and non interface specification.
+ * If the dependency is disabled, check that we are no constructor injection.
+ * @param dependency the dependency
+ */
+ private static void disableProxyForInconsistentTypes(Dependency dependency) throws ConfigurationException {
+ if (! dependency.getSpecification().isInterface()
+ || dependency.isAggregate() && dependency.getAggregateType() == AggregateDependencyInjectionType.ARRAY
+ || dependency.isAggregate() && dependency.getAggregateType() == AggregateDependencyInjectionType.VECTOR) {
+ dependency.setProxy(false);
+ if (dependency.getConstructorParameterIndex() != -1) {
+ throw new ConfigurationException("The dependency " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " has an inconsistent configuration. - reason: the service specification " +
+ "or container do not support proxy, which is required for constructor injection");
+ }
+ dependency.getHandler().info("Proxy disabled for " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " - the service specification or container do not support proxy");
+ }
+ }
+
+ /**
+ * Checks that the dependency callbacks are consistent:
+ * <ul>
+ * <li>have a supported 'type'</li>
+ * <li>have a supported signature</li>
+ * </ul>
+ * If the method is not in the component class, a message is logged, as this verification cannot be used.
+ * If the method is found in the manipulation metadata, the callback parameters are set.
+ * @param dependency the dependency
+ * @param manipulation the manipulation
+ * @throws ConfigurationException if the methods do not obey to the previously mentioned rules.
+ */
+ private static void ensureThatCallbacksAreCoherent(Dependency dependency, PojoMetadata manipulation) throws
+ ConfigurationException {
+ DependencyCallback[] callbacks = dependency.getCallbacks();
+ if (callbacks != null) {
+ for (DependencyCallback callback : callbacks) {
+ MethodMetadata metadata = manipulation.getMethod(callback.getMethodName());
+ if (metadata == null) {
+ dependency.getHandler().debug("A dependency callback " + callback.getMethodName() + " of " +
+ DependencyHandler.getDependencyIdentifier(dependency) + " does not " +
+ "exist in the implementation class, will try the parent classes");
+ } else {
+ String[] parameters = metadata.getMethodArguments();
+ switch(parameters.length) {
+ case 0 : // Just a notification method.
+ callback.setArgument(parameters);
+ break;
+ case 1 :
+ // Can be the service object, service reference or properties
+ callback.setArgument(parameters);
+ break;
+ case 2 :
+ // Constraints on the second argument, must be a service reference, a dictionary or a map
+ if (!ServiceReference.class.getName().equals(parameters[1])
+ && ! Dictionary.class.getName().equals(parameters[1])
+ && ! Map.class.getName().equals(parameters[1])) {
+ throw new ConfigurationException("The method " + callback.getMethodName() + " of " +
+ DependencyHandler.getDependencyIdentifier(dependency) + " is not a valid " +
+ "dependency callback - reason: the second argument (" + parameters[1] +
+ ") must be a service reference, a dictionary or a map.");
+ }
+ callback.setArgument(parameters);
+ break;
+ default:
+ // Invalid signature.
+ throw new ConfigurationException("The method " + callback.getMethodName() + " of " +
+ DependencyHandler.getDependencyIdentifier(dependency) + " is not a valid " +
+ "dependency callback - reason: the signature is invalid");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks whether the constructor parameter injection is suitable. this check verified that the constructor has
+ * enough parameter.
+ * @param dependency the dependency
+ * @param manipulation the manipulation metadata
+ * @throws ConfigurationException if the constructor is not suitable
+ */
+ private static void ensureThatTheConstructorParameterIsCoherent(Dependency dependency,
+ PojoMetadata manipulation) throws
+ ConfigurationException {
+ if (dependency.getConstructorParameterIndex() != -1) {
+ MethodMetadata[] constructors = manipulation.getConstructors();
+ if (constructors == null || constructors.length == 0) {
+ throw new ConfigurationException("The constructor parameter attribute of " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " is inconsistent - reason: there is no constructor in" +
+ " the component class (" + dependency.getHandler().getInstanceManager().getClassName() + ")");
+ }
+
+ //TODO Consider only the first constructor. This is a limitation we should think about,
+ // how to determine which constructor to use. Only one constructor should have annotations,
+ // it could be use as hint.
+ MethodMetadata constructor = constructors[0];
+ if (! (constructor.getMethodArguments().length > dependency.getConstructorParameterIndex())) {
+ throw new ConfigurationException("The constructor parameter attribute of " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " is inconsistent - reason: the constructor with the " +
+ "signature " + Arrays.toString(constructor.getMethodArguments()) + " has not enough " +
+ "parameters");
+ }
+
+ }
+ }
+
+ /**
+ * Checks that the field used to inject the dependency is in the component class. If the dependency has no field,
+ * this method does nothing.
+ * @param dependency the dependency
+ * @param manipulation the manipulation metadata
+ * @throws ConfigurationException if the field used to inject the given dependency is not in the component class.
+ */
+ private static void ensureThatTheFieldIsInComponentClass(Dependency dependency, PojoMetadata manipulation) throws ConfigurationException {
+ if (dependency.getField() != null) {
+ FieldMetadata field = manipulation.getField(dependency.getField());
+ if (field == null) {
+ throw new ConfigurationException("Incorrect field injection for " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " - reason: the field " + dependency.getField() + " is" +
+ " not in the component class (" + dependency.getHandler().getInstanceManager().getClassName()
+ + ")");
+ }
+ }
+ }
+
+ /**
+ * Determines if the dependency is aggregate from the field or constructor parameter used to inject the dependency.
+ * If the dependency just uses methods, this method does nothing. This method also check that dependencies set to
+ * aggregate have a valid injection type.
+ * @param dependency the dependency
+ * @param manipulation the manipulation metadata
+ * @throws ConfigurationException if the type of the field or constructor parameter used to inject the dependency
+ * is not suitable for aggregate dependencies.
+ */
+ private static void deduceAggregationFromTheInjectionPoints(Dependency dependency, PojoMetadata manipulation) throws ConfigurationException {
+ if (dependency.getField() != null) {
+ FieldMetadata field = manipulation.getField(dependency.getField());
+ String type = field.getFieldType();
+ if (type.endsWith("[]")) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.ARRAY);
+ } else if (Collection.class.getName().equals(type) || List.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.LIST);
+ } else if (Set.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.SET);
+ } else if (Vector.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.VECTOR);
+ } else if (dependency.isAggregate()) {
+ // Something wrong. The dependency has a field that is not suitable for aggregate dependencies
+ throw new ConfigurationException("The dependency " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " cannot be an aggregate dependency - reason: the type " + field.getFieldType
+ () + " of the field " + field.getFieldName() + " is not suitable for aggregate " +
+ "dependencies. Compatible types are array, vector, list, set and collection.");
+ }
+ }
+ if (dependency.getConstructorParameterIndex() != -1) {
+ String type = manipulation.getConstructors()[0].getMethodArguments()[dependency
+ .getConstructorParameterIndex()];
+ if (type.endsWith("[]")) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.ARRAY);
+ } else if (Collection.class.getName().equals(type) || List.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.LIST);
+ } else if (Set.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.SET);
+ } else if (Vector.class.getName().equals(type)) {
+ dependency.setAggregateType(AggregateDependencyInjectionType.VECTOR);
+ } else if (dependency.isAggregate()) {
+ // Something wrong. The dependency has a field that is not suitable for aggregate dependencies
+ throw new ConfigurationException("The dependency " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " cannot be an aggregate dependency - reason: the type " + type
+ + " of the constructor parameter " + dependency.getConstructorParameterIndex() + " is not suitable for aggregate " +
+ "dependencies. Compatible types are array, vector, list, set and collection.");
+ }
+ }
+ //TODO We may not cover some cases such as inconsistency between the constructor and the field. However this
+ // should be very rare.
+
+ }
+
+ /**
+ * Checks that the dependency has at least one injection point.
+ * @param dependency the dependency
+ * @throws ConfigurationException if the dependency has no injection point
+ */
+ private static void ensureThatAtLeastOneInjectionIsSpecified(Dependency dependency) throws ConfigurationException {
+ if (dependency.getField() == null
+ && (dependency.getCallbacks() == null || dependency.getCallbacks().length == 0)
+ && dependency.getConstructorParameterIndex() == -1) {
+ throw new ConfigurationException("The dependency " + DependencyHandler.getDependencyIdentifier
+ (dependency) + " is invalid - reason: no injection specified, at least a field, " +
+ "a method or a constructor parameter index must be set");
+ }
+ }
+
+ /**
+ * Checks that the `from` attribute is used consistently:
+ * <ul>
+ * <li>Rule 1 : it cannot be used on aggregate dependency</li>
+ * <li>Rule 2 : it cannot be used in combination with the `comparator` attribute</li>
+ * <li>Rule 3 : it cannot be used in combination with the `dynamic-priority` binding policy</li>
+ * </ul>
+ *
+ * @param dependency the dependency
+ * @param metadata the dependency metadata
+ * @throws ConfigurationException if the `from` attribute is used inconsistently.
+ */
+ private static void checkTheConsistencyOfTheFromAttribute(Dependency dependency,
+ Element metadata) throws ConfigurationException {
+ // Check if we have a from attribute.
+ if (metadata.getAttribute("from") != null) {
+ final String message = "The `from` attribute is not usable in " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " - reason: ";
+ // Rule 1
+ if (dependency.isAggregate()) {
+ throw new ConfigurationException(message + "the dependency is " +
+ "aggregate");
+ }
+ // Rule 2
+ String comparator = metadata.getAttribute("comparator");
+ if (comparator != null) {
+ throw new ConfigurationException(message + "the dependency uses a comparator");
+ }
+ // Rule 3
+ if (dependency.getBindingPolicy() == DependencyModel.DYNAMIC_PRIORITY_BINDING_POLICY) {
+ throw new ConfigurationException(message + "the dependency uses the dynamic-priority " +
+ "binding policy");
+ }
+ }
+ }
+
+ /**
+ * Checks that service unavailable actions are consistent.
+ * <ul>
+ * <li>Rule 1: Nullable, Exception, Default-Implementation... can only be used for scalar optional dependency</li>
+ * <li>Rule 2: Only one can be used</li>
+ * <li>Rule 3: Timeout can only be used on optional dependency</li>
+ * </ul>
+ *
+ * @param dependency the dependency
+ * @throws ConfigurationException if the dependency used inconsistent attributes
+ */
+ private static void checkTheServiceUnavailableAction(Dependency dependency,
+ Element metadata) throws ConfigurationException {
+ if (metadata.containsAttribute("nullable") || dependency.getDefaultImplementation() != null || dependency
+ .getException() != null) {
+ // Rule 1:
+ String message = "The `nullable`, `default-implementation` and `exception` attributes are not " +
+ "usable in " + DependencyHandler.getDependencyIdentifier(dependency) + " - reason: ";
+ if (dependency.isAggregate()) {
+ throw new ConfigurationException(message + "the dependency is aggregate");
+ }
+ if (! dependency.isOptional()) {
+ throw new ConfigurationException(message + "the dependency is mandatory");
+ }
+
+ // At this point, we know that the dependency is scalar and optional, and at least one attribute is set
+
+ // Rule 2:
+ message = "Inconsistent use of the `nullable`, `default-implementation` and `exception` attributes are " +
+ "not usable in " + DependencyHandler.getDependencyIdentifier(dependency) + " - reason: ";
+ if (metadata.containsAttribute("nullable") && dependency.getDefaultImplementation() != null) {
+ throw new ConfigurationException(message + "`nullable` and `default-implementation` cannot be " +
+ "combined");
+ }
+ if (metadata.containsAttribute("nullable") && dependency.getException() != null) {
+ throw new ConfigurationException(message + "`nullable` and `exception` cannot be combined");
+ }
+ if (dependency.getDefaultImplementation() != null && dependency.getException() != null) {
+ throw new ConfigurationException(message + "`exception` and `default-implementation` cannot be " +
+ "combined");
+ }
+ }
+
+ // Rule 3:
+ if (dependency.getTimeout() != 0 && ! dependency.isOptional()) {
+ throw new ConfigurationException("The `timeout` attribute is not usable in " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " - reason: the dependency is not optional");
+ }
+
+
+
+
+ }
+
+ /**
+ * Tries to determine the service specification to inject in the dependency.
+ * If the specification is already checked by the dependency, just checks the consistency.
+ *
+ * @param dependency the dependency
+ * @param manipulation the manipulation metadata
+ * @throws ConfigurationException if the specification cannot be deduced, or when the set specification is not
+ * consistent.
+ */
+ private static void deduceTheServiceSpecification(Dependency dependency, PojoMetadata manipulation) throws
+ ConfigurationException {
+
+ // Deduction algorithm
+ String fieldType = null;
+ String callbackType = null;
+ String constructorType = null;
+ // First check the field
+ if (dependency.getField() != null) {
+ fieldType = extractSpecificationFromField(dependency.getField(), manipulation);
+ }
+ if (dependency.getCallbacks() != null && dependency.getCallbacks().length != 0) {
+ callbackType = extractSpecificationFromMethods(dependency, dependency.getCallbacks(), manipulation);
+ }
+ if (dependency.getConstructorParameterIndex() != -1) {
+ constructorType = extractSpecificationFromConstructor(dependency.getConstructorParameterIndex(),
+ manipulation);
+ }
+
+ if (dependency.getSpecification() == null
+ && fieldType == null && callbackType == null && constructorType == null) {
+ throw new ConfigurationException("The deduction of the service specification for " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " has failed - reason: when neither the field, " +
+ "methods and constructor parameter have provided the service specification, " +
+ "the `specification` attribute must be set");
+
+ }
+
+ // The Dependency.setSpecification method check whether the specification coming from the different sources
+ // are consistent.
+ if (fieldType != null) {
+ setSpecification(dependency, fieldType);
+ }
+ if (callbackType != null) {
+ setSpecification(dependency, callbackType);
+ }
+ if (constructorType != null) {
+ setSpecification(dependency, constructorType);
+ }
+ }
+
+ private static String extractSpecificationFromMethods(Dependency dependency, DependencyCallback[] callbacks,
+ PojoMetadata manipulation) throws ConfigurationException {
+ String type = null;
+ for (DependencyCallback callback : callbacks) {
+ MethodMetadata metadata = manipulation.getMethod(callback.getMethodName());
+ if (metadata != null) {
+ String[] parameters = metadata.getMethodArguments();
+ if (parameters.length == 1 || parameters.length == 2) {
+ if (! ServiceReference.class.getName().equals(parameters[0])
+ && ! Dictionary.class.getName().equals(parameters[0])
+ && ! Map.class.getName().equals(parameters[0])) {
+ if (type == null) {
+ type = parameters[0];
+ } else {
+ if (! type.equals(parameters[0])) {
+ throw new ConfigurationException("The callbacks of " + DependencyHandler
+ .getDependencyIdentifier(dependency) + " have inconsistent parameters");
+ }
+ }
+ }
+ }
+ }
+ }
+ return type;
+ }
+
+ private static String extractSpecificationFromConstructor(int index, PojoMetadata manipulation) {
+ // We can write the following instructions as everything was previously checked.
+ String type = manipulation.getConstructors()[0].getMethodArguments()[index];
+ if (type.endsWith("[]")) {
+ return type.substring(0, type.length() - 2);
+ }
+ if (AggregateDependencyInjectionType.AGGREGATE_TYPES.contains(type)) {
+ return null; // It's an aggregate
+ }
+ return type;
+ }
+
+ /**
+ * Extracts the service specification from the field.
+ * When this method is called, we know that the field is containing in the component class.
+ * @param field the field
+ * @param manipulation the manipulation metadata
+ * @return the service specification, or {@code null} if is cannot be extracted.
+ */
+ private static String extractSpecificationFromField(String field, PojoMetadata manipulation) {
+ FieldMetadata metadata = manipulation.getField(field);
+ if (metadata.getFieldType().endsWith("[]")) {
+ return metadata.getFieldType().substring(0, metadata.getFieldType().length() - 2);
+ }
+ if (AggregateDependencyInjectionType.AGGREGATE_TYPES.contains(metadata.getFieldType())) {
+ return null; // It's an aggregate
+ }
+ return metadata.getFieldType();
+ }
+
+ /**
+ * Sets the dependency specification. If the dependency has already a specification set,
+ * throw an error if the current specification and the given one are not equal.
+ * @param dep the dependency
+ * @param className the service specification
+ * @throws ConfigurationException if the given specification is not loadable or if the dependency has already a
+ * specification set that is not the given one.
+ */
+ private static void setSpecification(Dependency dep, String className) throws ConfigurationException {
+ if (dep.getSpecification() != null && ! dep.getSpecification().getName().equals(className)) {
+ throw new ConfigurationException("Inconsistent service specification for " + DependencyHandler
+ .getDependencyIdentifier(dep) + " - reason: mismatch between the current specification (" + dep
+ .getSpecification().getName() + ") and the discovered specification (" + className + ")");
+ } else if (dep.getSpecification() == null) {
+ // Set the specification
+ try {
+ dep.setSpecification(dep.getBundleContext().getBundle().loadClass(className));
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("Cannot set the service specification of " + DependencyHandler
+ .getDependencyIdentifier(dep) + " - reason: the class " + className + " cannot be loaded from" +
+ " the bundle " + dep.getBundleContext().getBundle().getBundleId(), e);
+ }
+ }
+ }
+
+}
Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java?rev=1527496&r1=1527495&r2=1527496&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java Mon Sep 30 09:34:36 2013
@@ -1,4 +1,4 @@
-/*
+/*
* 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
Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java?rev=1527496&r1=1527495&r2=1527496&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java Mon Sep 30 09:34:36 2013
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+
package org.apache.felix.ipojo.handlers.dependency;
import java.util.*;
@@ -70,24 +71,6 @@ public class DependencyHandler extends P
public static final String PROXY_DISABLED = "disabled";
/**
- * Dependency field type : Vector
- * The dependency will be injected as a vector.
- */
- protected static final int VECTOR = 2;
-
- /**
- * Dependency Field Type : List.
- * The dependency will be injected as a list.
- */
- protected static final int LIST = 1;
-
- /**
- * Dependency Field Type : Set.
- * The dependency will be injected as a set.
- */
- protected static final int SET = 3;
-
- /**
* List of dependencies of the component.
*/
private final List<Dependency> m_dependencies = new ArrayList<Dependency>();
@@ -173,167 +156,6 @@ public class DependencyHandler extends P
}
/**
- * Check if the dependency given is valid in the sense that metadata are consistent.
- * @param dep : the dependency to check
- * @param manipulation : the component-type manipulation metadata
- * @return true if the dependency is valid
- * @throws ConfigurationException : the checked dependency is not correct
- */
- private boolean checkDependency(Dependency dep, PojoMetadata manipulation) throws ConfigurationException {
- // Check the internal type of dependency
- String field = dep.getField();
- DependencyCallback[] callbacks = dep.getCallbacks();
- int index = dep.getConstructorParameterIndex();
-
- if (callbacks == null && field == null && index == -1) {
- throw new ConfigurationException("A service dependency requires at least binding methods, " +
- "a field or a constructor parameter " + getDependencyIdentifier(dep));
- }
-
- for (int i = 0; callbacks != null && i < callbacks.length; i++) {
- MethodMetadata[] mets = manipulation.getMethods(callbacks[i].getMethodName());
- if (mets.length == 0) {
- debug("A dependency callback " + callbacks[i].getMethodName() + " does not exist in the " +
- "implementation class, will try the super classes " + getDependencyIdentifier(dep));
- } else {
- if (mets[0].getMethodArguments().length > 2) {
- throw new ConfigurationException("Requirement Callback : A requirement callback "
- + callbacks[i].getMethodName()
- + " must have 0, 1 or 2 arguments " + getDependencyIdentifier(dep));
- }
-
- callbacks[i].setArgument(mets[0].getMethodArguments());
-
- if (mets[0].getMethodArguments().length == 1) {
- if (!mets[0].getMethodArguments()[0].equals(ServiceReference.class.getName())) {
- // The callback receives the service object.
- setSpecification(dep, mets[0].getMethodArguments()[0], false); // Just warn if a mismatch is discovered.
- }
- } else if (mets[0].getMethodArguments().length == 2) {
- // The callback receives service object, service reference. Check that the second argument is a service reference
- if (!(mets[0].getMethodArguments()[1].equals(ServiceReference.class.getName()) // callback with (service object, service reference)
- || mets[0].getMethodArguments()[1].equals(Dictionary.class.getName()) // callback with (service object, service properties in a dictionary)
- || mets[0].getMethodArguments()[1].equals(Map.class.getName()))) { // callback with (service object, service properties in a map)
- String message =
- "The requirement callback " + callbacks[i].getMethodName() + " must have a " +
- "ServiceReference, a Dictionary or a Map as the second argument " +
- getDependencyIdentifier(dep);
- throw new ConfigurationException(message);
- }
- setSpecification(dep, mets[0].getMethodArguments()[0], false); // Just warn if a mismatch is discovered.
- }
- }
-
- }
-
- if (field != null) {
- FieldMetadata meta = manipulation.getField(field);
- if (meta == null) {
- throw new ConfigurationException("Requirement Callback : A requirement field "
- + field
- + " does not exist in the implementation class " + getDependencyIdentifier(dep));
- }
- String type = meta.getFieldType();
- if (type.endsWith("[]")) {
- if (dep.isProxy()) {
- info("Arrays cannot be used for dependencies using proxies - Disabling the proxy mode " +
- getDependencyIdentifier(dep));
- dep.setProxy(false);
- }
- // Set the dependency to multiple
- dep.setAggregate(true);
- type = type.substring(0, type.length() - 2);
- } else if (type.equals(List.class.getName()) || type.equals(Collection.class.getName())) {
- dep.setType(LIST);
- type = null;
- } else if (type.equals(Vector.class.getName())) {
- dep.setType(VECTOR);
- if (dep.isProxy()) {
- warn("Vectors cannot be used for dependencies using proxies - Disabling the proxy mode " +
- getDependencyIdentifier(dep));
- dep.setProxy(false);
- }
- type = null;
- } else if (type.equals(Set.class.getName())) {
- dep.setType(SET);
- type = null;
- } else {
- if (dep.isAggregate()) {
- throw new ConfigurationException("A required service is not correct : the field "
- + meta.getFieldName()
- + " must be an array or a collection to support aggregate injections " +
- getDependencyIdentifier(dep));
- }
- }
- setSpecification(dep, type, true); // Throws an exception if the field type mismatch.
- }
-
- // Constructor parameter
- if (index != -1) {
- if (! dep.isProxy()) {
- throw new ConfigurationException("Services injected into constructor must use proxies " +
- getDependencyIdentifier(dep));
- }
-
- MethodMetadata[] cts = manipulation.getConstructors();
- // If we don't have a type, try to get the first constructor and get the type of the parameter
- // we the index 'index'.
- if (cts.length > 0 && cts[0].getMethodArguments().length > index) {
- String type = cts[0].getMethodArguments()[index];
- if (type.endsWith("[]")) {
- throw new ConfigurationException("Services injected into constructor cannot be arrays " +
- getDependencyIdentifier(dep));
- } else if (type.equals(List.class.getName()) || type.equals(Collection.class.getName())) {
- dep.setType(LIST);
- type = null;
- } else if (type.equals(Vector.class.getName())) {
- throw new ConfigurationException("Services injected into constructor cannot be Vectors " +
- getDependencyIdentifier(dep));
- } else if (type.equals(Set.class.getName())) {
- dep.setType(SET);
- type = null;
- } else {
- if (dep.isAggregate()) {
- throw new ConfigurationException("A required service is not correct : the constructor parameter "
- + index
- + " must be an aggregate type to support aggregate injections " +
- getDependencyIdentifier(dep));
- }
- }
- setSpecification(dep, type, true); // Throws an exception if the field type mismatch.
- } else {
- throw new ConfigurationException("Cannot determine the specification of the dependency " + index +
- ", please use the specification attribute " + getDependencyIdentifier(dep));
- }
- }
-
- // At this point we must have discovered the specification, it it's null, throw a ConfiguraitonException
- if (dep.getSpecification() == null) {
- String identifier = getDependencyIdentifier(dep);
- throw new ConfigurationException("Cannot determine the targeted service specification for the dependency " +
- identifier);
- }
-
- // Disable proxy on scalar dependency targeting non-interface specification
- if (! dep.isAggregate() && dep.isProxy()) {
- if (! dep.getSpecification().isInterface()) {
- warn("Proxies cannot be used on service dependency targeting non interface " +
- "service specification " + getDependencyIdentifier(dep));
- dep.setProxy(false);
- }
- }
-
- // Disables proxy on null (nullable=false)
-// if (dep.isProxy() && dep.isOptional() && ! dep.supportsNullable()) {
-// dep.setProxy(false);
-// warn("Optional Null Dependencies do not support proxying - Disable the proxy mode");
-// }
-
- // Check that all required info are set
- return dep.getSpecification() != null;
- }
-
- /**
* Builds a description of this dependency to help the user to identify it. IT's not related to the Dependency
* Description, it's just a string containing dependency information to spot it easily in the code.
* @param dep the dependency
@@ -368,65 +190,6 @@ public class DependencyHandler extends P
}
/**
- * Check if we have to set the dependency specification with the given class name.
- * @param dep : dependency to check
- * @param className : class name
- * @param error : set to true to throw an error if the set dependency specification and the given specification are different.
- * @throws ConfigurationException : the specification class cannot be loaded correctly
- */
- private void setSpecification(Dependency dep, String className, boolean error) throws ConfigurationException {
- if (className == null) {
- // No found type (list and vector)
- if (dep.getSpecification() == null) {
- if (error) {
- String id = dep.getId();
- if (id == null) {
- id = dep.getField();
- if (id == null) {
- id = Integer.toString(dep.getConstructorParameterIndex());
- }
- }
- throw new ConfigurationException("Cannot discover the required specification for " +
- getDependencyIdentifier(dep));
- } else {
- // If the specification is different, warn that we will override it.
- info("Cannot discover the required specification for " + dep.getField());
- }
- }
- } else { // In all other case, className is not null.
- if (dep.getSpecification() == null || !dep.getSpecification().getName().equals(className)) {
- if (dep.getSpecification() != null) {
- if (error) {
- throw new ConfigurationException("A required service is not correct : the discovered type ["
- + className
- + "] and the specified (or already discovered) service interface ["
- + dep.getSpecification().getName()
- + "] are not the same " + getDependencyIdentifier(dep));
- } else {
- // If the specification is different, warn that we will override it.
- warn("["
- + getInstanceManager().getInstanceName()
- + "] The field type ["
- + className
- + "] and the required service interface ["
- + dep.getSpecification()
- + "] are not the same " + getDependencyIdentifier(dep));
- }
- }
-
- Bundle bundle = getInstanceManager().getContext().getBundle();
- try {
- dep.setSpecification(bundle.loadClass(className));
- } catch (ClassNotFoundException e) {
- throw new ConfigurationException("The required service interface (" + className
- + ") cannot be loaded from bundle " + bundle.getBundleId() + " " +
- getDependencyIdentifier(dep), e);
- }
- }
- }
- }
-
- /**
* Configure the handler.
* @param componentMetadata : the component type metadata
* @param configuration : the instance configuration
@@ -497,14 +260,14 @@ public class DependencyHandler extends P
dep.addConstructorInjection(index);
}
- // Check the dependency :
- if (checkDependency(dep, manipulation)) {
- m_dependencies.add(dep);
- if (dep.getField() != null) {
- getInstanceManager().register(manipulation.getField(dep.getField()), dep);
- atLeastOneField = true;
- }
+ // Check the dependency, throws an exception on error.
+ DependencyConfigurationChecker.ensure(dep, dependencyElement, manipulation);
+ m_dependencies.add(dep);
+ if (dep.getField() != null) {
+ getInstanceManager().register(manipulation.getField(dep.getField()), dep);
+ atLeastOneField = true;
}
+
}
if (atLeastOneField) { // Does register only if we have fields
Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java?rev=1527496&r1=1527495&r2=1527496&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java Mon Sep 30 09:34:36 2013
@@ -1,4 +1,4 @@
-/*
+/*
* 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
Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java?rev=1527496&r1=1527495&r2=1527496&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java Mon Sep 30 09:34:36 2013
@@ -1,4 +1,4 @@
-/*
+/*
* 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
Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java?rev=1527496&r1=1527495&r2=1527496&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java Mon Sep 30 09:34:36 2013
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+
package org.apache.felix.ipojo.handlers.dependency;
Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceCollection.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceCollection.java?rev=1527496&r1=1527495&r2=1527496&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceCollection.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceCollection.java Mon Sep 30 09:34:36 2013
@@ -1,4 +1,4 @@
-/*
+/*
* 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
Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java?rev=1527496&r1=1527495&r2=1527496&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java Mon Sep 30 09:34:36 2013
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -24,7 +24,7 @@ package org.apache.felix.ipojo.handlers.
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
-public class ServiceUsage extends ThreadLocal {
+public class ServiceUsage extends ThreadLocal<ServiceUsage.Usage> {
/**
* Structure contained in the Thread Local.
@@ -93,7 +93,7 @@ public class ServiceUsage extends Thread
* @return an empty Usage object.
* @see java.lang.ThreadLocal#initialValue()
*/
- public Object initialValue() {
+ public Usage initialValue() {
return new Usage();
}
Modified: felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java?rev=1527496&r1=1527495&r2=1527496&view=diff
==============================================================================
--- felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java (original)
+++ felix/trunk/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java Mon Sep 30 09:34:36 2013
@@ -21,6 +21,7 @@ package org.apache.felix.ipojo.util;
import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.IPOJOServiceFactory;
import org.apache.felix.ipojo.dependency.impl.ServiceReferenceManager;
+import org.apache.felix.ipojo.handlers.dependency.DependencyCallback;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;