Refactor nullable object system.
Add default-implementation attribute allowing to configure the default implementation of a required service instead of the default nullable object.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@587421 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
index 13d8c02..6b343d9 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
@@ -318,40 +318,14 @@
}
} else {
if (m_references.size() == 0) {
- // Load the nullable class
- String className = m_specification + "Nullable";
- Class nullableClazz = m_handler.getNullableClass(className);
+ Object nullable = m_handler.getNullableObject(this);
- if (nullableClazz == null) {
+ if (nullable == null) {
m_handler.log(Logger.WARNING, "[" + m_handler.getInstanceManager().getClassName() + "] Cannot load the nullable class to return a dependency object for " + m_field + " -> " + m_specification);
return null;
}
- // The nullable class is loaded, create the object and add it
- Object instance = null;
- try {
- instance = nullableClazz.newInstance();
- } catch (IllegalAccessException e) {
- // There is a problem in the dependency resolving (like in stopping method)
- if (m_isAggregate) {
- m_handler.log(Logger.ERROR, "[" + m_handler.getInstanceManager().getInstanceName() + "] Return an empty array, an exception was throwed in the get method", e);
- return Array.newInstance(m_clazz, 0);
- } else {
- m_handler.log(Logger.ERROR, "[" + m_handler.getInstanceManager().getInstanceName() + "] Return null, an exception was throwed in the get method", e);
- return null;
- }
- } catch (InstantiationException e) {
- // There is a problem in the dependency resolving (like in stopping
- // method)
- if (m_isAggregate) {
- m_handler.log(Logger.ERROR, "[" + m_handler.getInstanceManager().getInstanceName() + "] Return an empty array, an exception was throwed in the get method", e);
- return Array.newInstance(m_clazz, 0);
- } else {
- m_handler.log(Logger.ERROR, "[" + m_handler.getInstanceManager().getInstanceName() + "] Return null, an exception was throwed in the get method", e);
- return null;
- }
- }
- m_usage.getObjects().add(instance);
+ m_usage.getObjects().add(nullable);
} else {
ServiceReference ref = (ServiceReference) m_references.get(0);
m_usage.getReferences().add(ref); // Get the first one
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
index 2e38641..275f265 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
@@ -21,7 +21,9 @@
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.ConfigurationException;
@@ -48,9 +50,9 @@
private Dependency[] m_dependencies = new Dependency[0];
/**
- * List of nullable class for optional dependencies.
+ * Map of dependency - nullable objects for optional dependencies.
*/
- private Class[] m_nullableClasses = new Class[0];
+ private Map m_nullableObjects;
/**
* State of the handler.
@@ -65,7 +67,6 @@
/**
* Add a dependency.
- *
* @param dep : the dependency to add
*/
private void addDependency(Dependency dep) {
@@ -83,25 +84,6 @@
}
/**
- * Add a nullable class.
- *
- * @param clazz : the class to add
- */
- private void addNullableClass(Class clazz) {
- for (int i = 0; (m_nullableClasses != null) && (i < m_nullableClasses.length); i++) {
- if (m_nullableClasses[i] == clazz) { return; }
- }
- if (m_nullableClasses.length > 0) {
- Class[] newClass = new Class[m_nullableClasses.length + 1];
- System.arraycopy(m_nullableClasses, 0, newClass, 0, m_nullableClasses.length);
- newClass[m_nullableClasses.length] = clazz;
- m_nullableClasses = newClass;
- } else {
- m_nullableClasses = new Class[] { clazz };
- }
- }
-
- /**
* Get the list of managed dependency.
* @return the dependency list
*/
@@ -234,7 +216,7 @@
*/
public void configure(Element componentMetadata, Dictionary configuration) throws ConfigurationException {
m_dependencies = new Dependency[0];
- m_nullableClasses = new Class[0];
+ m_nullableObjects = new HashMap();
ManipulationMetadata manipulation = new ManipulationMetadata(componentMetadata);
List fl = new ArrayList();
@@ -252,6 +234,7 @@
String filter = deps[i].getAttribute("filter");
String opt = deps[i].getAttribute("optional");
boolean optional = opt != null && opt.equalsIgnoreCase("true");
+
String agg = deps[i].getAttribute("aggregate");
boolean aggregate = agg != null && agg.equalsIgnoreCase("true");
String id = deps[i].getAttribute("id");
@@ -314,7 +297,13 @@
fl.add(manipulation.getField(dep.getField()));
}
}
-
+
+ if (optional) {
+ String defaultImpl = deps[i].getAttribute("default-implementation");
+ if (defaultImpl != null) {
+ m_nullableObjects.put(dep, defaultImpl);
+ }
+ }
}
if (deps.length > 0) {
@@ -326,30 +315,58 @@
/**
* Create a nullable class for the given dependency.
- * @param dep : the dependency
+ * @param dep : the service dependency
*/
- private void createNullableClass(Dependency dep) {
-
- String className = dep.getSpecification() + "Nullable";
- String resource = dep.getSpecification().replace('.', '/') + ".class";
+ private void createNullableObject(Dependency dep) {
+ String spec = dep.getSpecification();
+ String className = spec + "Nullable";
+ String resource = spec.replace('.', '/') + ".class";
URL url = getInstanceManager().getContext().getBundle().getResource(resource);
- byte[] b = NullableObjectWriter.dump(url, dep.getSpecification());
+ byte[] b = NullableObjectWriter.dump(url, spec);
Class c = getInstanceManager().getFactory().defineClass(className, b, null);
- addNullableClass(c);
+ try {
+ Object o = c.newInstance();
+ m_nullableObjects.put(dep, o);
+ } catch (InstantiationException e) {
+ log(Logger.ERROR, "The nullable object for " + dep.getSpecification() + " cannot be instantiate : " + e.getMessage());
+ getInstanceManager().stop();
+ } catch (IllegalAccessException e) {
+ log(Logger.ERROR, "The nullable object for " + dep.getSpecification() + " cannot be instantiate : " + e.getMessage());
+ getInstanceManager().stop();
+ }
}
/**
* Return the nullable class corresponding to the given name.
- * @param name the needed type
- * @return the class correspondig to the name, or null if the class does not exist.
+ * @param dep the dependency which require the nullable class.
+ * @return the class corresponding to the name, or null if the class does not exist.
*/
- protected Class getNullableClass(String name) {
- for (int i = 0; i < m_nullableClasses.length; i++) {
- Class c = m_nullableClasses[i];
- if (c.getName().equals(name)) { return c; }
+ protected Object getNullableObject(Dependency dep) {
+ Object obj = m_nullableObjects.get(dep);
+ if (obj == null) { return null; } // Should not happen
+ if (obj instanceof String) {
+ try {
+ Class c = getInstanceManager().getContext().getBundle().loadClass((String) obj);
+ obj = c.newInstance();
+ m_nullableObjects.put(dep, obj);
+ return obj;
+ } catch (ClassNotFoundException e) {
+ // A default-implementation class cannot be loaded
+ log(Logger.ERROR, "The default-implementation class " + obj + " cannot be loaded : " + e.getMessage());
+ getInstanceManager().stop();
+ return null;
+ } catch (InstantiationException e) {
+ log(Logger.ERROR, "The default-implementation class " + obj + " cannot be instantiated : " + e.getMessage());
+ getInstanceManager().stop();
+ } catch (IllegalAccessException e) {
+ log(Logger.ERROR, "The default-implementation class " + obj + " cannot be instantiated : " + e.getMessage());
+ getInstanceManager().stop();
+ }
+ return null;
+ } else {
+ return obj;
}
- return null;
}
/**
@@ -406,12 +423,11 @@
* @see org.apache.felix.ipojo.Handler#start()
*/
public void start() {
- // Start the dependencies, for optional dependencies create Nullable
- // class
+ // Start the dependencies, for optional dependencies create Nullable class
for (int i = 0; i < m_dependencies.length; i++) {
Dependency dep = m_dependencies[i];
- if (dep.isOptional() && !dep.isAggregate()) {
- createNullableClass(dep);
+ if (dep.isOptional() && !dep.isAggregate() && ! m_nullableObjects.containsKey(dep)) {
+ createNullableObject(dep);
}
dep.start();
}