FELIX-2758 Add post-registration and post-unregistration callbacks to the iPOJO API
FELIX-2759 The iPOJO API do not support contructor injection
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1054958 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java
index 724b466..86366ba 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Dependency.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
@@ -29,17 +29,17 @@
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class Dependency implements HandlerConfiguration {
-
+
/**
* The dynamic binding policy.
*/
public static final int DYNAMIC = org.apache.felix.ipojo.handlers.dependency.Dependency.DYNAMIC_BINDING_POLICY;
-
+
/**
- * The static binding policy.
+ * The static binding policy.
*/
public static final int STATIC = org.apache.felix.ipojo.handlers.dependency.Dependency.STATIC_BINDING_POLICY;
-
+
/**
* The dynamic-priority binding policy.
*/
@@ -49,76 +49,81 @@
* The required specification.
*/
private String m_specification;
-
+
/**
- * The LDAP filter of the dependency.
+ * The LDAP filter of the dependency.
*/
private String m_filter;
-
+
/**
* The field of the implementation class attached to
- * this dependency.
+ * this dependency.
*/
private String m_field;
-
+
/**
- * Is the dependency optional?
+ * The constructor parameter index.
+ */
+ private int m_parameterIndex = -1;
+
+ /**
+ * Is the dependency optional?
*/
private boolean m_optional;
-
+
/**
- * Is the dependency aggregate?
+ * Is the dependency aggregate?
*/
private boolean m_aggregate;
-
+
/**
- * Bind method attached to the dependency.
+ * Bind method attached to the dependency.
*/
private String m_bind;
-
+
/**
- * Unbind method attached to the dependency.
+ * Unbind method attached to the dependency.
*/
private String m_unbind;
-
+
/**
- * Modified method attached to the dependency.
+ * Modified method attached to the dependency.
*/
private String m_modified;
-
+
/**
- * The dependency binding policy.
+ * The dependency binding policy.
*/
private int m_policy;
-
+
/**
* The dependency comparator.
- * (used to compare service providers)
+ * (used to compare service providers)
*/
private String m_comparator;
-
+
/**
- * The dependency default-implementation.
+ * The dependency default-implementation.
*/
private String m_di;
-
+
/**
- * The dependency specific provider.
+ * The dependency specific provider.
*/
private String m_from;
-
+
/**
- * The dependency id.
+ * The dependency id.
*/
private String m_id;
-
+
/**
- * Does the dependency supports nullable?
+ * Does the dependency supports nullable?
*/
private boolean m_nullable = true;
-
+
/**
- * Does the dependency enables proxy.
+ * Does the dependency enables proxy.
*/
private boolean m_proxy = true;
@@ -129,7 +134,7 @@
*/
public Element getElement() {
ensureValidity();
-
+
Element dep = new Element("requires", "");
if (m_specification != null) {
dep.addAttribute(new Attribute("specification", m_specification));
@@ -140,6 +145,10 @@
if (m_field != null) {
dep.addAttribute(new Attribute("field", m_field));
}
+ if (m_parameterIndex != -1) {
+ dep.addAttribute(new Attribute("constructor-parameter",
+ Integer.toString(m_parameterIndex)));
+ }
if (m_bind != null) {
Element cb = new Element("callback", "");
cb.addAttribute(new Attribute("type", "bind"));
@@ -194,7 +203,7 @@
}
return dep;
}
-
+
/**
* Sets the required service specification.
* @param spec the specification
@@ -204,7 +213,7 @@
m_specification = spec;
return this;
}
-
+
/**
* Sets the dependency filter.
* @param filter the LDAP filter
@@ -214,7 +223,7 @@
m_filter = filter;
return this;
}
-
+
/**
* Sets the field attached to the dependency.
* @param field the implementation class field name.
@@ -224,10 +233,20 @@
m_field = field;
return this;
}
-
+
+ /**
+ * Sets the constructor parameter index of the dependency.
+ * @param index the parameter index
+ * @return the current dependency object
+ */
+ public Dependency setConstructorParameter(int index) {
+ m_parameterIndex = index;
+ return this;
+ }
+
/**
* Sets the dependency optionality.
- * @param opt <code>true</code> to set the
+ * @param opt <code>true</code> to set the
* dependency to optional.
* @return the current dependency object.
*/
@@ -235,10 +254,10 @@
m_optional = opt;
return this;
}
-
+
/**
* Sets the dependency cardinality.
- * @param agg <code>true</code> to set the
+ * @param agg <code>true</code> to set the
* dependency to aggregate.
* @return the current dependency object.
*/
@@ -246,7 +265,7 @@
m_aggregate = agg;
return this;
}
-
+
/**
* Sets if the dependency supports nullable objects.
* @param nullable <code>false</code> if the dependency does not
@@ -257,7 +276,7 @@
m_nullable = nullable;
return this;
}
-
+
/**
* Sets if the dependency injects proxies.
* @param proxy <code>false</code> if the dependency does not
@@ -268,7 +287,7 @@
m_proxy = proxy;
return this;
}
-
+
/**
* Sets the dependency bind method.
* @param bind the bind method name
@@ -278,7 +297,7 @@
m_bind = bind;
return this;
}
-
+
/**
* Sets the dependency unbind method.
* @param unbind the unbind method
@@ -288,7 +307,7 @@
m_unbind = unbind;
return this;
}
-
+
/**
* Sets the dependency modified method.
* @param modified the modified method
@@ -298,7 +317,7 @@
m_modified = modified;
return this;
}
-
+
/**
* Sets the dependency binding policy.
* @param policy the binding policy
@@ -308,7 +327,7 @@
m_policy = policy;
return this;
}
-
+
/**
* Sets the dependency comparator.
* @param cmp the comparator class name
@@ -318,7 +337,7 @@
m_comparator = cmp;
return this;
}
-
+
/**
* Sets the dependency default-implementation.
* @param di the default-implementation class name
@@ -328,7 +347,7 @@
m_di = di;
return this;
}
-
+
/**
* Sets the dependency 'from' attribute.
* @param from the name of the service provider.
@@ -338,7 +357,7 @@
m_from = from;
return this;
}
-
+
/**
* Sets the dependency id.
* @param id the dependency id.
@@ -348,14 +367,15 @@
m_id = id;
return this;
}
-
+
/**
* Checks dependency configuration validity.
*/
private void ensureValidity() {
// At least a field or methods.
- if (m_field == null && m_bind == null && m_unbind == null) {
- throw new IllegalStateException("A dependency must have a field or bind/unbind methods");
+ if (m_field == null && m_bind == null && m_unbind == null && m_parameterIndex == -1) {
+ throw new IllegalStateException("A dependency must have a field or bind/unbind methods " +
+ "or a parameter index");
}
// Check binding policy.
if (m_policy != -1) {
@@ -364,12 +384,12 @@
}
}
}
-
+
/**
* Gets the dependency description object attached to
* this dependency.
* @param instance the instance on which searching the dependency
- * @return the dependency description attached to this dependency or
+ * @return the dependency description attached to this dependency or
* <code>null</code> if the dependency cannot be found.
*/
public DependencyDescription getDependencyDescription(ComponentInstance instance) {
@@ -384,9 +404,9 @@
if (deps.length == 1) {
return deps[0];
}
- // Cannot determine the dependency.
+ // Cannot determine the dependency.
return null;
}
-
-
+
+
}
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Property.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Property.java
index 8b1b970..9387941 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Property.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Property.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
@@ -29,37 +29,42 @@
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class Property {
-
+
/**
* The property name.
*/
private String m_name;
-
+
/**
- * The property field.
+ * The property field.
*/
private String m_field;
-
+
/**
- * The property value.
+ * The constructor parameter index.
+ */
+ private int m_parameterIndex = -1;
+
+ /**
+ * The property value.
*/
private String m_value;
-
+
/**
- * The property method.
+ * The property method.
*/
private String m_method;
-
+
/**
- * Is the property mandatory.
+ * Is the property mandatory.
*/
private boolean m_mandatory;
-
+
/**
- * Is the property immutable.
+ * Is the property immutable.
*/
private boolean m_immutable;
-
+
/**
* Sets the property name.
* @param name the property name
@@ -69,7 +74,7 @@
m_name = name;
return this;
}
-
+
/**
* Sets the property field.
* @param name the property field
@@ -79,7 +84,17 @@
m_field = name;
return this;
}
-
+
+ /**
+ * Sets the constructor parameter index of the property.
+ * @param index the parameter index
+ * @return the current property object
+ */
+ public Property setConstructorParameter(int index) {
+ m_parameterIndex = index;
+ return this;
+ }
+
/**
* Sets the property method.
* @param name the property method
@@ -89,7 +104,7 @@
m_method = name;
return this;
}
-
+
/**
* Sets the property value.
* @param name the property value
@@ -99,7 +114,7 @@
m_value = name;
return this;
}
-
+
/**
* Sets if the property is mandatory.
* @param mandatory <code>true</code> if the dependency is mandatory.
@@ -109,7 +124,7 @@
m_mandatory = mandatory;
return this;
}
-
+
/**
* Sets if the property is immutable.
* @param immutable <code>true</code> if the dependency is immutable.
@@ -119,7 +134,7 @@
m_immutable = immutable;
return this;
}
-
+
/**
* Gets the property element.
* @return the property element.
@@ -133,6 +148,10 @@
if (m_method != null) {
element.addAttribute(new Attribute("method", m_method));
}
+ if (m_parameterIndex != -1) {
+ element.addAttribute(new Attribute("constructor-parameter",
+ Integer.toString(m_parameterIndex)));
+ }
if (m_value != null) {
element.addAttribute(new Attribute("value", m_value));
}
@@ -154,32 +173,33 @@
private void ensureValidity() {
// Two cases
// Field or Method
- if (m_field == null && m_method == null) {
- throw new IllegalStateException("A property must have either a field or a method");
+ if (m_field == null && m_method == null && m_parameterIndex == -1) {
+ throw new IllegalStateException("A property must have either a field or a method " +
+ "or a constructor parameter");
}
if (m_immutable && m_value == null) {
throw new IllegalStateException("A immutable service property must have a value");
}
}
-
+
/**
* Gets the property description for the current property.
* @param instance the component instance on which looking for the property.
- * @return the property description associated with the current property
+ * @return the property description associated with the current property
* or <code>null</code> if not found.
*/
public PropertyDescription getPropertyDescription(ComponentInstance instance) {
PrimitiveInstanceDescription desc = (PrimitiveInstanceDescription) instance.getInstanceDescription();
PropertyDescription[] props = desc.getProperties();
-
+
for (int i = 0; i < props.length; i++) {
- if ((m_name != null && m_name.equals(props[i].getName()))
+ if ((m_name != null && m_name.equals(props[i].getName()))
|| (m_field != null && m_field.equals(props[i].getName()))) {
return props[i];
}
}
-
+
return null;
}
-
+
}
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Service.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Service.java
index 43a71bb..99499ef 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Service.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Service.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
@@ -34,57 +34,67 @@
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class Service implements HandlerConfiguration {
-
+
/**
* Creation strategy : singleton (default).
*/
public static final int SINGLETON_STRATEGY = ProvidedService.SINGLETON_STRATEGY;
-
+
/**
* Creation strategy : delegate on the static factory method.
*/
public static final int STATIC_STRATEGY = ProvidedService.STATIC_STRATEGY;
-
+
/**
* Creation strategy : one service object per instance.
*/
public static final int INSTANCE_STRATEGY = ProvidedService.INSTANCE_STRATEGY;
-
+
/**
* Creation strategy : one service object per bundle (OSGi service factory).
*/
public static final int SERVICE_STRATEGY = ProvidedService.SERVICE_STRATEGY;
-
+
/**
- * The provided service specification.
+ * The provided service specification.
*/
- private List m_specifications; // null be default computed.
-
+ private List m_specifications; // null be default computed.
+
/**
- * The provided service strategy.
+ * The provided service strategy.
*/
private int m_strategy = ProvidedService.SINGLETON_STRATEGY;
-
+
/**
- * The provided service custom strategy.
+ * The provided service custom strategy.
*/
private String m_customStrategy;
-
+
/**
- * The service properties.
+ * The service properties.
*/
private List m_properties = new ArrayList();
-
+
/**
* Service controller.
*/
private String m_controller;
-
+
/**
* Service Controller value.
*/
private boolean m_controllerValue;
-
+
+ /**
+ * Post-Registration callback.
+ */
+ private String m_postRegistrationCallback;
+
+ /**
+ * Post-Unregistration callback.
+ */
+ private String m_postUnregistrationCallback;
+
/**
* Gets the provided service element.
* @return the 'provides' element.
@@ -99,21 +109,28 @@
for (int i = 0; i < m_properties.size(); i++) {
element.addElement(((ServiceProperty) m_properties.get(i)).getElement());
}
-
+
if (m_controller != null) {
Element ctrl = new Element("controller", "");
ctrl.addAttribute(new Attribute("field", m_controller));
ctrl.addAttribute(new Attribute("value", String.valueOf(m_controllerValue)));
element.addElement(ctrl);
}
-
- return element;
+
+ if (m_postRegistrationCallback != null) {
+ element.addAttribute(new Attribute("post-registration", m_postRegistrationCallback));
+ }
+ if (m_postUnregistrationCallback != null) {
+ element.addAttribute(new Attribute("post-unregistration", m_postUnregistrationCallback));
+ }
+
+ return element;
}
-
+
/**
* Gets the provided service description associated with the current service.
* @param instance the instance on which looking for the provided service description
- * @return the provided service description or <code>null</code> if not found.
+ * @return the provided service description or <code>null</code> if not found.
*/
public ProvidedServiceDescription getProvidedServiceDescription(ComponentInstance instance) {
PrimitiveInstanceDescription desc = (PrimitiveInstanceDescription) instance.getInstanceDescription();
@@ -121,11 +138,11 @@
if (pss.length == 0) {
return null;
}
-
+
if (pss.length == 1) {
return pss[0];
}
-
+
if (m_specifications == null) {
return null;
} else {
@@ -137,12 +154,12 @@
}
}
}
-
+
return null;
}
-
+
/**
* Checks the validity of the configuration.
*/
@@ -170,7 +187,7 @@
return buffer.toString();
}
}
-
+
/**
* Adds a service property.
* @param ps the service property to add
@@ -180,7 +197,7 @@
m_properties.add(ps);
return this;
}
-
+
/**
* Adds a service property.
* @param key the property key
@@ -211,7 +228,7 @@
m_specifications.add(spec);
return this;
}
-
+
/**
* Sets the provided service specifications.
* @param specs the service specifications
@@ -221,7 +238,7 @@
m_specifications = specs;
return this;
}
-
+
/**
* Sets the creation strategy.
* @param strategy the service strategy.
@@ -231,7 +248,7 @@
m_strategy = strategy;
return this;
}
-
+
/**
* Sets the creation strategy.
* This method allows using a customized
@@ -244,20 +261,40 @@
m_customStrategy = strategy;
return this;
}
-
+
/**
* Sets the service controller.
* @param field the controller field
* @param initialValue the initial value
- * @return the current servic object
+ * @return the current service object
*/
- public Service setServiceController(String field,
+ public Service setServiceController(String field,
boolean initialValue) {
m_controller = field;
m_controllerValue = initialValue;
return this;
}
-
+
+ /**
+ * Sets the post-registration callback.
+ * @param callback the callback name (method name)
+ * @return the current service object
+ */
+ public Service setPostRegistrationCallback(String callback) {
+ m_postRegistrationCallback = callback;
+ return this;
+ }
+
+ /**
+ * Sets the post-unregistration callback.
+ * @param callback the callback name (method name)
+ * @return the current service object
+ */
+ public Service setPostUnregistrationCallback(String callback) {
+ m_postUnregistrationCallback = callback;
+ return this;
+ }
+
/**
* Gets the string-form of the creation strategy.
* @return the creation strategy string form
diff --git a/ipojo/api/src/test/java/org/apache/felix/ipojo/api/DependencyTest.java b/ipojo/api/src/test/java/org/apache/felix/ipojo/api/DependencyTest.java
new file mode 100644
index 0000000..d542f05
--- /dev/null
+++ b/ipojo/api/src/test/java/org/apache/felix/ipojo/api/DependencyTest.java
@@ -0,0 +1,130 @@
+package org.apache.felix.ipojo.api;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Test the {@link Dependency} methods.
+ */
+public class DependencyTest extends TestCase {
+
+ public void testConstructorParameter() {
+ Dependency dep = new Dependency().setConstructorParameter(1);
+ Element elem = dep.getElement();
+ assertEquals("1", elem.getAttribute("constructor-parameter"));
+ }
+
+ public void testField() {
+ Dependency dep = new Dependency().setField("field");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ }
+
+ public void testAggregate() {
+ Dependency dep = new Dependency().setField("field")
+ .setAggregate(true);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("aggregate"));
+ }
+
+ public void testOptional() {
+ Dependency dep = new Dependency().setField("field")
+ .setOptional(true);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("optional"));
+ }
+
+ public void testNullable() {
+ Dependency dep = new Dependency().setField("field").setOptional(true)
+ .setNullable(false);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("optional"));
+ assertEquals("false", elem.getAttribute("nullable"));
+
+ dep = new Dependency().setField("field").setOptional(true)
+ .setNullable(true);
+ elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("optional"));
+ assertEquals(null, elem.getAttribute("nullable")); // Default value.
+ }
+
+ public void testFilter() {
+ Dependency dep = new Dependency().setField("field")
+ .setFilter("(my.prop=1)");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("(my.prop=1)", elem.getAttribute("filter"));
+ }
+
+ public void testFrom() {
+ Dependency dep = new Dependency().setField("field")
+ .setFrom("foo");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("foo", elem.getAttribute("from"));
+ }
+
+ public void testId() {
+ Dependency dep = new Dependency().setField("field")
+ .setId("foo");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("foo", elem.getAttribute("id"));
+ }
+
+ public void testProxy() {
+ Dependency dep = new Dependency().setField("field").setOptional(true)
+ .setProxy(false);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("true", elem.getAttribute("optional"));
+ assertEquals("false", elem.getAttribute("proxy"));
+ }
+
+ public void testComparator() {
+ Dependency dep = new Dependency().setField("field")
+ .setComparator("my.Comparator");
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("my.Comparator", elem.getAttribute("comparator"));
+ }
+
+ public void testBindingPolicy() {
+ Dependency dep = new Dependency().setField("field")
+ .setBindingPolicy(Dependency.DYNAMIC_PRIORITY);
+ Element elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("dynamic-priority", elem.getAttribute("policy"));
+
+ dep = new Dependency().setField("field")
+ .setBindingPolicy(Dependency.STATIC);
+ elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("static", elem.getAttribute("policy"));
+
+ dep = new Dependency().setField("field")
+ .setBindingPolicy(Dependency.DYNAMIC);
+ elem = dep.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("dynamic", elem.getAttribute("policy"));
+ }
+
+}
diff --git a/ipojo/api/src/test/java/org/apache/felix/ipojo/api/PropertyTest.java b/ipojo/api/src/test/java/org/apache/felix/ipojo/api/PropertyTest.java
new file mode 100644
index 0000000..339b562
--- /dev/null
+++ b/ipojo/api/src/test/java/org/apache/felix/ipojo/api/PropertyTest.java
@@ -0,0 +1,41 @@
+package org.apache.felix.ipojo.api;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Test the {@link Property} methods.
+ */
+public class PropertyTest extends TestCase {
+
+ public void testConstructorParameter() {
+ Property prop = new Property().setConstructorParameter(1);
+ Element elem = prop.getElement();
+ assertEquals("1", elem.getAttribute("constructor-parameter"));
+ }
+
+ public void testField() {
+ Property prop = new Property().setField("field");
+ Element elem = prop.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ }
+
+ public void testMandatoryPropertyWithValue() {
+ Property prop = new Property().setField("field")
+ .setMandatory(true)
+ .setName("prop")
+ .setValue("foo")
+ .setImmutable(true);
+ Element elem = prop.getElement();
+ assertEquals(null, elem.getAttribute("constructor-parameter"));
+ assertEquals("field", elem.getAttribute("field"));
+ assertEquals("prop", elem.getAttribute("name"));
+ assertEquals("foo", elem.getAttribute("value"));
+ assertEquals("true", elem.getAttribute("mandatory"));
+ assertEquals("true", elem.getAttribute("immutable"));
+ }
+
+
+}
diff --git a/ipojo/api/src/test/java/org/apache/felix/ipojo/api/ServiceTest.java b/ipojo/api/src/test/java/org/apache/felix/ipojo/api/ServiceTest.java
new file mode 100644
index 0000000..5bac016
--- /dev/null
+++ b/ipojo/api/src/test/java/org/apache/felix/ipojo/api/ServiceTest.java
@@ -0,0 +1,62 @@
+package org.apache.felix.ipojo.api;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the {@link Service} methods.
+ */
+public class ServiceTest extends TestCase {
+
+ public void testServiceController() {
+ Service svc = new Service().setServiceController("m_controller", true);
+
+ Element elem = svc.getElement();
+ assertTrue(elem.getElements("controller").length == 1);
+ Element controller = elem.getElements("controller")[0];
+ assertEquals("m_controller", controller.getAttribute("field"));
+ assertEquals("true", controller.getAttribute("value"));
+
+ svc = new Service().setServiceController("m_controller", false);
+ elem = svc.getElement();
+ assertTrue(elem.getElements("controller").length == 1);
+ controller = elem.getElements("controller")[0];
+ assertEquals("m_controller", controller.getAttribute("field"));
+ assertEquals("false", controller.getAttribute("value"));
+ }
+
+ public void testRegistrationCallbacks() {
+ Service svc = new Service()
+ .setPostRegistrationCallback("registration")
+ .setPostUnregistrationCallback("unregistration");
+
+ Element elem = svc.getElement();
+ assertEquals("registration", elem.getAttribute("post-registration"));
+ assertEquals("unregistration", elem.getAttribute("post-unregistration"));
+ }
+
+ public void testSpecificationWithOneService() {
+ Service svc = new Service()
+ .setSpecification("org.foo.acme.MyService");
+
+ Element elem = svc.getElement();
+ assertEquals("org.foo.acme.MyService", elem.getAttribute("specifications"));
+ }
+
+ public void testSpecificationWithTwoServices() {
+ List spec = new ArrayList();
+ spec.add("org.foo.acme.MyService");
+ spec.add("org.foo.acme.MyService2");
+ Service svc = new Service()
+ .setSpecifications(spec);
+
+ Element elem = svc.getElement();
+ assertEquals("{org.foo.acme.MyService,org.foo.acme.MyService2}", elem.getAttribute("specifications"));
+ }
+
+
+}