Fix issue Felix-853.
iPOJO has a new service object creation strategy allowing creating an object per asking instance. Moreover, new strategies can be created (by implementing CreationStrategy).
The 'factory' attribute of the 'provides' becomes 'strategy' which makes more sense.
Commit the creation strategy test suite.
Improve the efficiency of Properties and Callbacks.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@728056 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java b/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java
index 1b25d05..a2780d7 100644
--- a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java
+++ b/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java
@@ -35,9 +35,13 @@
Class[] specifications() default { };
/**
- * Set the service object creation policy.
- * Two value are possible: SINGLETON or FACTORY. FACTORY means OSGi Service Factory.
+ * Set the service object creation strategy.
+ * Two value are possible: SINGLETON, SERVICE, METHOD, INSTANCE or the strategy class name.
+ * SERVICE means OSGi Service Factory.
+ * METHOD delegates the creation to the factory-method of the component
+ * INSTANCE creates one service object per requiring instance
+ * for other strategies, specify the qualified name of the CreationStrategy class.
* Default : SINGLETON
*/
- String factory() default "SINGLETON";
+ String strategy() default "SINGLETON";
}
diff --git a/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceImporter.java b/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceImporter.java
index 019ebb0..dcc9e4a 100644
--- a/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceImporter.java
+++ b/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceImporter.java
@@ -156,7 +156,7 @@
*/
public ServiceImporter(Class specification, Filter filter, boolean multiple, boolean optional, Comparator cmp, int policy, BundleContext context, String identitity
, ServiceDependencyHandler handler) {
- super(specification, multiple, optional, filter, cmp, policy, context, handler);
+ super(specification, multiple, optional, filter, cmp, policy, context, handler, handler.getCompositeManager());
this.m_handler = handler;
diff --git a/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java b/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java
index 7fab7f2..965ef72 100644
--- a/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java
+++ b/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java
@@ -82,7 +82,7 @@
* @throws ConfigurationException : an attribute cannot be parsed correctly, or is incorrect.
*/
public SvcInstance(ServiceDependencyHandler handler, String spec, Dictionary conf, boolean isAgg, boolean isOpt, Filter filt, Comparator cmp, int policy) throws ConfigurationException {
- super(Factory.class, isAgg, isOpt, filt, cmp, policy, null, handler);
+ super(Factory.class, isAgg, isOpt, filt, cmp, policy, null, handler, handler.getCompositeManager());
m_specification = spec;
diff --git a/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java b/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java
index a16b9c1..906a2d2 100644
--- a/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java
+++ b/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java
@@ -71,7 +71,7 @@
* @param manager : composite manager
*/
public ServiceExporter(Class specification, Filter filter, boolean multiple, boolean optional, Comparator cmp, int policy, ServiceContext from, BundleContext dest, DependencyStateListener listener, CompositeManager manager) {
- super(specification, multiple, optional, filter, cmp, policy, from, listener);
+ super(specification, multiple, optional, filter, cmp, policy, from, listener, manager);
m_destination = dest;
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/IPOJOServiceFactory.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/IPOJOServiceFactory.java
new file mode 100644
index 0000000..a74f22d
--- /dev/null
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/IPOJOServiceFactory.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+
+/**
+ * iPOJO Service Factory is a special service factory handling to get the
+ * instance consuming the service. The mechanism is equivalent to the OSGi Service
+ * Factory.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface IPOJOServiceFactory {
+
+ /**
+ * Gets a service object.
+ * @param instance the instance asking the for the service object.
+ * @return the service object.
+ */
+ Object getService(ComponentInstance instance);
+
+ /**
+ * Un-gets a service object.
+ * @param instance the instance un-getting the service object.
+ * @param svcObject the service object used
+ */
+ void ungetService(ComponentInstance instance, Object svcObject);
+}
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
index 8a47d4a..892b6ea 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
@@ -732,6 +732,16 @@
return instance;
}
+
+ /**
+ * Deletes a POJO object.
+ * @param pojo the pojo to remove from the list of created pojos.
+ */
+ public synchronized void deletePojoObject(Object pojo) {
+ if (m_pojoObjects != null) {
+ m_pojoObjects.remove(pojo);
+ }
+ }
/**
* Gets the first object created by the instance.
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 6161cfb..ba3b829 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
@@ -129,7 +129,7 @@
* @param defaultImplem : default-implementation class
*/
public Dependency(DependencyHandler handler, String field, Class spec, Filter filter, boolean isOptional, boolean isAggregate, boolean nullable, String identity, BundleContext context, int policy, Comparator cmp, String defaultImplem) {
- super(spec, isAggregate, isOptional, filter, cmp, policy, context, handler);
+ super(spec, isAggregate, isOptional, filter, cmp, policy, context, handler, handler.getInstanceManager());
m_handler = handler;
m_field = field;
if (field != null) {
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/controller/ControllerHandler.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/controller/ControllerHandler.java
index d76670d..a97411a 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/controller/ControllerHandler.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/controller/ControllerHandler.java
@@ -82,7 +82,11 @@
* @return : the handler state.
*/
public Object onGet(Object pojo, String field, Object value) {
- return new Boolean(m_state);
+ if (m_state) {
+ return Boolean.TRUE;
+ } else {
+ return Boolean.FALSE;
+ }
}
/**
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/CreationStrategy.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/CreationStrategy.java
new file mode 100644
index 0000000..d0f1ae8
--- /dev/null
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/CreationStrategy.java
@@ -0,0 +1,76 @@
+/*
+ * 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.providedservice;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.InstanceManager;
+import org.osgi.framework.ServiceFactory;
+
+/**
+ * Creation strategy to creation service object.
+ * This class is extended by all service object
+ * creation policy.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class CreationStrategy implements ServiceFactory {
+ /**
+ * Method called when the service is registered.
+ * @param instance the instance registering the service.
+ * @param interfaces the exposed service specification interfaces
+ * @param props the published properties.
+ */
+ public abstract void onPublication(InstanceManager instance, String[] interfaces, Properties props);
+ /**
+ * Method called when the service in unregistered.
+ */
+ public abstract void onUnpublication();
+
+ /**
+ * Checks if the given method object is the
+ * {@link IPOJOServiceFactory#getService(ComponentInstance)}
+ * method.
+ * @param method the method to check
+ * @return <code>true</code> if the method is the getService method
+ * <code>false</code> otherwise.
+ */
+ public static boolean isGetServiceMethod(Method method) {
+ Class[] params = method.getParameterTypes();
+ return method.getName().equals("getService")
+ && params.length == 1
+ && params[0].getName().equals(ComponentInstance.class.getName());
+ }
+
+ /**
+ * Checks if the given method object is the
+ * {@link IPOJOServiceFactory#ungetService(ComponentInstance, Object)}
+ * method.
+ * @param method the method to check
+ * @return <code>true</code> if the method is the ungetService method
+ * <code>false</code> otherwise.
+ */
+ public static boolean isUngetServiceMethod(Method method) {
+ Class[] params = method.getParameterTypes();
+ return method.getName().equals("ungetService")
+ && params.length == 2
+ && params[0].getName().equals(ComponentInstance.class.getName());
+ }
+}
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
index 7a44822..92d80d0 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
@@ -18,16 +18,26 @@
*/
package org.apache.felix.ipojo.handlers.providedservice;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
+import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.IPOJOServiceFactory;
import org.apache.felix.ipojo.InstanceManager;
import org.apache.felix.ipojo.util.Property;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
@@ -63,6 +73,12 @@
* Factory policy : STATIC_FACTORY.
*/
public static final int STATIC_FACTORY = 2;
+
+ /**
+ * Factory policy : INSTANCE.
+ * Creates one service object per instance consuming the service.
+ */
+ public static final int INSTANCE = 3;
/**
* At this time, it is only the java interface full name.
@@ -89,15 +105,21 @@
* Properties Array.
*/
private Property[] m_properties;
+
+ /**
+ * Service Object creation policy.
+ */
+ private CreationStrategy m_strategy;
/**
- * Construct a provided service object.
+ * Creates a provided service object.
*
- * @param handler : the provided service handler.
- * @param specification : specifications provided by this provided service
- * @param factoryPolicy : service providing policy
+ * @param handler the the provided service handler.
+ * @param specification the specifications provided by this provided service
+ * @param factoryPolicy the service providing policy
+ * @param creationStrategyClass the customized service object creation strategy.
*/
- public ProvidedService(ProvidedServiceHandler handler, String[] specification, int factoryPolicy) {
+ public ProvidedService(ProvidedServiceHandler handler, String[] specification, int factoryPolicy, Class creationStrategyClass) {
m_handler = handler;
m_serviceSpecification = specification;
@@ -110,6 +132,53 @@
} catch (ConfigurationException e) {
m_handler.error("An exception occurs when adding instance.name and factory.name property : " + e.getMessage());
}
+ if (creationStrategyClass != null) {
+ try {
+ m_strategy = (CreationStrategy) creationStrategyClass.newInstance();
+ } catch (IllegalAccessException e) {
+ m_handler.error("["
+ + m_handler.getInstanceManager().getInstanceName()
+ + "] The customized service object creation policy "
+ + "(" + creationStrategyClass.getName() + ") is not accessible: "
+ + e.getMessage());
+ getInstanceManager().stop();
+ return;
+ } catch (InstantiationException e) {
+ m_handler.error("["
+ + m_handler.getInstanceManager().getInstanceName()
+ + "] The customized service object creation policy "
+ + "(" + creationStrategyClass.getName() + ") cannot be instantiated: "
+ + e.getMessage());
+ getInstanceManager().stop();
+ return;
+ }
+ } else {
+ switch (m_factoryPolicy) {
+ case SINGLETON_FACTORY:
+ m_strategy = new SingletonStrategy();
+ break;
+ case SERVICE_FACTORY:
+ case STATIC_FACTORY:
+ // In this case, we need to try to create a new pojo object,
+ // the factory method will handle the creation.
+ m_strategy = new FactoryStrategy();
+ break;
+ case INSTANCE:
+ m_strategy = new PerInstanceStrategy();
+ break;
+ // Other policies:
+ // Thread : one service object per asking thread
+ // Consumer : one service object per consumer
+ default:
+ List specs = Arrays.asList(m_serviceSpecification);
+ m_handler.error("["
+ + m_handler.getInstanceManager().getInstanceName()
+ + "] Unknown creation policy for " + specs + " : "
+ + m_factoryPolicy);
+ getInstanceManager().stop();
+ break;
+ }
+ }
}
/**
@@ -193,28 +262,7 @@
* @return : a new service object or a already created service object (in the case of singleton)
*/
public Object getService(Bundle bundle, ServiceRegistration registration) {
- Object svc = null;
- switch (m_factoryPolicy) {
- case SINGLETON_FACTORY:
- svc = m_handler.getInstanceManager().getPojoObject();
- break;
- case SERVICE_FACTORY:
- svc = m_handler.getInstanceManager().createPojoObject();
- break;
- case STATIC_FACTORY:
- // In this case, we need to try to create a new pojo object, the factory method will handle the creation.
- svc = m_handler.getInstanceManager().createPojoObject();
- break;
- // Other policies:
- // Thread : one service object per asking thread
- // Consumer : one service object per consumer TODO how to shortcut the service factory
- default:
- List specs = Arrays.asList(m_serviceSpecification);
- m_handler.error("[" + m_handler.getInstanceManager().getClassName() + "] Unknown factory policy for " + specs + " : " + m_factoryPolicy);
- getInstanceManager().stop();
- break;
- }
- return svc;
+ return m_strategy.getService(bundle, registration);
}
/**
@@ -227,30 +275,34 @@
* @param service : service object
*/
public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
- // Nothing to do
+ m_strategy.ungetService(bundle, registration, service);
}
/**
- * Register the service. The service object must be able to serve this
- * service. To avoid cycle in Check Context, the registered service is set to
- * registered before the real registration.
+ * Registers the service. The service object must be able to serve this
+ * service.
+ * This method also notifies the creation strategy of the publication.
*/
- protected synchronized void registerService() {
+ protected synchronized void registerService() {
if (m_serviceRegistration == null) {
// Build the service properties list
Properties serviceProperties = getServiceProperties();
+ m_strategy.onPublication(getInstanceManager(), m_serviceSpecification, serviceProperties);
m_serviceRegistration = m_handler.getInstanceManager().getContext().registerService(m_serviceSpecification, this, serviceProperties);
}
}
/**
- * Unregister the service.
+ * Unregisters the service.
*/
protected synchronized void unregisterService() {
if (m_serviceRegistration != null) {
m_serviceRegistration.unregister();
m_serviceRegistration = null;
}
+
+ m_strategy.onUnpublication();
+
}
/**
@@ -353,5 +405,246 @@
public ServiceRegistration getServiceRegistration() {
return m_serviceRegistration;
}
+
+ /**
+ * Singleton creation strategy.
+ * This strategy just creates one service object and
+ * returns always the same.
+ */
+ private class SingletonStrategy extends CreationStrategy {
+
+ /**
+ * The service is going to be registered.
+ * @param instance the instance manager
+ * @param interfaces the published interfaces
+ * @param props the properties
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onPublication(InstanceManager, java.lang.String[], java.util.Properties)
+ */
+ public void onPublication(InstanceManager instance, String[] interfaces,
+ Properties props) { }
+
+ /**
+ * The service was unpublished.
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onUnpublication()
+ */
+ public void onUnpublication() { }
+
+ /**
+ * A service object is required.
+ * @param arg0 the bundle requiring the service object.
+ * @param arg1 the service registration.
+ * @return the first pojo object.
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(Bundle arg0, ServiceRegistration arg1) {
+ return m_handler.getInstanceManager().getPojoObject();
+ }
+
+ /**
+ * A service object is released.
+ * @param arg0 the bundle
+ * @param arg1 the service registration
+ * @param arg2 the get service object.
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+ */
+ public void ungetService(Bundle arg0, ServiceRegistration arg1,
+ Object arg2) {
+ }
+
+ }
+
+ /**
+ * Service object creation policy following the OSGi Service Factory
+ * policy {@link ServiceFactory}.
+ */
+ private class FactoryStrategy extends CreationStrategy {
+
+ /**
+ * The service is going to be registered.
+ * @param instance the instance manager
+ * @param interfaces the published interfaces
+ * @param props the properties
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onPublication(InstanceManager, java.lang.String[], java.util.Properties)
+ */
+ public void onPublication(InstanceManager instance, String[] interfaces,
+ Properties props) { }
+
+ /**
+ * The service is unpublished.
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onUnpublication()
+ */
+ public void onUnpublication() { }
+
+ /**
+ * OSGi Service Factory getService method.
+ * Returns a new service object per asking bundle.
+ * This object is then cached by the framework.
+ * @param arg0 the bundle requiring the service
+ * @param arg1 the service registration
+ * @return the service object for the asking bundle
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(Bundle arg0, ServiceRegistration arg1) {
+ return m_handler.getInstanceManager().createPojoObject();
+ }
+
+ /**
+ * OSGi Service Factory unget method.
+ * Deletes the created object for the asking bundle.
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @param arg2 the created service object returned for this bundle
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+ */
+ public void ungetService(Bundle arg0, ServiceRegistration arg1,
+ Object arg2) {
+ m_handler.getInstanceManager().deletePojoObject(arg2);
+ }
+ }
+
+
+ /**
+ * Service object creation policy creating a service object per asking iPOJO component
+ * instance. This creation policy follows the iPOJO Service Factory interaction pattern
+ * and does no support 'direct' invocation.
+ */
+ private class PerInstanceStrategy extends CreationStrategy implements IPOJOServiceFactory, InvocationHandler {
+ /**
+ * Map [ComponentInstance->ServiceObject] storing created service objects.
+ */
+ private Map/*<ComponentInstance, ServiceObject>*/ m_instances = new HashMap();
+
+ /**
+ * A method is invoked on the proxy object.
+ * If the method is the {@link IPOJOServiceFactory#getService(ComponentInstance)}
+ * method, this method creates a service object if no already created for the asking
+ * component instance.
+ * If the method is {@link IPOJOServiceFactory#ungetService(ComponentInstance, Object)}
+ * the service object is unget (i.e. removed from the map and deleted).
+ * In all other cases, a {@link UnsupportedOperationException} is thrown as this policy
+ * requires to use the {@link IPOJOServiceFactory} interaction pattern.
+ * @param arg0 the proxy object
+ * @param arg1 the called method
+ * @param arg2 the arguments
+ * @return the service object attached to the asking instance for 'get',
+ * <code>null</code> for 'unget',
+ * a {@link UnsupportedOperationException} for all other methods.
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ public Object invoke(Object arg0, Method arg1, Object[] arg2) {
+ if (isGetServiceMethod(arg1)) {
+ return getService((ComponentInstance) arg2[0]);
+ }
+
+ if (isUngetServiceMethod(arg1)) {
+ ungetService((ComponentInstance) arg2[0], arg2[1]);
+ return null;
+ }
+
+ throw new UnsupportedOperationException("This service requires an advanced creation policy. "
+ + "Before calling the service, call the getService(ComponentInstance) method to get "
+ + "the service object. ");
+ }
+
+ /**
+ * A service object is required.
+ * This policy returns a service object per asking instance.
+ * @param instance the instance requiring the service object
+ * @return the service object for this instance
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#getService(org.apache.felix.ipojo.ComponentInstance)
+ */
+ public Object getService(ComponentInstance instance) {
+ Object obj = m_instances.get(instance);
+ if (obj == null) {
+ obj = m_handler.getInstanceManager().createPojoObject();
+ m_instances.put(instance, obj);
+ }
+ return obj;
+ }
+
+ /**
+ * A service object is unget.
+ * The service object is removed from the map and deleted.
+ * @param instance the instance releasing the service
+ * @param svcObject the service object
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#ungetService(org.apache.felix.ipojo.ComponentInstance, java.lang.Object)
+ */
+ public void ungetService(ComponentInstance instance, Object svcObject) {
+ Object pojo = m_instances.remove(instance);
+ m_handler.getInstanceManager().deletePojoObject(pojo);
+ }
+
+ /**
+ * The service is going to be registered.
+ * @param instance the instance manager
+ * @param interfaces the published interfaces
+ * @param props the properties
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onPublication(InstanceManager, java.lang.String[], java.util.Properties)
+ */
+ public void onPublication(InstanceManager instance, String[] interfaces,
+ Properties props) { }
+
+ /**
+ * The service is going to be unregistered.
+ * The instance map is cleared. Created object are disposed.
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onUnpublication()
+ */
+ public void onUnpublication() {
+ Collection col = m_instances.values();
+ Iterator it = col.iterator();
+ while (it.hasNext()) {
+ m_handler.getInstanceManager().deletePojoObject(it.next());
+ }
+ m_instances.clear();
+ }
+
+ /**
+ * OSGi Service Factory getService method.
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @return a proxy implementing the {@link IPOJOServiceFactory}
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(Bundle arg0, ServiceRegistration arg1) {
+ Object proxy = Proxy.newProxyInstance(getInstanceManager().getClazz().getClassLoader(),
+ getSpecificationsWithIPOJOServiceFactory(m_serviceSpecification, m_handler.getInstanceManager().getContext()), this);
+ return proxy;
+ }
+
+ /**
+ * OSGi Service factory unget method.
+ * Does nothing.
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @param arg2 the service object created for this bundle.
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+ */
+ public void ungetService(Bundle arg0, ServiceRegistration arg1,
+ Object arg2) { }
+
+ /**
+ * Utility method returning the class array of provided service
+ * specification and the {@link IPOJOServiceFactory} interface.
+ * @param specs the published service interface
+ * @param bc the bundle context, used to load classes
+ * @return the class array containing provided service specification and
+ * the {@link IPOJOServiceFactory} class.
+ */
+ private Class[] getSpecificationsWithIPOJOServiceFactory(String[] specs, BundleContext bc) {
+ Class[] classes = new Class[specs.length + 1];
+ int i = 0;
+ for (i = 0; i < specs.length; i++) {
+ try {
+ classes[i] = bc.getBundle().loadClass(specs[i]);
+ } catch (ClassNotFoundException e) {
+ // Should not happen.
+ }
+ }
+ classes[i] = IPOJOServiceFactory.class;
+ return classes;
+ }
+
+
+ }
}
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java
index 3844cba..93d19bd 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java
@@ -102,16 +102,35 @@
// Get the factory policy
int factory = ProvidedService.SINGLETON_FACTORY;
- String fact = providedServices[i].getAttribute("factory");
- if (fact != null && "service".equalsIgnoreCase(fact)) {
- factory = ProvidedService.SERVICE_FACTORY;
+ Class custom = null;
+ String strategy = providedServices[i].getAttribute("strategy");
+ if (strategy == null) {
+ strategy = providedServices[i].getAttribute("factory");
}
- if (fact != null && "method".equalsIgnoreCase(fact)) {
- factory = ProvidedService.STATIC_FACTORY;
- }
+ if (strategy != null) {
+ if ("service".equalsIgnoreCase(strategy)) {
+ factory = ProvidedService.SERVICE_FACTORY;
+ } else if ("method".equalsIgnoreCase(strategy)) {
+ factory = ProvidedService.STATIC_FACTORY;
+ } else if ("instance".equalsIgnoreCase(strategy)) {
+ factory = ProvidedService.INSTANCE;
+ } else {
+ // Customized policy
+ try {
+ custom = getInstanceManager().getContext().getBundle().loadClass(strategy);
+ if (! CreationStrategy.class.isAssignableFrom(custom)) {
+ throw new ConfigurationException("The custom creation policy class " + custom.getName() + " does not implement " + CreationStrategy.class.getName());
+ }
+ } catch (ClassNotFoundException e) {
+ throw new ConfigurationException("The custom creation policy class " + strategy + " cannot be loaded " + e.getMessage());
+ }
+
+ }
+ }
+
// Then create the provided service
- ProvidedService svc = new ProvidedService(this, serviceSpecifications, factory);
+ ProvidedService svc = new ProvidedService(this, serviceSpecifications, factory, custom);
Element[] props = providedServices[i].getElements("Property");
if (props != null) {
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Callback.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Callback.java
index 5cede5a..6b83eea 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Callback.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Callback.java
@@ -228,8 +228,7 @@
// - if instances already exists : call on each instances
// - if no instance exists : create an instance
if (m_manager.getPojoObjects() == null) {
- Object r = m_methodObj.invoke(m_manager.getPojoObject(), arg);
- return r;
+ return m_methodObj.invoke(m_manager.getPojoObject(), arg);
} else {
Object newObject = null;
for (int i = 0; i < m_manager.getPojoObjects().length; i++) {
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
index 835a291..458d7af 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
@@ -21,9 +21,15 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.IPOJOServiceFactory;
import org.apache.felix.ipojo.context.ServiceReferenceImpl;
import org.apache.felix.ipojo.metadata.Element;
import org.osgi.framework.BundleContext;
@@ -142,6 +148,18 @@
* to the filter and the {@link DependencyModel#match(ServiceReference)} method.
*/
private final List m_matchingRefs = new ArrayList();
+
+ /**
+ * The instance requiring the service.
+ */
+ private final ComponentInstance m_instance;
+
+ /**
+ * Map {@link ServiceReference} -> Service Object.
+ * This map stores service object, and so is able to handle
+ * iPOJO custom policies.
+ */
+ private Map/*<ServiceReference, Object>*/ m_serviceObjects = new HashMap();
/**
* Creates a DependencyModel.
@@ -156,10 +174,11 @@
* @param policy the binding policy
* @param context the bundle context (or service context)
* @param listener the dependency lifecycle listener to notify from dependency
+ * @param ci instance managing the dependency
* state changes.
*/
public DependencyModel(Class specification, boolean aggregate, boolean optional, Filter filter, Comparator comparator, int policy,
- BundleContext context, DependencyStateListener listener) {
+ BundleContext context, DependencyStateListener listener, ComponentInstance ci) {
m_specification = specification;
m_aggregate = aggregate;
m_optional = optional;
@@ -173,6 +192,7 @@
}
m_state = UNRESOLVED;
m_listener = listener;
+ m_instance = ci;
}
/**
@@ -196,8 +216,30 @@
m_tracker.close();
m_tracker = null;
}
+ ungetAllServices();
m_state = UNRESOLVED;
}
+
+ /**
+ * Ungets all 'get' service references.
+ * This also clears the service object map.
+ */
+ private void ungetAllServices() {
+ Set entries = m_serviceObjects.entrySet();
+ Iterator it = entries.iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ ServiceReference ref = (ServiceReference) entry.getKey();
+ Object svc = entry.getValue();
+ if (m_tracker != null) {
+ m_tracker.ungetService(ref);
+ }
+ if (svc instanceof IPOJOServiceFactory) {
+ ((IPOJOServiceFactory) svc).ungetService(m_instance, svc);
+ }
+ }
+ m_serviceObjects.clear();
+ }
/**
* Is the reference set frozen (cannot change anymore)?
@@ -378,6 +420,9 @@
* @param obj the service object if the service was get
*/
private void manageDeparture(ServiceReference ref, Object obj) {
+ // Unget the service reference
+ ungetService(ref);
+
// If we already get this service and the binding policy is static, the dependency becomes broken
if (isFrozen() && obj != null) {
if (m_state != BROKEN) {
@@ -833,15 +878,28 @@
* @return the service object attached to the given reference
*/
public Object getService(ServiceReference ref) {
- return m_tracker.getService(ref);
+ Object svc = m_tracker.getService(ref);
+ if (svc instanceof IPOJOServiceFactory) {
+ Object obj = ((IPOJOServiceFactory) svc).getService(m_instance);
+ m_serviceObjects.put(ref, obj);
+ return obj;
+ } else {
+ m_serviceObjects.put(ref, svc);
+ return svc;
+ }
}
-
+
/**
* Ungets a used service reference.
* @param ref the reference to unget.
*/
public void ungetService(ServiceReference ref) {
+ Object svc = m_tracker.getService(ref); // Get the service object
m_tracker.ungetService(ref);
+ Object obj = m_serviceObjects.remove(ref); // Remove the service object
+ if (svc instanceof IPOJOServiceFactory) {
+ ((IPOJOServiceFactory) svc).ungetService(m_instance, obj);
+ }
}
/**
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java
index 79195b2..6be8314 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java
@@ -183,31 +183,31 @@
private static Class computeArrayType(String type, BundleContext context) throws ConfigurationException {
String internalType = type.substring(0, type.length() - 2);
if ("string".equals(internalType) || "String".equals(internalType)) {
- return new String[0].getClass();
+ return String[].class;
}
if ("boolean".equals(internalType)) {
- return new boolean[0].getClass();
+ return boolean[].class;
}
if ("byte".equals(internalType)) {
- return new byte[0].getClass();
+ return byte[].class;
}
if ("short".equals(internalType)) {
- return new short[0].getClass();
+ return short[].class;
}
if ("int".equals(internalType)) {
- return new int[0].getClass();
+ return int[].class;
}
if ("long".equals(internalType)) {
- return new long[0].getClass();
+ return long[].class;
}
if ("float".equals(internalType)) {
- return new float[0].getClass();
+ return float[].class;
}
if ("double".equals(internalType)) {
- return new double[0].getClass();
+ return double[].class;
}
if ("char".equals(internalType)) {
- return new char[0].getClass();
+ return char[].class;
}
// Complex array type.
@@ -271,7 +271,7 @@
* @return the object to inject when the property has no value.
*/
private static Object getNoValue(Class type) {
- if (Boolean.TYPE.equals(type)) { return new Boolean(false); }
+ if (Boolean.TYPE.equals(type)) { return Boolean.FALSE; }
if (Byte.TYPE.equals(type)) { return new Byte((byte) 0); }
if (Short.TYPE.equals(type)) { return new Short((short) 0); }
if (Integer.TYPE.equals(type)) { return new Integer(0); }
@@ -344,7 +344,9 @@
* @throws ConfigurationException if the object cannot be created.
*/
public static Object create(Class type, String strValue) throws ConfigurationException {
- if (Boolean.TYPE.equals(type)) { return new Boolean(strValue); }
+ if (Boolean.TYPE.equals(type)) {
+ return Boolean.valueOf(strValue);
+ }
if (Byte.TYPE.equals(type)) { return new Byte(strValue); }
if (Short.TYPE.equals(type)) { return new Short(strValue); }
if (Integer.TYPE.equals(type)) { return new Integer(strValue); }
@@ -390,7 +392,7 @@
if (Boolean.TYPE.equals(interntype)) {
boolean[] bool = new boolean[values.length];
for (int i = 0; i < values.length; i++) {
- bool[i] = new Boolean(values[i]).booleanValue();
+ bool[i] = Boolean.valueOf(values[i]).booleanValue();
}
return bool;
}
diff --git a/ipojo/core/src/main/resources/core.xsd b/ipojo/core/src/main/resources/core.xsd
index 4584e26..9bb7014 100644
--- a/ipojo/core/src/main/resources/core.xsd
+++ b/ipojo/core/src/main/resources/core.xsd
@@ -309,7 +309,7 @@
</xs:attribute>
</xs:complexType>
<xs:element name="provides" type="ProvidesType" id="provides"></xs:element>
- <xs:complexType name="ProvidesType">
+ <xs:complexType name="ProvidesType">
<xs:annotation>
<xs:documentation>Provided service(s) description.</xs:documentation>
</xs:annotation>
@@ -323,9 +323,14 @@
<xs:annotation>
<xs:documentation>The list of interfaces of the service to expose. By default, all interfaces implemented by the component implementation class are published.</xs:documentation>
</xs:annotation></xs:attribute>
- <xs:attribute name="factory" type="xs:string" use="optional">
+ <xs:attribute name="factory" type="xs:string" use="prohibited">
<xs:annotation>
- <xs:documentation>POJO factory policy. By default, the POJO object is created once (singleton). If the factory is set to "SERVICE", the creation policy follows the OSGi service factory policy (one object object per asking bundle).</xs:documentation>
+ <xs:documentation>Use 'strategy' instead of 'factory'</xs:documentation>
+ </xs:annotation></xs:attribute>
+ <xs:attribute name="strategy" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>POJO creation strategy. By default, the POJO object is created once (singleton). If the factory is set to "SERVICE", the creation policy follows the OSGi service factory policy (one object object per asking bundle).
+ INSTANCE allows creating one different POJO object per asking instance. Finally, a custom strategy can be used by specifying the qualified name of the class extending CreationPolicy</xs:documentation>
</xs:annotation></xs:attribute>
</xs:complexType>
<xs:complexType name="PropertyType">
diff --git a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
index 916cfc8..a5bacfb 100644
--- a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
+++ b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
@@ -83,7 +83,7 @@
BundleContext context, long timeout, int policy,
String defaultImpl, TemporalHandler handler) {
super(spec, agg, true, filter, null,
- DependencyModel.DYNAMIC_BINDING_POLICY, context, handler);
+ DependencyModel.DYNAMIC_BINDING_POLICY, context, handler, handler.getInstanceManager());
m_di = defaultImpl;
m_policy = policy;
m_timeout = timeout;
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
index 7874b9f..49866d0 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
@@ -206,9 +206,12 @@
* @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
*/
public void visit(String arg0, Object arg1) {
- if (arg0.equals("factory")) {
+ if (arg0.equals("factory")) { // Should be deprecated
m_prov.addAttribute(new Attribute("factory", arg1.toString()));
}
+ if (arg0.equals("strategy")) {
+ m_prov.addAttribute(new Attribute("strategy", arg1.toString()));
+ }
}
/**
diff --git a/ipojo/manipulator/src/main/resources/core.xsd b/ipojo/manipulator/src/main/resources/core.xsd
index 4584e26..d98fca3 100644
--- a/ipojo/manipulator/src/main/resources/core.xsd
+++ b/ipojo/manipulator/src/main/resources/core.xsd
@@ -323,9 +323,14 @@
<xs:annotation>
<xs:documentation>The list of interfaces of the service to expose. By default, all interfaces implemented by the component implementation class are published.</xs:documentation>
</xs:annotation></xs:attribute>
- <xs:attribute name="factory" type="xs:string" use="optional">
+ <xs:attribute name="factory" type="xs:string" use="prohibited">
<xs:annotation>
- <xs:documentation>POJO factory policy. By default, the POJO object is created once (singleton). If the factory is set to "SERVICE", the creation policy follows the OSGi service factory policy (one object object per asking bundle).</xs:documentation>
+ <xs:documentation>Use 'strategy' instead of 'factory'</xs:documentation>
+ </xs:annotation></xs:attribute>
+ <xs:attribute name="strategy" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>POJO creation strategy. By default, the POJO object is created once (singleton). If the factory is set to "SERVICE", the creation policy follows the OSGi service factory policy (one object object per asking bundle).
+ INSTANCE allows creating one different POJO object per asking instance. Finally, a custom strategy can be used by specifying the qualified name of the class extending CreationPolicy</xs:documentation>
</xs:annotation></xs:attribute>
</xs:complexType>
<xs:complexType name="PropertyType">
diff --git a/ipojo/tests/composite/service-instance/src/main/java/org/apache/felix/ipojo/test/composite/instance/InstanceScopeTest.java b/ipojo/tests/composite/service-instance/src/main/java/org/apache/felix/ipojo/test/composite/instance/InstanceScopeTest.java
index 6634062..3aae2e5 100644
--- a/ipojo/tests/composite/service-instance/src/main/java/org/apache/felix/ipojo/test/composite/instance/InstanceScopeTest.java
+++ b/ipojo/tests/composite/service-instance/src/main/java/org/apache/felix/ipojo/test/composite/instance/InstanceScopeTest.java
@@ -69,6 +69,7 @@
//System.out.println(instance2.getInstanceDescription().getDescription());
assertEquals("Check invalidity", ComponentInstance.INVALID, instance2.getState());
+ instance2.dispose();
}
diff --git a/ipojo/tests/core/lifecycle-controller/src/main/java/org/apache/felix/ipojo/test/scenarios/lfc/ImmediateLifeCycleControllerTest.java b/ipojo/tests/core/lifecycle-controller/src/main/java/org/apache/felix/ipojo/test/scenarios/lfc/ImmediateLifeCycleControllerTest.java
index 9cd60f7..4b86fb0 100644
--- a/ipojo/tests/core/lifecycle-controller/src/main/java/org/apache/felix/ipojo/test/scenarios/lfc/ImmediateLifeCycleControllerTest.java
+++ b/ipojo/tests/core/lifecycle-controller/src/main/java/org/apache/felix/ipojo/test/scenarios/lfc/ImmediateLifeCycleControllerTest.java
@@ -39,11 +39,11 @@
public void testOne() {
Properties props = new Properties();
props.put("conf", "foo");
- props.put("instance.name","under");
+ props.put("instance.name","under1");
under = Utils.getComponentInstance(getContext(), "LFC-Test-Immediate", props);
// The conf is correct, the PS must be provided
- ServiceReference ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ServiceReference ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under1");
assertNotNull("Check service availability -1", ref);
CheckService cs = (CheckService) getContext().getService(ref);
assertTrue("Check state 1", cs.check());
@@ -59,7 +59,7 @@
}
// The instance should now be invalid
- ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under1");
assertNull("Check service availability -2", ref);
// Reconfigure the instance with a valid configuration
@@ -70,7 +70,7 @@
fail("The reconfiguration is not unacceptable and seems unacceptable (2) : " + props);
}
- ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under1");
assertNotNull("Check service availability -3", ref);
cs = (CheckService) getContext().getService(ref);
assertTrue("Check state 2", cs.check());
@@ -83,13 +83,13 @@
public void testTwo() {
Properties props = new Properties();
props.put("conf", "bar");
- props.put("instance.name","under");
+ props.put("instance.name","under2");
under = Utils.getComponentInstance(getContext(), "LFC-Test-Immediate", props);
assertEquals("check under state", under.getState(), ComponentInstance.INVALID);
// The conf is incorrect, the PS must not be provided
- ServiceReference ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ServiceReference ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under2");
assertNull("Check service availability -1", ref);
// Reconfigure the instance with a correct configuration
@@ -100,7 +100,7 @@
fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
}
- ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under2");
assertNotNull("Check service availability -2", ref);
CheckService cs = (CheckService) getContext().getService(ref);
assertTrue("Check state ", cs.check());
diff --git a/ipojo/tests/core/lifecycle-controller/src/main/java/org/apache/felix/ipojo/test/scenarios/lfc/LifeCycleControllerTest.java b/ipojo/tests/core/lifecycle-controller/src/main/java/org/apache/felix/ipojo/test/scenarios/lfc/LifeCycleControllerTest.java
index 68f8600..bec71e1 100644
--- a/ipojo/tests/core/lifecycle-controller/src/main/java/org/apache/felix/ipojo/test/scenarios/lfc/LifeCycleControllerTest.java
+++ b/ipojo/tests/core/lifecycle-controller/src/main/java/org/apache/felix/ipojo/test/scenarios/lfc/LifeCycleControllerTest.java
@@ -44,11 +44,11 @@
public void testOne() {
Properties props = new Properties();
props.put("conf", "foo");
- props.put("instance.name","under");
+ props.put("instance.name","under1");
under = Utils.getComponentInstance(getContext(), "LFC-Test", props);
// The conf is correct, the PS must be provided
- ServiceReference ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ServiceReference ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under1");
assertNotNull("Check service availability -1", ref);
CheckService cs = (CheckService) getContext().getService(ref);
assertTrue("Check state 1", cs.check());
@@ -64,7 +64,7 @@
}
// The instance should now be invalid
- ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under1");
assertNull("Check service availability -2", ref);
// Reconfigure the instance with a valid configuration
@@ -75,7 +75,7 @@
fail("The reconfiguration is not unacceptable and seems unacceptable (2) : " + props);
}
- ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under1");
assertNotNull("Check service availability -3", ref);
cs = (CheckService) getContext().getService(ref);
assertTrue("Check state 2", cs.check());
@@ -92,11 +92,11 @@
public void notestTwo() {
Properties props = new Properties();
props.put("conf", "bar");
- props.put("instance.name","under");
+ props.put("instance.name","under2");
under = Utils.getComponentInstance(getContext(), "LFC-Test", props);
// The conf is incorrect, but the test can appears only when the object is created : the PS must be provided
- ServiceReference ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ServiceReference ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under2");
assertNotNull("Check service availability -1", ref);
System.out.println("CS received : " + getContext().getService(ref));
@@ -110,7 +110,7 @@
}
// As soon as the instance is created, the service has to disappear :
- ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under2");
assertNull("Check service availability -2", ref);
// Reconfigure the instance with a correct configuration
@@ -121,7 +121,7 @@
fail("The reconfiguration is not unacceptable and seems unacceptable : " + props);
}
- ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under");
+ ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), "under2");
assertNotNull("Check service availability -3", ref);
cs = (CheckService) getContext().getService(ref);
assertTrue("Check state ", cs.check());
diff --git a/ipojo/tests/core/service-providing-strategies/pom.xml b/ipojo/tests/core/service-providing-strategies/pom.xml
new file mode 100755
index 0000000..80be307
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/pom.xml
@@ -0,0 +1,104 @@
+<!--
+ 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.
+-->
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>bundle</packaging>
+ <name>iPOJO Service Providing Strategy Test Suite</name>
+ <artifactId>tests.core.ps.strategy</artifactId>
+ <groupId>ipojo.tests</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>1.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <artifactId>tests.core.ps</artifactId>
+ <groupId>ipojo.tests</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>1.4.3</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>
+ ${pom.artifactId}
+ </Bundle-SymbolicName>
+ <Private-Package>
+ org.apache.felix.ipojo.test.scenarios.component.strategies, org.apache.felix.ipojo.test.scenarios.ps.strategies
+ </Private-Package>
+ <Test-Suite>
+ org.apache.felix.ipojo.test.scenarios.ps.strategies.ProvidedServiceStrategyTestSuite
+ </Test-Suite>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-ipojo-plugin</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>ipojo-bundle</goal>
+ </goals>
+ <configuration>
+ <ignoreAnnotations>true</ignoreAnnotations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.4</source>
+ <target>1.4</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/BarConsumer.java b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/BarConsumer.java
new file mode 100644
index 0000000..c7cf2d2
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/BarConsumer.java
@@ -0,0 +1,23 @@
+package org.apache.felix.ipojo.test.scenarios.component.strategies;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.test.scenarios.ps.service.BarService;
+import org.apache.felix.ipojo.test.scenarios.ps.service.CheckService;
+
+public class BarConsumer implements CheckService {
+
+ private BarService bs;
+
+
+ public boolean check() {
+ return bs.bar();
+ }
+
+ public Properties getProps() {
+ Properties props = bs.getProps();
+ props.put("object", bs);
+ return props;
+ }
+
+}
diff --git a/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/Consumer.java b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/Consumer.java
new file mode 100644
index 0000000..1479eb1
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/Consumer.java
@@ -0,0 +1,23 @@
+package org.apache.felix.ipojo.test.scenarios.component.strategies;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.test.scenarios.ps.service.CheckService;
+import org.apache.felix.ipojo.test.scenarios.ps.service.FooService;
+
+public class Consumer implements CheckService {
+
+ private FooService fs;
+
+
+ public boolean check() {
+ return fs.foo();
+ }
+
+ public Properties getProps() {
+ Properties props = fs.fooProps();
+ props.put("object", fs);
+ return props;
+ }
+
+}
diff --git a/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/DummyCreationStrategy.java b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/DummyCreationStrategy.java
new file mode 100644
index 0000000..d0b7660
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/DummyCreationStrategy.java
@@ -0,0 +1,168 @@
+package org.apache.felix.ipojo.test.scenarios.component.strategies;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.IPOJOServiceFactory;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.handlers.providedservice.CreationStrategy;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class DummyCreationStrategy extends CreationStrategy implements InvocationHandler {
+
+ /**
+ * Map [ComponentInstance->ServiceObject] storing created service objects.
+ */
+ private Map/*<ComponentInstance, ServiceObject>*/ m_instances = new HashMap();
+
+ private InstanceManager m_manager;
+
+ private String[] m_specs;
+
+ /**
+ * A method is invoked on the proxy object.
+ * If the method is the {@link IPOJOServiceFactory#getService(ComponentInstance)}
+ * method, this method creates a service object if no already created for the asking
+ * component instance.
+ * If the method is {@link IPOJOServiceFactory#ungetService(ComponentInstance, Object)}
+ * the service object is unget (i.e. removed from the map and deleted).
+ * In all other cases, a {@link UnsupportedOperationException} is thrown as this policy
+ * requires to use the {@link IPOJOServiceFactory} interaction pattern.
+ * @param arg0 the proxy object
+ * @param arg1 the called method
+ * @param arg2 the arguments
+ * @return the service object attached to the asking instance for 'get',
+ * <code>null</code> for 'unget',
+ * a {@link UnsupportedOperationException} for all other methods.
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ public Object invoke(Object arg0, Method arg1, Object[] arg2) {
+ if (isGetServiceMethod(arg1)) {
+ return getService((ComponentInstance) arg2[0]);
+ }
+
+ if (isUngetServiceMethod(arg1)) {
+ ungetService((ComponentInstance) arg2[0], arg2[1]);
+ return null;
+ }
+
+ throw new UnsupportedOperationException("This service requires an advanced creation policy. "
+ + "Before calling the service, call the getService(ComponentInstance) method to get "
+ + "the service object. " + arg1.getName()); // TODO DEBUG
+ }
+
+ /**
+ * A service object is required.
+ * This policy returns a service object per asking instance.
+ * @param instance the instance requiring the service object
+ * @return the service object for this instance
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#getService(org.apache.felix.ipojo.ComponentInstance)
+ */
+ public Object getService(ComponentInstance instance) {
+ Object obj = m_instances.get(instance);
+ if (obj == null) {
+ obj = m_manager.createPojoObject();
+ m_instances.put(instance, obj);
+ }
+ return obj;
+ }
+
+ /**
+ * A service object is unget.
+ * The service object is removed from the map and deleted.
+ * @param instance the instance releasing the service
+ * @param svcObject the service object
+ * @see org.apache.felix.ipojo.IPOJOServiceFactory#ungetService(org.apache.felix.ipojo.ComponentInstance, java.lang.Object)
+ */
+ public void ungetService(ComponentInstance instance, Object svcObject) {
+ Object pojo = m_instances.remove(instance);
+ m_manager.deletePojoObject(pojo);
+ }
+
+ /**
+ * The service is going to be registered.
+ * @param im the instance manager
+ * @param interfaces the published interfaces
+ * @param props the properties
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onPublication(org.osgi.framework.BundleContext, java.lang.String[], java.util.Properties)
+ */
+ public void onPublication(InstanceManager im, String[] interfaces,
+ Properties props) {
+
+ m_manager = im;
+ m_specs = interfaces;
+
+ }
+
+ /**
+ * The service is going to be unregistered.
+ * The instance map is cleared. Created object are disposed.
+ * @see org.apache.felix.ipojo.handlers.providedservice.CreationStrategy#onUnpublication()
+ */
+ public void onUnpublication() {
+ Collection col = m_instances.values();
+ Iterator it = col.iterator();
+ while (it.hasNext()) {
+ m_manager.deletePojoObject(it.next());
+ }
+ m_instances.clear();
+ }
+
+ /**
+ * OSGi Service Factory getService method.
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @return a proxy implementing the {@link IPOJOServiceFactory}
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ */
+ public Object getService(Bundle arg0, ServiceRegistration arg1) {
+ Object proxy = Proxy.newProxyInstance(m_manager.getClazz().getClassLoader(),
+ getSpecificationsWithIPOJOServiceFactory(m_specs, m_manager.getContext()), this);
+ return proxy;
+ }
+
+ /**
+ * OSGi Service factory unget method.
+ * Does nothing.
+ * @param arg0 the asking bundle
+ * @param arg1 the service registration
+ * @param arg2 the service object created for this bundle.
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+ */
+ public void ungetService(Bundle arg0, ServiceRegistration arg1,
+ Object arg2) { }
+
+ /**
+ * Utility method returning the class array of provided service
+ * specification and the {@link IPOJOServiceFactory} interface.
+ * @param specs the published service interface
+ * @param bc the bundle context, used to load classes
+ * @return the class array containing provided service specification and
+ * the {@link IPOJOServiceFactory} class.
+ */
+ private Class[] getSpecificationsWithIPOJOServiceFactory(String[] specs, BundleContext bc) {
+ Class[] classes = new Class[specs.length + 1];
+ int i = 0;
+ for (i = 0; i < specs.length; i++) {
+ try {
+ classes[i] = bc.getBundle().loadClass(specs[i]);
+ } catch (ClassNotFoundException e) {
+ // Should not happen.
+ }
+ }
+ classes[i] = IPOJOServiceFactory.class;
+ return classes;
+ }
+
+
+}
+
diff --git a/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/FooBarProviderType1.java b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/FooBarProviderType1.java
new file mode 100644
index 0000000..be254c5
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/FooBarProviderType1.java
@@ -0,0 +1,86 @@
+/*
+ * 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.test.scenarios.component.strategies;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.test.scenarios.ps.service.BarService;
+import org.apache.felix.ipojo.test.scenarios.ps.service.FooService;
+
+public class FooBarProviderType1 implements FooService, BarService {
+
+ public static long id = 0;
+
+ public static long getNewId() {
+ id++;
+ return id;
+ }
+
+ public static long getReturnedIds() {
+ return id;
+ }
+
+ public static void resetIds() {
+ id = 0;
+ }
+
+ private int m_bar;
+ private String m_foo;
+
+ private long myid = getNewId();
+
+
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ System.out.println(this + " - id : " + myid); //TODO DEBUG
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+
+ p.put("id", new Long(myid));
+ return p;
+ }
+
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+ public boolean bar() {
+ return foo();
+ }
+
+ public Properties getProps() {
+ return fooProps();
+ }
+
+
+}
diff --git a/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/FooProviderType1.java b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/FooProviderType1.java
new file mode 100755
index 0000000..967a8de
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/component/strategies/FooProviderType1.java
@@ -0,0 +1,77 @@
+/*
+ * 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.test.scenarios.component.strategies;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.test.scenarios.ps.service.FooService;
+
+public class FooProviderType1 implements FooService {
+
+ public static long id = 0;
+
+ public static long getNewId() {
+ id++;
+ return id;
+ }
+
+ public static long getReturnedIds() {
+ return id;
+ }
+
+ public static void resetIds() {
+ id = 0;
+ }
+
+ private int m_bar;
+ private String m_foo;
+
+ private long myid = getNewId();
+
+
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ System.out.println(this + " - id : " + myid); //TODO DEBUG
+ Properties p = new Properties();
+ p.put("bar", new Integer(m_bar));
+ if(m_foo != null) {
+ p.put("foo", m_foo);
+ }
+
+ p.put("id", new Long(myid));
+ return p;
+ }
+
+
+ public boolean getBoolean() { return true; }
+
+ public double getDouble() { return 1.0; }
+
+ public int getInt() { return 1; }
+
+ public long getLong() { return 1; }
+
+ public Boolean getObject() { return new Boolean(true); }
+
+
+}
diff --git a/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/ps/strategies/CustomStrategyTest.java b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/ps/strategies/CustomStrategyTest.java
new file mode 100644
index 0000000..f5635f4
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/ps/strategies/CustomStrategyTest.java
@@ -0,0 +1,200 @@
+package org.apache.felix.ipojo.test.scenarios.ps.strategies;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
+import org.apache.felix.ipojo.junit4osgi.helpers.IPOJOHelper;
+import org.apache.felix.ipojo.test.scenarios.component.strategies.FooBarProviderType1;
+import org.apache.felix.ipojo.test.scenarios.component.strategies.FooProviderType1;
+import org.apache.felix.ipojo.test.scenarios.ps.service.BarService;
+import org.apache.felix.ipojo.test.scenarios.ps.service.CheckService;
+import org.apache.felix.ipojo.test.scenarios.ps.service.FooService;
+import org.osgi.framework.ServiceReference;
+
+public class CustomStrategyTest extends OSGiTestCase {
+
+
+ private IPOJOHelper helper;
+ private ComponentInstance cons1, cons2, prov;
+ private ComponentInstance cons3, prov2;
+
+ public void setUp() {
+ helper = new IPOJOHelper(this);
+ cons1 = helper.createComponentInstance("PSS-Cons");
+ assertEquals("cons1 invalid", ComponentInstance.INVALID, cons1.getState());
+ cons2 = helper.createComponentInstance("PSS-Cons");
+ assertEquals("cons2 invalid", ComponentInstance.INVALID, cons2.getState());
+ prov = helper.createComponentInstance("PSS-FooProviderType-Custom");
+ prov2 = helper.createComponentInstance("PSS-FooBarProviderType-Custom");
+ cons3 = helper.createComponentInstance("PSS-ConsBar");
+ prov2.stop();
+ prov.stop();
+ }
+
+ public void tearDown() {
+ reset();
+ }
+
+
+ private void reset() {
+ FooProviderType1.resetIds();
+ FooBarProviderType1.resetIds();
+ }
+
+ private void checkCreatedObjects(ComponentInstance ci, int expected) {
+ assertEquals("Number of created objects", expected, ci.getInstanceDescription().getCreatedObjects().length);
+ }
+
+ public void testOneService() {
+ prov.start();
+ cons2.stop();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov.getState());
+ ServiceReference ref = helper.getServiceReferenceByName(FooService.class.getName(), prov.getInstanceName());
+ assertNotNull("Service available", ref);
+ checkCreatedObjects(prov, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = helper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) getServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov, 1);
+
+
+ // Step 2 : create a second consumer
+ cons2.start();
+ ServiceReference refcons2 = helper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) getServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov, 2);
+
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ System.out.println("cons2 stopping");
+ cons2.stop();
+ System.out.println("cons2 stopped");
+ checkCreatedObjects(prov, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+ public void testObjectCreation() {
+ prov.start();
+
+ // The two consumers are started and use their own objects.
+ ServiceReference refcons1 = helper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ CheckService cs_cons1 = (CheckService) getServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ FooService fscons1 = (FooService) props.get("object");
+
+ ServiceReference refcons2 = helper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ CheckService cs_cons2 = (CheckService) getServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ FooService fscons2 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Stop the provider
+ prov.stop();
+ // Cons1 and 2 are invalid.
+ assertEquals("Cons1 invalidity", ComponentInstance.INVALID, cons1.getState());
+ assertEquals("Cons2 invalidity", ComponentInstance.INVALID, cons2.getState());
+
+ // No object created in prov
+ checkCreatedObjects(prov, 0);
+
+ // Restart the provider
+ prov.start();
+
+ // Consumers are valid.
+ assertEquals("Cons1 validity", ComponentInstance.VALID, cons1.getState());
+ assertEquals("Cons2 validity", ComponentInstance.VALID, cons2.getState());
+
+ // Check objects
+ refcons1 = helper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ cs_cons1 = (CheckService) getServiceObject(refcons1);
+ props = cs_cons1.getProps();
+ Object fscons3 = (FooService) props.get("object");
+
+ refcons2 = helper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ cs_cons2 = (CheckService) getServiceObject(refcons2);
+ props2 = cs_cons2.getProps();
+ Object fscons4 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons3, fscons4);
+ assertNotSame("Two new objects - 1", fscons3, fscons1);
+ assertNotSame("Two new objects - 2", fscons4, fscons2);
+
+ }
+
+ public void testTwoServices() {
+ cons3.stop();
+ prov2.start();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov2.getState());
+ ServiceReference ref = helper.getServiceReferenceByName(FooService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", ref);
+ ServiceReference refBar = helper.getServiceReferenceByName(BarService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", refBar);
+ checkCreatedObjects(prov2, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = helper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) getServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov2, 1);
+
+
+ // Step 2 : create a second consumer
+ cons3.start();
+ ServiceReference refcons2 = helper.getServiceReferenceByName(CheckService.class.getName(), cons3.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) getServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov2, 2);
+
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ cons3.stop();
+ checkCreatedObjects(prov2, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+}
diff --git a/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/ps/strategies/PerInstanceStrategyTest.java b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/ps/strategies/PerInstanceStrategyTest.java
new file mode 100644
index 0000000..e59b2ce
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/ps/strategies/PerInstanceStrategyTest.java
@@ -0,0 +1,200 @@
+package org.apache.felix.ipojo.test.scenarios.ps.strategies;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
+import org.apache.felix.ipojo.junit4osgi.helpers.IPOJOHelper;
+import org.apache.felix.ipojo.test.scenarios.component.strategies.FooBarProviderType1;
+import org.apache.felix.ipojo.test.scenarios.component.strategies.FooProviderType1;
+import org.apache.felix.ipojo.test.scenarios.ps.service.BarService;
+import org.apache.felix.ipojo.test.scenarios.ps.service.CheckService;
+import org.apache.felix.ipojo.test.scenarios.ps.service.FooService;
+import org.osgi.framework.ServiceReference;
+
+public class PerInstanceStrategyTest extends OSGiTestCase {
+
+
+ private IPOJOHelper helper;
+ private ComponentInstance cons1, cons2, prov;
+ private ComponentInstance cons3, prov2;
+
+ public void setUp() {
+ helper = new IPOJOHelper(this);
+ cons1 = helper.createComponentInstance("PSS-Cons");
+ assertEquals("cons1 invalid", ComponentInstance.INVALID, cons1.getState());
+ cons2 = helper.createComponentInstance("PSS-Cons");
+ assertEquals("cons2 invalid", ComponentInstance.INVALID, cons2.getState());
+ prov = helper.createComponentInstance("PSS-FooProviderType-Instance");
+ prov2 = helper.createComponentInstance("PSS-FooBarProviderType-Instance");
+ cons3 = helper.createComponentInstance("PSS-ConsBar");
+ prov2.stop();
+ prov.stop();
+ }
+
+ public void tearDown() {
+ reset();
+ }
+
+
+ private void reset() {
+ FooProviderType1.resetIds();
+ FooBarProviderType1.resetIds();
+ }
+
+ private void checkCreatedObjects(ComponentInstance ci, int expected) {
+ assertEquals("Number of created objects", expected, ci.getInstanceDescription().getCreatedObjects().length);
+ }
+
+ public void testOneService() {
+ prov.start();
+ cons2.stop();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov.getState());
+ ServiceReference ref = helper.getServiceReferenceByName(FooService.class.getName(), prov.getInstanceName());
+ assertNotNull("Service available", ref);
+ checkCreatedObjects(prov, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = helper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) getServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov, 1);
+
+
+ // Step 2 : create a second consumer
+ cons2.start();
+ ServiceReference refcons2 = helper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) getServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov, 2);
+
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ System.out.println("cons2 stopping");
+ cons2.stop();
+ System.out.println("cons2 stopped");
+ checkCreatedObjects(prov, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+ public void testObjectCreation() {
+ prov.start();
+
+ // The two consumers are started and use their own objects.
+ ServiceReference refcons1 = helper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ CheckService cs_cons1 = (CheckService) getServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ FooService fscons1 = (FooService) props.get("object");
+
+ ServiceReference refcons2 = helper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ CheckService cs_cons2 = (CheckService) getServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ FooService fscons2 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Stop the provider
+ prov.stop();
+ // Cons1 and 2 are invalid.
+ assertEquals("Cons1 invalidity", ComponentInstance.INVALID, cons1.getState());
+ assertEquals("Cons2 invalidity", ComponentInstance.INVALID, cons2.getState());
+
+ // No object created in prov
+ checkCreatedObjects(prov, 0);
+
+ // Restart the provider
+ prov.start();
+
+ // Consumers are valid.
+ assertEquals("Cons1 validity", ComponentInstance.VALID, cons1.getState());
+ assertEquals("Cons2 validity", ComponentInstance.VALID, cons2.getState());
+
+ // Check objects
+ refcons1 = helper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+ cs_cons1 = (CheckService) getServiceObject(refcons1);
+ props = cs_cons1.getProps();
+ Object fscons3 = (FooService) props.get("object");
+
+ refcons2 = helper.getServiceReferenceByName(CheckService.class.getName(), cons2.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+ cs_cons2 = (CheckService) getServiceObject(refcons2);
+ props2 = cs_cons2.getProps();
+ Object fscons4 = (FooService) props2.get("object");
+
+ checkCreatedObjects(prov, 2);
+ assertNotSame("Two objects", fscons3, fscons4);
+ assertNotSame("Two new objects - 1", fscons3, fscons1);
+ assertNotSame("Two new objects - 2", fscons4, fscons2);
+
+ }
+
+ public void testTwoServices() {
+ cons3.stop();
+ prov2.start();
+ cons1.stop();
+ assertEquals("Prov valid", ComponentInstance.VALID, prov2.getState());
+ ServiceReference ref = helper.getServiceReferenceByName(FooService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", ref);
+ ServiceReference refBar = helper.getServiceReferenceByName(BarService.class.getName(), prov2.getInstanceName());
+ assertNotNull("Service available", refBar);
+ checkCreatedObjects(prov2, 0);
+
+ // Step 1 : create start one consumer
+ cons1.start();
+ ServiceReference refcons1 = helper.getServiceReferenceByName(CheckService.class.getName(), cons1.getInstanceName());
+ assertNotNull("Cons1 Service available", refcons1);
+
+ CheckService cs_cons1 = (CheckService) getServiceObject(refcons1);
+ Properties props = cs_cons1.getProps();
+ Long id = (Long) props.get("id");
+ FooService fscons1 = (FooService) props.get("object");
+ assertEquals("id 1", 1, id.intValue());
+ checkCreatedObjects(prov2, 1);
+
+
+ // Step 2 : create a second consumer
+ cons3.start();
+ ServiceReference refcons2 = helper.getServiceReferenceByName(CheckService.class.getName(), cons3.getInstanceName());
+ assertNotNull("Cons2 Service available", refcons2);
+
+ CheckService cs_cons2 = (CheckService) getServiceObject(refcons2);
+ Properties props2 = cs_cons2.getProps();
+ Long id2 = (Long) props2.get("id");
+ FooService fscons2 = (FooService) props2.get("object");
+ assertEquals("id 2", 2, id2.intValue());
+ checkCreatedObjects(prov2, 2);
+
+
+ assertNotSame("Two objects", fscons1, fscons2);
+
+ // Step 3 : stop the second provider
+ cons3.stop();
+ checkCreatedObjects(prov2, 1);
+
+ // Step 4 : stop the first consumer
+ cons1.stop();
+ checkCreatedObjects(prov, 0);
+ }
+
+}
diff --git a/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/ps/strategies/ProvidedServiceStrategyTestSuite.java b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/ps/strategies/ProvidedServiceStrategyTestSuite.java
new file mode 100755
index 0000000..9b1a99d
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/src/main/java/org/apache/felix/ipojo/test/scenarios/ps/strategies/ProvidedServiceStrategyTestSuite.java
@@ -0,0 +1,36 @@
+/*
+ * 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.test.scenarios.ps.strategies;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.felix.ipojo.junit4osgi.OSGiTestSuite;
+import org.osgi.framework.BundleContext;
+
+public class ProvidedServiceStrategyTestSuite extends TestSuite {
+
+ public static Test suite(BundleContext bc) {
+ OSGiTestSuite ots = new OSGiTestSuite("Provided Service Strategy Test Suite", bc);
+ ots.addTestSuite(PerInstanceStrategyTest.class);
+ ots.addTestSuite(CustomStrategyTest.class);
+ return ots;
+ }
+
+}
diff --git a/ipojo/tests/core/service-providing-strategies/src/main/resources/metadata.xml b/ipojo/tests/core/service-providing-strategies/src/main/resources/metadata.xml
new file mode 100755
index 0000000..dccd19c
--- /dev/null
+++ b/ipojo/tests/core/service-providing-strategies/src/main/resources/metadata.xml
@@ -0,0 +1,42 @@
+<ipojo>
+ <!-- Simple provider -->
+ <component
+ classname="org.apache.felix.ipojo.test.scenarios.component.strategies.FooProviderType1"
+ name="PSS-FooProviderType-Instance" architecture="true">
+ <provides strategy="instance"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.test.scenarios.component.strategies.Consumer"
+ name="PSS-Cons" architecture="true">
+ <requires field="fs"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.test.scenarios.component.strategies.BarConsumer"
+ name="PSS-ConsBar" architecture="true">
+ <requires field="bs"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.test.scenarios.component.strategies.FooBarProviderType1"
+ name="PSS-FooBarProviderType-Instance" architecture="true">
+ <provides strategy="instance"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.test.scenarios.component.strategies.FooProviderType1"
+ name="PSS-FooProviderType-Custom" architecture="true">
+ <provides strategy="org.apache.felix.ipojo.test.scenarios.component.strategies.DummyCreationStrategy"/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.test.scenarios.component.strategies.FooBarProviderType1"
+ name="PSS-FooBarProviderType-Custom" architecture="true">
+ <provides strategy="org.apache.felix.ipojo.test.scenarios.component.strategies.DummyCreationStrategy"/>
+ </component>
+
+
+</ipojo>
diff --git a/ipojo/tests/integration-tests/pom.xml b/ipojo/tests/integration-tests/pom.xml
index 194132d..a1409fd 100644
--- a/ipojo/tests/integration-tests/pom.xml
+++ b/ipojo/tests/integration-tests/pom.xml
@@ -181,6 +181,13 @@
<version>${ipojo.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <artifactId>tests.core.ps.strategy</artifactId>
+ <groupId>ipojo.tests</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
<!-- Composite -->
<dependency>
diff --git a/ipojo/tests/pom.xml b/ipojo/tests/pom.xml
index 0bb3372..8573de0 100644
--- a/ipojo/tests/pom.xml
+++ b/ipojo/tests/pom.xml
@@ -37,6 +37,7 @@
<module>core/service-dependency-bindingpolicy</module>
<module>core/service-dependency-filter</module>
<module>core/service-dependency-comparator</module>
+ <module>core/service-providing-strategies</module>
<module>core/configuration</module>
<module>core/external-handlers</module>
<module>core/bad-configurations</module>