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;