Improve configuration error detection and reporting of service dependency (FELIX-4243 Define the dependency configuration matrix and improve error detection)
Added test about FELIX-4250 Specification deduction broken when the method does not start with the 'bind' prefix
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1527496 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
index 6c631f5..b708d80 100644
--- a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/CheckServiceProvider.java
@@ -45,28 +45,28 @@
public Properties getProps() {
Properties props = new Properties();
- props.put("voidB", new Integer(simpleB));
- props.put("objectB", new Integer(objectB));
- props.put("refB", new Integer(refB));
- props.put("bothB", new Integer(bothB));
- props.put("voidU", new Integer(simpleU));
- props.put("objectU", new Integer(objectU));
- props.put("refU", new Integer(refU));
- props.put("bothU", new Integer(bothU));
- props.put("mapB", new Integer(mapB));
- props.put("dictB", new Integer(dictB));
- props.put("mapU", new Integer(mapU));
- props.put("dictU", new Integer(dictU));
+ props.put("voidB", simpleB);
+ props.put("objectB", objectB);
+ props.put("refB", refB);
+ props.put("bothB", bothB);
+ props.put("voidU", simpleU);
+ props.put("objectU", objectU);
+ props.put("refU", refU);
+ props.put("bothU", bothU);
+ props.put("mapB", mapB);
+ props.put("dictB", dictB);
+ props.put("mapU", mapU);
+ props.put("dictU", dictU);
if (fs != null) {
// If nullable = false and proxy, a runtime exception may be launched here
// catch the exception and add this to props.
try {
props.put("exception", Boolean.FALSE); // Set exception to false for checking.
- props.put("result", new Boolean(fs.foo()));
- props.put("boolean", new Boolean(fs.getBoolean()));
- props.put("int", new Integer(fs.getInt()));
- props.put("long", new Long(fs.getLong()));
- props.put("double", new Double(fs.getDouble()));
+ props.put("result", fs.foo());
+ props.put("boolean", fs.getBoolean());
+ props.put("int", fs.getInt());
+ props.put("long", fs.getLong());
+ props.put("double", fs.getDouble());
if(fs.getObject() != null) { props.put("object", fs.getObject()); }
} catch (RuntimeException e) {
props.put("exception", Boolean.TRUE);
@@ -77,7 +77,7 @@
// Add modified
- props.put("modified", new Integer(modified));
+ props.put("modified", modified);
return props;
}
@@ -95,7 +95,7 @@
System.err.println("Bind receive null !!! ");
return;
}
- if(o != null && o instanceof FooService) { objectB++; }
+ objectB++;
}
protected void objectModify(FooService o) {
@@ -103,7 +103,7 @@
System.err.println("Bind receive null !!! [" + modified + "]");
return;
}
- if(o != null && o instanceof FooService) { modified++; }
+ modified++;
}
public void refBind(ServiceReference sr) {
@@ -115,30 +115,30 @@
}
public void bothBind(FooService o, ServiceReference sr) {
- if(sr != null && o != null && o instanceof FooService) { bothB++; }
+ if(sr != null && o != null) { bothB++; }
}
public void bothModify(FooService o, ServiceReference sr) {
- if(sr != null && o != null && o instanceof FooService) { modified++; }
+ if(sr != null && o != null) { modified++; }
}
protected void propertiesDictionaryBind(FooService o, Dictionary props) {
- if(props != null && o != null && o instanceof FooService && props.size() > 0) { dictB++; }
+ if(props != null && o != null && props.size() > 0) { dictB++; }
fs = o;
}
protected void propertiesDictionaryModify(FooService o, Dictionary props) {
- if(props != null && o != null && o instanceof FooService && props.size() > 0) { modified++; }
+ if(props != null && o != null && props.size() > 0) { modified++; }
fs = o;
}
protected void propertiesMapBind(FooService o, Map props) {
- if(props != null && o != null && o instanceof FooService && props.size() > 0) { mapB++; }
+ if(props != null && o != null && props.size() > 0) { mapB++; }
fs = o;
}
protected void propertiesMapModify(FooService o, Map props) {
- if(props != null && o != null && o instanceof FooService && props.size() > 0) { modified++; }
+ if(props != null && o != null && props.size() > 0) { modified++; }
fs = o;
}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java
index 55ed5f0..9f8a9b2 100644
--- a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java
@@ -59,7 +59,7 @@
fs.foo();
return true; // always return true, to detect the exception case.
} catch (NoServiceException e) {
- return true;
+ return false;
}
}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ContextualFilterConsumer.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ContextualFilterConsumer.java
index 4415210..d234467 100644
--- a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ContextualFilterConsumer.java
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/context/ContextualFilterConsumer.java
@@ -36,7 +36,7 @@
@Provides
public class ContextualFilterConsumer implements CheckService {
- @Requires(nullable = false, id = "foo")
+ @Requires(id = "foo")
private FooService foo;
@Override
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/identification/ComponentWithCustomMethods.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/identification/ComponentWithCustomMethods.java
new file mode 100644
index 0000000..b76b34d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/identification/ComponentWithCustomMethods.java
@@ -0,0 +1,64 @@
+/*
+ * 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.runtime.core.test.components.identification;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Unbind;
+import org.apache.felix.ipojo.runtime.core.test.services.Call;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Set;
+
+/**
+ * A component reproducing FELIX-4250 - Specification deduction broken when the method does not start with the 'bind'
+ * prefix (https://issues.apache.org/jira/browse/FELIX-4250).
+ *
+ * The add and remove methods should be attached to the same dependency (id = MyService)
+ * The set and unset methods should be attached to the same dependency (id = MyOtherService)
+ */
+@Component
+public class ComponentWithCustomMethods {
+
+ Set<FooService> myServices;
+
+ Set<Call> myOtherServices;
+
+ @Bind(optional=true, aggregate=true)
+ public void addMyService(FooService newService) {
+ myServices.add(newService);
+ }
+
+ @Unbind
+ public void removeMyService(FooService oldService) {
+ myServices.remove(oldService);
+ }
+
+
+ @Bind(optional=true, aggregate=true)
+ public void setMyOtherService(Call newService) {
+ myOtherServices.add(newService);
+ }
+
+ @Unbind
+ public void unsetMyOtherService(Call oldService) {
+ myOtherServices.remove(oldService);
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
index 46e0f65..8af42c8 100644
--- a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/Common.java
@@ -19,11 +19,16 @@
package org.apache.felix.ipojo.runtime.core.test.dependencies;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
import org.ow2.chameleon.testing.helpers.BaseTest;
import java.util.Arrays;
import java.util.List;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+
/**
* Bootstrap the test from this project
*/
@@ -36,4 +41,12 @@
);
}
+ @Override
+ protected Option[] getCustomOptions() {
+ return new Option[] {
+ wrappedBundle(maven("org.easytesting", "fest-assert").versionAsInProject()),
+ wrappedBundle(maven("org.easytesting", "fest-util").versionAsInProject())
+ };
+ }
+
}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/identification/TestDependencyIdDetection.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/identification/TestDependencyIdDetection.java
new file mode 100644
index 0000000..630058d
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/identification/TestDependencyIdDetection.java
@@ -0,0 +1,108 @@
+/*
+ * 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.runtime.core.test.dependencies.identification;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.annotations.HandlerDeclaration;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyCallback;
+import org.apache.felix.ipojo.handlers.dependency.DependencyDescription;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class TestDependencyIdDetection extends Common {
+ String factory = "org.apache.felix.ipojo.runtime.core.test.components.identification.ComponentWithCustomMethods";
+
+ @Test
+ public void testSetAndUnSetMethods() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance(factory);
+ DependencyHandlerDescription dh = (DependencyHandlerDescription) instance.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:requires");
+
+ DependencyDescription dd = findDependencyById(dh, "MyOtherService");
+ assertThat(dd).isNotNull();
+
+ DependencyCallback[] callbacks = dd.getDependency().getDependencyCallbacks();
+ assertThat(callbacks).isNotNull();
+
+ DependencyCallback bind = getBindCallback(callbacks);
+ DependencyCallback unbind = getUnbindCallback(callbacks);
+
+ assertThat(bind).isNotNull();
+ assertThat(unbind).isNotNull();
+
+ assertThat(bind.getMethodName()).isEqualTo("setMyOtherService");
+ assertThat(unbind.getMethodName()).isEqualTo("unsetMyOtherService");
+ }
+
+ @Test
+ public void testAddAndRemoveMethods() {
+ ComponentInstance instance = ipojoHelper.createComponentInstance(factory);
+ DependencyHandlerDescription dh = (DependencyHandlerDescription) instance.getInstanceDescription()
+ .getHandlerDescription("org.apache.felix.ipojo:requires");
+
+ DependencyDescription dd = findDependencyById(dh, "MyService");
+ assertThat(dd).isNotNull();
+
+ DependencyCallback[] callbacks = dd.getDependency().getDependencyCallbacks();
+ assertThat(callbacks).isNotNull();
+
+ DependencyCallback bind = getBindCallback(callbacks);
+ DependencyCallback unbind = getUnbindCallback(callbacks);
+
+ assertThat(bind).isNotNull();
+ assertThat(unbind).isNotNull();
+
+ assertThat(bind.getMethodName()).isEqualTo("addMyService");
+ assertThat(unbind.getMethodName()).isEqualTo("removeMyService");
+ }
+
+ private DependencyCallback getBindCallback(DependencyCallback[] callbacks) {
+ for (DependencyCallback callback : callbacks) {
+ if (callback.getMethodType() == DependencyCallback.BIND) {
+ return callback;
+ }
+ }
+ return null;
+ }
+
+ private DependencyCallback getUnbindCallback(DependencyCallback[] callbacks) {
+ for (DependencyCallback callback : callbacks) {
+ if (callback.getMethodType() == DependencyCallback.UNBIND) {
+ return callback;
+ }
+ }
+ return null;
+ }
+
+ private DependencyDescription findDependencyById(DependencyHandlerDescription dh, String id) {
+ for (DependencyDescription dd : dh.getDependencies()) {
+ if (dd.getId().equals(id)) {
+ return dd;
+ }
+ }
+ return null;
+ }
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
index 0383ce3..660ceba 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
@@ -187,7 +187,7 @@
} catch (Throwable e) { // All others exception are handled here.
// As for the previous case, the instance is stopped.
instance.stop();
- m_logger.log(Logger.ERROR, e.getMessage(), e);
+ m_logger.log(Logger.INFO, "An error occurred when creating an instance of " + getFactoryName(), e);
throw new ConfigurationException(e.getMessage(), e);
}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/AggregateDependencyInjectionType.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/AggregateDependencyInjectionType.java
new file mode 100644
index 0000000..56ba6ec
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/AggregateDependencyInjectionType.java
@@ -0,0 +1,41 @@
+/*
+ * 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 java.util.*;
+
+/**
+ * An enumeration listing the different possibility to inject an aggregate dependency in a field or constructor
+ * parameter.
+ */
+public enum AggregateDependencyInjectionType {
+
+ ARRAY,
+ LIST,
+ SET,
+ VECTOR;
+
+ public static List<String> AGGREGATE_TYPES =
+ Arrays.asList(
+ List.class.getName(),
+ Vector.class.getName(),
+ Set.class.getName(),
+ Collection.class.getName());
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
index 9017751..4f9c71a 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+
package org.apache.felix.ipojo.handlers.dependency;
import org.apache.felix.ipojo.*;
@@ -80,10 +81,11 @@
*/
private ServiceUsage m_usage;
/**
- * Type of the object to inject.
+ * Type of the object to inject in aggregate dependency. This value is used to determine what kind of object need
+ * to be injected for fields and constructor parameter for aggregate dependencies.
* Cannot change once set.
*/
- private int m_type;
+ private AggregateDependencyInjectionType m_type;
/**
* Nullable object.
* Immutable once set.
@@ -107,6 +109,10 @@
* -1 if not used.
*/
private int m_index = -1;
+
+ /**
+ * The dependency timeout.
+ */
private int m_timeout;
/**
@@ -599,6 +605,16 @@
}
}
+
+ /**
+ * Gets the list of callbacks attached to the current dependency.
+ * @return the array of dependency callback, {@code null} if no callbacks are attached to the current dependency.
+ */
+ public DependencyCallback[] getDependencyCallbacks() {
+ return m_callbacks;
+ }
+
+
/**
* Called by the proxy to get service objects to delegate a method.
* On aggregate dependencies, it returns a list.
@@ -690,7 +706,7 @@
public Object onGet(Object pojo, String fieldName, Object value) {
// Initialize the thread local object is not already touched.
- Usage usage = (Usage) m_usage.get();
+ Usage usage = m_usage.get();
if (usage.m_stack == 0) { // uninitialized usage.
createServiceObject(usage);
usage.inc(); // Start the caching, so set the stack level to 1
@@ -737,59 +753,60 @@
usage.m_object = getService(ref);
}
} else {
- if (m_type == 0) { // Array
- try {
+ switch(m_type) {
+ case ARRAY:
+ try {
+ if (refs == null) {
+ usage.m_object = (Object[]) Array.newInstance(getSpecification(), 0); // Create an empty array.
+ } else {
+ // Use a reflective construction to avoid class cast exception. This method allows setting the component type.
+ Object[] objs = (Object[]) Array.newInstance(getSpecification(), refs.length);
+ for (int i = 0; i < refs.length; i++) {
+ ServiceReference ref = refs[i];
+ objs[i] = getService(ref);
+ }
+ usage.m_object = objs;
+ }
+ } catch (ArrayStoreException e) {
+ throw new RuntimeException("Cannot create the array - Check that the bundle can access the service interface", e);
+ }
+ break;
+ case LIST:
if (refs == null) {
- usage.m_object = (Object[]) Array.newInstance(getSpecification(), 0); // Create an empty array.
+ usage.m_object = Collections.emptyList();
} else {
- // Use a reflective construction to avoid class cast exception. This method allows setting the component type.
- Object[] objs = (Object[]) Array.newInstance(getSpecification(), refs.length);
- for (int i = 0; i < refs.length; i++) {
- ServiceReference ref = refs[i];
- objs[i] = getService(ref);
+ // Use a list to store service objects
+ List<Object> objs = new ArrayList<Object>(refs.length);
+ for (ServiceReference ref : refs) {
+ objs.add(getService(ref));
}
usage.m_object = objs;
}
- } catch (ArrayStoreException e) {
- m_handler.error("Cannot create the array - Check that the bundle can access the service interface", e);
- throw new RuntimeException("Cannot create the array - Check that the bundle can access the service interface", e);
- }
- } else if (m_type == DependencyHandler.LIST) {
- if (refs == null) {
- usage.m_object = new ArrayList(0); // Create an empty list.
- } else {
- // Use a list to store service objects
- List objs = new ArrayList(refs.length);
- for (int i = 0; refs != null && i < refs.length; i++) {
- ServiceReference ref = refs[i];
- objs.add(getService(ref));
+ break;
+ case SET:
+ if (refs == null) {
+ usage.m_object = Collections.emptySet();
+ } else {
+ // Use a vector to store service objects
+ Set<Object> objs = new HashSet<Object>(refs.length);
+ for (ServiceReference ref : refs) {
+ objs.add(getService(ref));
+ }
+ usage.m_object = objs;
}
- usage.m_object = objs;
- }
- } else if (m_type == DependencyHandler.VECTOR) {
- if (refs == null) {
- usage.m_object = new Vector(0); // Create an empty vector.
- } else {
- // Use a vector to store service objects
- Vector objs = new Vector(refs.length);
- for (int i = 0; refs != null && i < refs.length; i++) {
- ServiceReference ref = refs[i];
- objs.add(getService(ref));
+ break;
+ case VECTOR:
+ if (refs == null) {
+ usage.m_object = new Vector(0); // Create an empty vector.
+ } else {
+ // Use a vector to store service objects
+ Vector<Object> objs = new Vector<Object>(refs.length);
+ for (ServiceReference ref : refs) {
+ objs.add(getService(ref));
+ }
+ usage.m_object = objs;
}
- usage.m_object = objs;
- }
- } else if (m_type == DependencyHandler.SET) {
- if (refs == null) {
- usage.m_object = new HashSet(0); // Create an empty vector.
- } else {
- // Use a vector to store service objects
- Set objs = new HashSet(refs.length);
- for (int i = 0; refs != null && i < refs.length; i++) {
- ServiceReference ref = refs[i];
- objs.add(getService(ref));
- }
- usage.m_object = objs;
- }
+ break;
}
}
}
@@ -841,7 +858,7 @@
*/
public void onEntry(Object pojo, Member method, Object[] args) {
if (m_usage != null) {
- Usage usage = (Usage) m_usage.get();
+ Usage usage = m_usage.get();
usage.incComponentStack(); // Increment the number of component access.
if (usage.m_stack > 0) {
usage.inc();
@@ -884,13 +901,14 @@
*/
public void onFinally(Object pojo, Member method) {
if (m_usage != null) {
- Usage usage = (Usage) m_usage.get();
+ Usage usage = m_usage.get();
usage.decComponentStack();
if (usage.m_stack > 0) {
if (usage.dec()) {
// Exit the method flow => Release all objects
usage.clear();
- m_usage.set(usage); // Set the Thread local as value has been modified
+ // Also remove the thread local object.
+ m_usage.remove();
}
}
}
@@ -902,7 +920,9 @@
* @return true if the dependency is optional and supports nullable objects.
*/
public boolean supportsNullable() {
- return m_supportNullable;
+ return isOptional()
+ && ! isAggregate()
+ && m_supportNullable;
}
public String getDefaultImplementation() {
@@ -921,9 +941,9 @@
* Set the type to inject.
* This method set the dependency as aggregate.
*
- * @param type either list of vector
+ * @param type the type to inject.
*/
- protected void setType(int type) {
+ protected void setAggregateType(AggregateDependencyInjectionType type) {
setAggregate(true);
m_type = type;
}
@@ -974,11 +994,10 @@
if (m_index == index && m_proxyObject != null) {
if (isAggregate()) {
switch (m_type) {
- case DependencyHandler.LIST:
+ case LIST:
return List.class;
- case DependencyHandler.SET:
+ case SET:
return Set.class;
- //TODO We should also manage the Collection type.
default:
return null; // Should never happen, it was checked before.
}
@@ -990,6 +1009,18 @@
}
}
+ public String getException() {
+ return m_exception;
+ }
+
+ public int getTimeout() {
+ return m_timeout;
+ }
+
+ public AggregateDependencyInjectionType getAggregateType() {
+ return m_type;
+ }
+
/**
* Classloader for nullable objects.
*/
@@ -1173,7 +1204,7 @@
Class declaringClass = method.getDeclaringClass();
if (declaringClass == Object.class) {
if (method.equals(m_hashCodeMethod)) {
- return new Integer(this.hashCode());
+ return this.hashCode();
} else if (method.equals(m_equalsMethod)) {
return proxy == args[0] ? Boolean.TRUE : Boolean.FALSE;
} else if (method.equals(m_toStringMethod)) {
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java
index 571a92c..a7b4c4b 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java
@@ -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
@@ -18,20 +18,17 @@
*/
package org.apache.felix.ipojo.handlers.dependency;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
import org.apache.felix.ipojo.util.Callback;
import org.osgi.framework.ServiceReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
/**
* This class allwos the creation of callback when service dependency arrives or
* disappear.
- *
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class DependencyCallback extends Callback {
@@ -40,44 +37,38 @@
* Bind method (called when a service arrives).
*/
public static final int BIND = 0;
-
/**
* Unbind method (called when a service disappears).
*/
public static final int UNBIND = 1;
-
/**
* Updated method (called when a service is modified).
*/
public static final int MODIFIED = 2;
-
/**
* Is the method a bind method or an unbind method ?
*/
private int m_methodType;
-
/**
* Arguments of the callback.
*/
private String[] m_argument;
-
/**
* Callback method name.
*/
private String m_method;
-
/**
- * Service Dependency.
+ * Service Dependency.
*/
private Dependency m_dependency;
/**
* Constructor.
- *
- * @param dep : the dependency attached to this dependency callback
- * @param method : the method to call
+ *
+ * @param dep : the dependency attached to this dependency callback
+ * @param method : the method to call
* @param methodType : is the method to call a bind method or an unbind
- * method
+ * method
*/
public DependencyCallback(Dependency dep, String method, int methodType) {
super(method, (String[]) null, false, dep.getHandler().getInstanceManager());
@@ -86,23 +77,23 @@
m_method = method;
}
-
public int getMethodType() {
return m_methodType;
}
-
+
public String getMethodName() {
return m_method;
}
-
+
/**
* Set the argument type (Empty or the class name).
+ *
* @param arg : the array of argument types.
*/
public void setArgument(String[] arg) {
m_argument = arg;
}
-
+
/**
* Search the method object in the POJO by analyzing present method.
* If not found in the pojo it tests the parent classes.
@@ -111,11 +102,11 @@
protected void searchMethod() {
if (m_argument != null) {
Method[] methods = m_dependency.getHandler().getInstanceManager().getClazz().getDeclaredMethods();
- for (int i = 0; i < methods.length; i++) {
+ for (Method method : methods) {
// First check the method name
- if (methods[i].getName().equals(m_method)) {
+ if (method.getName().equals(m_method)) {
// Check arguments
- Class[] clazzes = methods[i].getParameterTypes();
+ Class[] clazzes = method.getParameterTypes();
if (clazzes.length == m_argument.length) { // Test size to avoid useless loop // NOPMD
int argIndex = 0;
for (; argIndex < m_argument.length; argIndex++) {
@@ -124,8 +115,8 @@
}
}
if (argIndex == m_argument.length) { // If the array was completely read.
- m_methodObj = methods[i]; // It is the looked method.
- if (! m_methodObj.isAccessible()) {
+ m_methodObj = method; // It is the looked method.
+ if (!m_methodObj.isAccessible()) {
// If not accessible, try to set the accessibility.
m_methodObj.setAccessible(true);
}
@@ -136,22 +127,24 @@
}
}
}
-
+
// Not found => Try parent method.
searchParentMethod();
-
+
if (m_methodObj == null) {
// If not found, stop the instance (fatal error)
- m_dependency.getHandler().error("The method " + m_method + " cannot be called : method not found");
+ m_dependency.getHandler().error("The dependency callback method " + m_method + " cannot be invoked - " +
+ "reason: the method is not defined in the component class (" + m_dependency.getHandler()
+ .getInstanceManager().getClazz().getName() + ")");
m_dependency.getHandler().getInstanceManager().stop();
} else {
- if (! m_methodObj.isAccessible()) {
+ if (!m_methodObj.isAccessible()) {
// If not accessible, try to set the accessibility.
m_methodObj.setAccessible(true);
}
}
}
-
+
/**
* Introspect parent class to find the method.
*/
@@ -174,14 +167,14 @@
if (clazzes[0].getName().equals(ServiceReference.class.getName())) {
// Callback with a service reference.
m_methodObj = methods[i];
- m_argument = new String[] { ServiceReference.class.getName() };
+ m_argument = new String[]{ServiceReference.class.getName()};
return;
}
// The callback receives a Service object
if (clazzes[0].getName().equals(m_dependency.getSpecification().getName())) {
// Callback with the service object.
m_methodObj = methods[i];
- m_argument = new String[] { m_dependency.getSpecification().getName() };
+ m_argument = new String[]{m_dependency.getSpecification().getName()};
return;
}
break;
@@ -190,21 +183,21 @@
if (clazzes[0].getName().equals(m_dependency.getSpecification().getName()) && clazzes[1].getName().equals(ServiceReference.class.getName())) {
// Callback with two arguments.
m_methodObj = methods[i];
- m_argument = new String[] { m_dependency.getSpecification().getName(), ServiceReference.class.getName() };
+ m_argument = new String[]{m_dependency.getSpecification().getName(), ServiceReference.class.getName()};
return;
}
// The callback receives the service object and the service properties (in a Map)
if (clazzes[0].getName().equals(m_dependency.getSpecification().getName()) && clazzes[1].getName().equals(Map.class.getName())) {
// Callback with two arguments.
m_methodObj = methods[i];
- m_argument = new String[] { m_dependency.getSpecification().getName(), Map.class.getName() };
+ m_argument = new String[]{m_dependency.getSpecification().getName(), Map.class.getName()};
return;
}
// The callback receives the service object and the service properties (in a Dictionary)
if (clazzes[0].getName().equals(m_dependency.getSpecification().getName()) && clazzes[1].getName().equals(Dictionary.class.getName())) {
// Callback with two arguments.
m_methodObj = methods[i];
- m_argument = new String[] { m_dependency.getSpecification().getName(), Dictionary.class.getName() };
+ m_argument = new String[]{m_dependency.getSpecification().getName(), Dictionary.class.getName()};
return;
}
break;
@@ -217,38 +210,38 @@
/**
* Call the callback method with a service reference.
- *
+ *
* @param ref : the service reference to send to the method
* @param obj : the service object
- * @throws NoSuchMethodException : Method is not found in the class
+ * @throws NoSuchMethodException : Method is not found in the class
* @throws InvocationTargetException : The method is not static
- * @throws IllegalAccessException : The method can not be invoked
+ * @throws IllegalAccessException : The method can not be invoked
*/
protected void call(ServiceReference ref, Object obj) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (m_methodObj == null) {
searchMethod();
}
switch (m_argument.length) {
- case 0 :
+ case 0:
call(new Object[0]);
break;
- case 1 :
+ case 1:
if (m_argument[0].equals(ServiceReference.class.getName())) {
- call(new Object[] {ref});
+ call(new Object[]{ref});
} else {
- call(new Object[] {obj});
+ call(new Object[]{obj});
}
break;
- case 2 :
+ case 2:
if (m_argument[1].equals(ServiceReference.class.getName())) {
- call(new Object[] {obj, ref});
+ call(new Object[]{obj, ref});
} else if (m_argument[1].equals(Dictionary.class.getName())) {
- call(new Object[] {obj, getPropertiesInDictionary(ref)});
+ call(new Object[]{obj, getPropertiesInDictionary(ref)});
} else {
- call(new Object[] {obj, getPropertiesInMap(ref)});
+ call(new Object[]{obj, getPropertiesInMap(ref)});
}
break;
- default :
+ default:
break;
}
}
@@ -256,6 +249,7 @@
/**
* Creates a {@link Dictionary} containing service properties of the
* given service reference.
+ *
* @param ref the service reference
* @return a {@link Dictionary} containing the service properties.
*/
@@ -267,10 +261,11 @@
}
return dict;
}
-
+
/**
* Creates a {@link Map} containing service properties of the
* given service reference.
+ *
* @param ref the service reference
* @return a {@link Map} containing the service properties.
*/
@@ -283,15 +278,14 @@
return map;
}
-
/**
* Call the callback on the given instance with the given argument.
- *
+ *
* @param instance : the instance on which call the callback
- * @param ref : the service reference to send to the callback
- * @param obj : the service object
- * @throws NoSuchMethodException : the method is not found
- * @throws IllegalAccessException : the method could not be called
+ * @param ref : the service reference to send to the callback
+ * @param obj : the service object
+ * @throws NoSuchMethodException : the method is not found
+ * @throws IllegalAccessException : the method could not be called
* @throws InvocationTargetException : an error happens in the called method
*/
protected void callOnInstance(Object instance, ServiceReference ref, Object obj) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
@@ -299,26 +293,26 @@
searchMethod();
}
switch (m_argument.length) {
- case 0 :
+ case 0:
call(instance, new Object[0]);
break;
- case 1 :
+ case 1:
if (m_argument[0].equals(ServiceReference.class.getName())) {
- call(instance, new Object[] {ref});
+ call(instance, new Object[]{ref});
} else {
- call(instance, new Object[] {obj});
+ call(instance, new Object[]{obj});
}
break;
- case 2 :
+ case 2:
if (m_argument[1].equals(ServiceReference.class.getName())) {
- call(instance, new Object[] {obj, ref});
+ call(instance, new Object[]{obj, ref});
} else if (m_argument[1].equals(Dictionary.class.getName())) {
- call(instance, new Object[] {obj, getPropertiesInDictionary(ref)});
+ call(instance, new Object[]{obj, getPropertiesInDictionary(ref)});
} else {
- call(instance, new Object[] {obj, getPropertiesInMap(ref)});
+ call(instance, new Object[]{obj, getPropertiesInMap(ref)});
}
break;
- default :
+ default:
break;
}
}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java
new file mode 100644
index 0000000..ab84903
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyConfigurationChecker.java
@@ -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);
+ }
+ }
+ }
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java
index adbb126..9e95357 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java
@@ -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
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
index 9af82c4..8c07b76 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
@@ -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 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
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
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java
index a29b18b..74c6e09 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandlerDescription.java
@@ -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
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java
index b11419f..4d9ddd7 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableObject.java
@@ -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
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java
index 1dd2cf3..345afee 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ProxyGenerator.java
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+
package org.apache.felix.ipojo.handlers.dependency;
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceCollection.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceCollection.java
index 369ad94..0273895 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceCollection.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceCollection.java
@@ -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
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java
index 3757e77..365fa01 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/ServiceUsage.java
@@ -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 @@
*
* @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 @@
* @return an empty Usage object.
* @see java.lang.ThreadLocal#initialValue()
*/
- public Object initialValue() {
+ public Usage initialValue() {
return new Usage();
}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
index 1040787..c27e439 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
@@ -21,6 +21,7 @@
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;