Fix issue Felix-1159
Add a 'version' attribute to component type and instances allowing to select the component type version when an instance is declared.
<component classname="..." version="1.0"/>
<component classname="..." version="1.1"/>
<instance component="..." version="1.0"/> -> Use the version 1.0
<instance component="..." version="1.1"/> -> Use the version 1.1
<instance component="..."/> -> Any version
This commit also define the "bundle" constant reusing the bundle version:
<component classname="..." version="bundle"/> -> Use the bundle version
The API also supports the version API, add a getVersion method in the ComponentTypeDescription and in the Factory interface.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@775456 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java
index c1529dd..df2b63e 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.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
@@ -42,83 +42,88 @@
* The bundle context.
*/
private BundleContext m_context;
-
+
/**
- * The implementation class name.
+ * The implementation class name.
*/
private String m_classname;
-
+
/**
- * The component type name.
+ * The component type name.
*/
private String m_name;
-
+
/**
- * Is the component type immediate.
+ * The component type version.
+ */
+ private String m_version;
+
+ /**
+ * Is the component type immediate.
*/
private boolean m_immediate;
-
+
/**
- * Manipulation metadata of the component type.
+ * Manipulation metadata of the component type.
*/
private Element m_manipulation;
-
+
/**
* Component factory attached to the component
- * type.
+ * type.
*/
private ComponentFactory m_factory;
-
+
/**
- * Component type metadata.
+ * Component type metadata.
*/
private Element m_metadata;
-
+
/**
- * List of provided services.
+ * List of provided services.
*/
private List m_services = new ArrayList(1);
-
+
/**
- * List of service dependencies.
+ * List of service dependencies.
*/
private List m_dependencies = new ArrayList();
-
+
/**
- * List of configuration properties.
+ * List of configuration properties.
*/
private List m_properties = new ArrayList();
-
+
/**
- * The validate callback.
+ * The validate callback.
*/
private String m_validate;
-
+
/**
- * The invalidate callback.
+ * The invalidate callback.
*/
private String m_invalidate;
-
+
/**
* The udpated callback.
*/
private String m_updated;
-
+
/**
- * Are the properties propagated to provided services?
+ * Are the properties propagated to provided services?
*/
private boolean m_propagation;
-
+
/**
- * The factory method.
+ * The factory method.
*/
private String m_factoryMethod;
-
+
/**
- * Is the factory public?
+ * Is the factory public?
*/
private boolean m_public = true;
-
+
/**
* The Managed Service PID.
*/
@@ -128,13 +133,13 @@
* The temporal dependencies.
*/
private ArrayList m_temporals = new ArrayList();
-
+
/**
* List of Handler representing external
* handler configuration.
*/
private List m_handlers = new ArrayList();
-
+
/**
* Checks that the component type is not already
* started.
@@ -144,7 +149,7 @@
throw new IllegalStateException("The component type was already initialized, cannot modify metadata");
}
}
-
+
/**
* Checks that the component type description is valid.
*/
@@ -184,7 +189,7 @@
initializeFactory();
m_factory.stop();
}
-
+
/**
* Initializes the factory.
*/
@@ -193,7 +198,7 @@
createFactory();
}
}
-
+
/**
* Sets the bundle context.
* @param bc the bundle context
@@ -204,10 +209,10 @@
m_context = bc;
return this;
}
-
+
/**
* Sets the implementation class.
- * @param classname the class name
+ * @param classname the class name
* @return the current component type
*/
public PrimitiveComponentType setClassName(String classname) {
@@ -215,7 +220,7 @@
m_classname = classname;
return this;
}
-
+
/**
* Sets the component type name.
* @param name the factory name
@@ -226,7 +231,19 @@
m_name = name;
return this;
}
-
+
+ /**
+ * Sets the component type version.
+ * @param version the factory version or "bundle" to use the
+ * bundle version.
+ * @return the current component type
+ */
+ public PrimitiveComponentType setComponentTypeVersion(String version) {
+ ensureNotInitialized();
+ m_version = version;
+ return this;
+ }
+
/**
* Sets if the component type is immediate or not.
* @param immediate <code>true</code> to set the component
@@ -238,7 +255,7 @@
m_immediate = immediate;
return this;
}
-
+
/**
* Sets the dependency factory method.
* @param method the method used to create pojo object.
@@ -249,7 +266,7 @@
m_factoryMethod = method;
return this;
}
-
+
/**
* Sets if the component type propagates properties to service properties.
* @param propagation <code>true</code> to enable propagation
@@ -260,10 +277,10 @@
m_propagation = propagation;
return this;
}
-
+
/**
* Sets the factory public aspect.
- * @param visible <code>false</code> to create a private factory.
+ * @param visible <code>false</code> to create a private factory.
* @return the current component type
*/
public PrimitiveComponentType setPublic(boolean visible) {
@@ -271,7 +288,7 @@
m_public = visible;
return this;
}
-
+
/**
* Sets the managed service pid.
* @param pid the managed service pid
@@ -282,7 +299,7 @@
m_msPID = pid;
return this;
}
-
+
/**
* Sets the validate method.
* @param method the validate method
@@ -293,7 +310,7 @@
m_validate = method;
return this;
}
-
+
/**
* Sets the invalidate method.
* @param method the invalidate method
@@ -304,7 +321,7 @@
m_invalidate = method;
return this;
}
-
+
/**
* Sets the updated method.
* @param method the updated method
@@ -315,10 +332,10 @@
m_updated = method;
return this;
}
-
+
/**
* Generates the component description.
- * @return the component type description of
+ * @return the component type description of
* the current component type
*/
private Element generateComponentMetadata() {
@@ -327,6 +344,9 @@
if (m_name != null) {
element.addAttribute(new Attribute("name", m_name));
}
+ if (m_version != null) {
+ element.addAttribute(new Attribute("version", m_version));
+ }
if (m_factoryMethod != null) {
element.addAttribute(new Attribute("factory-method", m_factoryMethod));
}
@@ -360,7 +380,7 @@
callback.addAttribute(new Attribute("method", m_invalidate));
element.addElement(callback);
}
-
+
// Properties
// First determine if we need the properties element
if (m_propagation || m_msPID != null || ! m_properties.isEmpty()) {
@@ -380,16 +400,16 @@
}
element.addElement(properties);
}
-
+
// External handlers
for (int i = 0; i < m_handlers.size(); i++) {
HandlerConfiguration hc = (HandlerConfiguration) m_handlers.get(i);
element.addElement(hc.getElement());
}
-
+
return element;
}
-
+
/**
* Adds an HandlerConfiguration to the component type. Each component type
@@ -402,7 +422,7 @@
m_handlers.add(handler);
return this;
}
-
+
/**
* Creates the component factory.
*/
@@ -422,9 +442,9 @@
} catch (ConfigurationException e) {
throw new IllegalStateException("An exception occurs during factory initialization : " + e.getMessage());
}
-
+
}
-
+
/**
* Manipulates the implementation class.
* @return the manipulated class
@@ -440,7 +460,7 @@
throw new IllegalStateException("An exception occurs during implementation class manipulation : " + e.getMessage());
}
}
-
+
/**
* Gets a class file as a byte array.
* @return the byte array.
@@ -456,8 +476,8 @@
if (is == null) {
throw new IllegalStateException("An exception occurs during implementation class manipulation : cannot read the class file " + url);
}
- byte[] b = new byte[is.available()];
- is.read(b);
+ byte[] b = new byte[is.available()];
+ is.read(b);
return b;
}
@@ -471,7 +491,7 @@
m_services.add(svc);
return this;
}
-
+
/**
* Adds a service dependency.
* @param dep the dependency to add
@@ -482,7 +502,7 @@
m_dependencies.add(dep);
return this;
}
-
+
/**
* Adds a temporal service dependency.
* @param dep the temporal dependency to add
@@ -493,7 +513,7 @@
m_temporals.add(dep);
return this;
}
-
+
/**
* Adds a configuration property.
* @param prop the property to add
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java
index 9d33c28..be3dcc6 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.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
@@ -36,50 +36,50 @@
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class CompositeComponentType extends ComponentType {
-
+
/**
* The bundle context.
*/
private BundleContext m_context;
-
+
/**
* Component factory attached to the component
- * type.
+ * type.
*/
private ComponentFactory m_factory;
-
+
/**
- * Component type metadata.
+ * Component type metadata.
*/
private Element m_metadata;
-
+
/**
- * List of provided services.
+ * List of provided services.
*/
private List m_provided = new ArrayList(1);
-
+
/**
- * List of exported services.
+ * List of exported services.
*/
private List m_exported = new ArrayList(1);
-
+
/**
- * List of imported services.
+ * List of imported services.
*/
private List m_imported = new ArrayList(1);
-
+
/**
- * List of instantiated services.
+ * List of instantiated services.
*/
private List m_instantiated = new ArrayList();
-
+
/**
* List of contained instance.
*/
- private List m_contained = new ArrayList();
-
+ private List m_contained = new ArrayList();
+
/**
- * Is the factory public?
+ * Is the factory public?
*/
private boolean m_public = true;
@@ -87,7 +87,12 @@
* Component type name.
*/
private String m_name;
-
+
+ /**
+ * Component type version.
+ */
+ private String m_version;
+
/**
* List of Handler representing external.
* handler configuration
@@ -103,7 +108,7 @@
throw new IllegalStateException("The component type was already initialized, cannot modify metadata");
}
}
-
+
/**
* Checks that the component type description is valid.
*/
@@ -140,7 +145,7 @@
initializeFactory();
m_factory.stop();
}
-
+
/**
* Initializes the factory.
*/
@@ -149,7 +154,7 @@
createFactory();
}
}
-
+
/**
* Sets the bundle context.
* @param bc the bundle context
@@ -160,10 +165,10 @@
m_context = bc;
return this;
}
-
+
/**
* Sets the factory public aspect.
- * @param visible <code>false</code> to create a private factory.
+ * @param visible <code>false</code> to create a private factory.
* @return the current component type
*/
public CompositeComponentType setPublic(boolean visible) {
@@ -171,7 +176,7 @@
m_public = visible;
return this;
}
-
+
/**
* Sets the component type name.
* @param name the factory name
@@ -182,7 +187,19 @@
m_name = name;
return this;
}
-
+
+ /**
+ * Sets the component type version.
+ * @param version the factory version or "bundle" to use the
+ * bundle version.
+ * @return the current component type
+ */
+ public CompositeComponentType setComponentTypeVersion(String version) {
+ ensureNotInitialized();
+ m_version = version;
+ return this;
+ }
+
/**
* Adds a contained instance.
* @param inst the instance to add
@@ -192,7 +209,7 @@
m_contained.add(inst);
return this;
}
-
+
/**
* Adds an imported (sub-)service.
* @param is the imported service to add
@@ -202,7 +219,7 @@
m_imported.add(is);
return this;
}
-
+
/**
* Adds an instantiated sub-service.
* @param is the instantiated service to add
@@ -212,7 +229,7 @@
m_instantiated.add(is);
return this;
}
-
+
/**
* Adds an exported service.
* @param es the exported service to add
@@ -222,7 +239,7 @@
m_exported.add(es);
return this;
}
-
+
/**
* Adds a provided service.
* @param es the provided service to add
@@ -232,7 +249,7 @@
m_provided.add(es);
return this;
}
-
+
/**
* Adds an HandlerConfiguration to the component type. Each component type
* implementation must uses the populated list (m_handlers) when generating
@@ -244,10 +261,10 @@
m_handlers.add(handler);
return this;
}
-
+
/**
* Generates the component description.
- * @return the component type description of
+ * @return the component type description of
* the current component type
*/
private Element generateComponentMetadata() {
@@ -255,6 +272,9 @@
if (m_name != null) {
element.addAttribute(new Attribute("name", m_name));
}
+ if (m_version != null) {
+ element.addAttribute(new Attribute("version", m_version));
+ }
if (! m_public) {
element.addAttribute(new Attribute("public", "false"));
}
@@ -278,16 +298,16 @@
ProvidedService inst = (ProvidedService) m_provided.get(i);
element.addElement(inst.getElement());
}
-
+
// External handlers
for (int i = 0; i < m_handlers.size(); i++) {
HandlerConfiguration hc = (HandlerConfiguration) m_handlers.get(i);
element.addElement(hc.getElement());
}
-
+
return element;
}
-
+
/**
* Creates the component factory.
*/
@@ -300,10 +320,10 @@
} catch (ConfigurationException e) {
throw new IllegalStateException("An exception occurs during factory initialization : " + e.getMessage());
}
-
- }
-
-
+ }
+
+
+
}
diff --git a/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.java b/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.java
index a2a67ba..81d2f7c 100644
--- a/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.java
+++ b/ipojo/composite/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.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
@@ -170,4 +170,8 @@
return m_delegate.getBundleContext();
}
+ public String getVersion() {
+ return m_delegate.getVersion();
+ }
+
}
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
index 91578fc..4016e1d 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/ComponentFactory.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
@@ -40,7 +40,7 @@
/**
* The component factory manages component instance objects. This management
- * consists to create and manage component instances build with the current
+ * consists to create and manage component instances build with the current
* component factory. This class could export Factory and ManagedServiceFactory
* services.
* @see IPojoFactory
@@ -149,7 +149,7 @@
*/
public ComponentInstance createInstance(Dictionary config, IPojoContext context, HandlerManager[] handlers) throws org.apache.felix.ipojo.ConfigurationException {
InstanceManager instance = new InstanceManager(this, context, handlers);
-
+
try {
instance.configure(m_componentMetadata, config);
instance.start();
@@ -175,7 +175,7 @@
/**
* Defines a class.
- * This method needs to be synchronized to avoid that the classloader
+ * This method needs to be synchronized to avoid that the classloader
* is created twice.
* This method delegate the <code>define</code> method invocation to the
* factory classloader.
@@ -193,7 +193,7 @@
/**
* Returns the URL of a resource.
- * This methods delegates the invocation to the
+ * This methods delegates the invocation to the
* {@link Bundle#getResource(String)} method.
* @param resName the resource name
* @return the URL of the resource
@@ -256,7 +256,7 @@
* Computes the factory name. The factory name is computed from
* the 'name' and 'classname' attributes.
* This method does not manipulate any non-immutable fields,
- * so does not need to be synchronized.
+ * so does not need to be synchronized.
* @return the factory name.
*/
public String getFactoryName() {
@@ -270,7 +270,7 @@
/**
* Computes required handlers.
- * This method does not manipulate any non-immutable fields,
+ * This method does not manipulate any non-immutable fields,
* so does not need to be synchronized.
* @return the required handler list.
*/
@@ -292,8 +292,8 @@
if (arch == null || arch.equalsIgnoreCase("true")) {
list.add(new RequiredHandler("architecture", null));
}
-
-
+
+
// Determine if the component must be immediate.
// A component becomes immediate if it doesn't provide a service,
// and does not specified that the component is not immediate.
@@ -323,13 +323,13 @@
/**
* This method is called when a new handler factory is detected.
* Test if the factory can be used or not.
- * This method need to be synchronized as it accesses to the content
+ * This method need to be synchronized as it accesses to the content
* of required handlers.
* @param reference the new service reference.
* @return <code>true</code> if the given factory reference matches with a required handler.
* @see org.apache.felix.ipojo.util.TrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
*/
- public synchronized boolean addingService(ServiceReference reference) {
+ public synchronized boolean addingService(ServiceReference reference) {
for (int i = 0; i < m_requiredHandlers.size(); i++) {
RequiredHandler req = (RequiredHandler) m_requiredHandlers.get(i);
if (req.getReference() == null && match(req, reference)) {
@@ -347,8 +347,8 @@
}
/**
- * This method is called when a matching service has been added to the tracker,
- * we can no compute the factory state. This method is synchronized to avoid
+ * This method is called when a matching service has been added to the tracker,
+ * we can no compute the factory state. This method is synchronized to avoid
* concurrent calls to method modifying the factory state.
* @param reference the added service reference.
* @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
@@ -361,7 +361,7 @@
/**
* This method is called when a used handler factory disappears.
- * This method is synchronized to avoid concurrent calls to method modifying
+ * This method is synchronized to avoid concurrent calls to method modifying
* the factory state.
* @param reference the leaving service reference.
* @param service the handler factory object.
@@ -400,6 +400,15 @@
}
/**
+ * Gets the version of the component type
+ * @return the version of </code>null</code> if not set.
+ * @see org.apache.felix.ipojo.Factory#getVersion()
+ */
+ public String getVersion() {
+ return m_version;
+ }
+
+ /**
* this class defines the classloader attached to a factory.
* This class loader is used to load the implementation (e.g. manipulated)
* class.
@@ -453,7 +462,7 @@
/**
* This class defines the description of primitive (non-composite) component
- * types. An instance of this class will be returned when invoking the
+ * types. An instance of this class will be returned when invoking the
* {@link ComponentFactory#getComponentDescription()} method.
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
@@ -468,7 +477,7 @@
}
/**
- * Computes the properties to publish.
+ * Computes the properties to publish.
* The <code>component.class</code> property contains the implementation class name.
* @return the dictionary of properties to publish
* @see org.apache.felix.ipojo.architecture.ComponentTypeDescription#getPropertiesToPublish()
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/Factory.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/Factory.java
index 84ccf65..d5c0b95 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/Factory.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/Factory.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
@@ -32,13 +32,13 @@
public interface Factory {
/**
- * Factory State.
+ * Factory State.
* A valid factory is a factory where all required handlers are available.
*/
int VALID = 1;
/**
- * Factory State.
+ * Factory State.
* An invalid factory is a factory where at least one required handler is
* unavailable. Creating an instance with an invalid factory failed.
*/
@@ -67,7 +67,7 @@
ComponentInstance createComponentInstance(Dictionary configuration, ServiceContext serviceContext) throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException;
/**
- * Gets the component type information containing provided service,
+ * Gets the component type information containing provided service,
* configuration properties ...
* @return the component type information.
*/
@@ -94,7 +94,7 @@
String getName();
/**
- * Reconfigures an instance already created. This configuration needs to
+ * Reconfigures an instance already created. This configuration needs to
* have the name property to identify the instance.
* @param conf the configuration to reconfigure the instance.
* @throws UnacceptableConfiguration if the given configuration is not consistent for the targeted instance.
@@ -117,14 +117,14 @@
/**
* Gets the list of missing handlers.
* The handlers are given under the form namespace:name
- * @return the list containing the name of missing handlers
+ * @return the list containing the name of missing handlers
*/
List getMissingHandlers();
/**
* Get the list of required handlers.
* The handlers are given under the form namespace:name
- * @return the list containing the name of required handlers
+ * @return the list containing the name of required handlers
*/
List getRequiredHandlers();
@@ -148,4 +148,11 @@
*/
BundleContext getBundleContext();
+ /**
+ * Gets the version of the component type.
+ * @return the component type version or <code>null</code> if
+ * not specified.
+ */
+ String getVersion();
+
}
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java
index b3da972..a3e3f2e 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/IPojoFactory.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
@@ -32,6 +32,7 @@
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.util.Logger;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ManagedServiceFactory;
@@ -62,7 +63,7 @@
protected ComponentTypeDescription m_componentDesc;
/**
- * The list of the managed instance managers.
+ * The list of the managed instance managers.
* The key of this map is the name (i.e. instance names) of the created instance
*/
protected final Map m_componentInstances = new HashMap();
@@ -78,7 +79,7 @@
protected final BundleContext m_context;
/**
- * The factory name.
+ * The factory name.
* Could be the component class name if the factory name is not set.
* Immutable once set.
*/
@@ -106,6 +107,11 @@
protected final boolean m_isPublic;
/**
+ * The version of the component type.
+ */
+ protected final String m_version;
+
+ /**
* The service registration of this factory (Factory & ManagedServiceFactory).
* @see ManagedServiceFactory
* @see Factory
@@ -129,7 +135,7 @@
private long m_index = 0;
/**
- * The flag indicating if this factory has already a
+ * The flag indicating if this factory has already a
* computed description or not.
*/
private boolean m_described;
@@ -149,6 +155,15 @@
String fac = metadata.getAttribute("public");
m_isPublic = fac == null || !fac.equalsIgnoreCase("false");
m_logger = new Logger(m_context, m_factoryName);
+
+ // Compute the component type version.
+ String version = metadata.getAttribute("version");
+ if ("bundle".equalsIgnoreCase(version)) { // Handle the "bundle" constant: use the bundle version.
+ m_version = (String) m_context.getBundle().getHeaders().get(Constants.BUNDLE_VERSION);
+ } else {
+ m_version = version;
+ }
+
m_requiredHandlers = getRequiredHandlerList(); // Call sub-class to get the list of required handlers.
}
@@ -181,7 +196,7 @@
/**
* Computes the factory name.
- * Each sub-type must override this method.
+ * Each sub-type must override this method.
* @return the factory name.
*/
public abstract String getFactoryName();
@@ -239,7 +254,7 @@
if (configuration == null) {
configuration = new Properties();
}
-
+
IPojoContext context = null;
if (serviceContext == null) {
context = new IPojoContext(m_context);
@@ -417,7 +432,7 @@
}
// Check that the configuration does not override immutable properties.
-
+
for (int i = 0; i < props.length; i++) {
// Is the property immutable
if (props[i].isImmutable() && conf.get(props[i].getName()) != null) {
@@ -433,7 +448,7 @@
/**
* Reconfigures an existing instance.
* The acceptability of the configuration is checked before the reconfiguration. Moreover,
- * the configuration must contain the 'instance.name' property specifying the instance
+ * the configuration must contain the 'instance.name' property specifying the instance
* to reconfigure.
* This method is synchronized to assert the validity of the factory during the reconfiguration.
* @param properties the new configuration to push.
@@ -450,12 +465,12 @@
if (name == null) {
name = (String) properties.get("name");
}
-
+
ComponentInstance instance = (ComponentInstance) m_componentInstances.get(name);
if (instance == null) { // The instance does not exists.
return;
}
-
+
checkAcceptability(properties); // Test if the configuration is acceptable
instance.reconfigure(properties); // re-configure the instance
}
@@ -472,7 +487,7 @@
}
/**
- * Stopping method.
+ * Stopping method.
* This method is call when the factory is stopping.
* This method is called when holding the lock on the factory.
*/
@@ -483,7 +498,7 @@
* This method calls the {@link IPojoFactory#stopping()} method,
* notifies listeners, and disposes created instances. Moreover,
* if the factory is public, services are also unregistered.
- *
+ *
*/
public synchronized void stop() {
ComponentInstance[] instances;
@@ -527,7 +542,7 @@
}
/**
- * Destroys the factory.
+ * Destroys the factory.
* The factory cannot be restarted. Only the {@link Extender} can call this method.
*/
synchronized void dispose() {
@@ -537,7 +552,7 @@
}
/**
- * Starting method.
+ * Starting method.
* This method is called when the factory is starting.
* This method is called when holding the lock on the factory.
*/
@@ -580,7 +595,7 @@
synchronized (this) {
instance = (InstanceManager) m_componentInstances.get(name);
}
-
+
if (instance == null) {
try {
properties.put("instance.name", name); // Add the name in the configuration
@@ -637,9 +652,9 @@
/**
* Computes the component type description.
- * To do this, it creates a 'ghost' instance of the handler
+ * To do this, it creates a 'ghost' instance of the handler
* and calls the {@link Handler#initializeComponentFactory(ComponentTypeDescription, Element)}
- * method. The handler instance is then deleted.
+ * method. The handler instance is then deleted.
* The factory must be valid when calling this method.
* This method is called with the lock.
*/
@@ -849,7 +864,7 @@
}
}
-
+
/**
* Hashcode method.
* This method delegates to the {@link Object#hashCode()}.
@@ -861,7 +876,7 @@
}
/**
- * Gets the factory object used for this handler.
+ * Gets the factory object used for this handler.
* The object is get when used for the first time.
* This method is called with the lock avoiding concurrent modification and on a valid factory.
* @return the factory object.
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
index 988b1f0..48c3b29 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.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
@@ -30,7 +30,7 @@
import org.osgi.framework.BundleContext;
/**
- * The instance creator creates instances and tracks their factories.
+ * The instance creator creates instances and tracks their factories.
* It allows creating instances from external factories.
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
@@ -72,11 +72,16 @@
* @param bundle the bundle id declaring the instance
*/
synchronized void addInstance(Dictionary instance, long bundle) {
- m_logger.log(Logger.DEBUG, "New instance to managed, looking for " + instance.get("component"));
+ if (instance.get("factory.version") != null) {
+ m_logger.log(Logger.DEBUG, "New instance to managed, looking for " + instance.get("component") + "-" + instance.get("factory.version"));
+ } else {
+ m_logger.log(Logger.DEBUG, "New instance to managed, looking for " + instance.get("component"));
+ }
+
ManagedInstance managed = new ManagedInstance(instance, bundle);
for (int i = 0; i < m_factories.size(); i++) {
IPojoFactory factory = (IPojoFactory) m_factories.get(i);
- if (managed.matchName(factory)) {
+ if (managed.matchNameAndVersion(factory)) {
// Subscribe to the factory state change
m_logger.log(Logger.DEBUG, "Listen factory " + factory.getName() + " events");
factory.addFactoryStateListener(this);
@@ -86,7 +91,7 @@
if (list == null) {
list = new ArrayList();
list.add(managed);
- m_attached.put(factory, list);
+ m_attached.put(factory, list);
} else {
list.add(managed);
}
@@ -152,7 +157,7 @@
m_factories.add(factory);
for (int i = 0; i < m_idle.size(); i++) {
ManagedInstance managed = (ManagedInstance) m_idle.get(i);
- if (managed.matchName(factory)) {
+ if (managed.matchNameAndVersion(factory)) {
// We have to subscribe to the factory.
factory.addFactoryStateListener(this);
if (factory.getState() == Factory.VALID && managed.match(factory)) {
@@ -243,8 +248,8 @@
}
/**
- * This structure aims to manage a configuration.
- * It stores all necessary information to create an instance
+ * This structure aims to manage a configuration.
+ * It stores all necessary information to create an instance
* and to track the factory.
*/
private class ManagedInstance {
@@ -293,32 +298,38 @@
ComponentInstance getInstance() {
return m_instance;
}
-
-
+
+
/**
* Checks if the required factory name match with the given factory.
* This methods checks only the name, and not the configuration.
* @param factory the factory to test
- * @return <code>true</code> if the factory name matches, <code>false</code>
+ * @return <code>true</code> if the factory name and the version (if set) match, <code>false</code>
* otherwise.
*/
- public boolean matchName(IPojoFactory factory) {
+ public boolean matchNameAndVersion(IPojoFactory factory) {
String component = (String) m_configuration.get("component");
- return factory.getName().equals(component) || factory.getClassName().equalsIgnoreCase(component);
+ String v = (String) m_configuration.get("factory.version");
+ if (v == null) {
+ return factory.getName().equals(component) || factory.getClassName().equalsIgnoreCase(component);
+ } else {
+ return (factory.getName().equals(component) || factory.getClassName().equalsIgnoreCase(component))
+ && v.equals(factory.getVersion());
+ }
}
/**
- * Checks if the given factory match with the factory
- * required by this instance. A factory matches if its
- * name or its class name is equals to the 'component'
- * property of the instance. Then the acceptability of
+ * Checks if the given factory match with the factory
+ * required by this instance. A factory matches if its
+ * name or its class name is equals to the 'component'
+ * property of the instance. Then the acceptability of
* the configuration is checked.
* @param factory the factory to confront against the current instance.
* @return <code>true</code> if the factory matches.
*/
public boolean match(IPojoFactory factory) {
// Test factory name (and classname)
- if (matchName(factory)) {
+ if (matchNameAndVersion(factory)) {
// Test factory accessibility
if (factory.m_isPublic || factory.getBundleContext().getBundle().getBundleId() == m_bundleId) {
// Test the configuration validity.
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/architecture/ComponentTypeDescription.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/architecture/ComponentTypeDescription.java
index cb26e98..8a636f4 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/architecture/ComponentTypeDescription.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/architecture/ComponentTypeDescription.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
@@ -50,7 +50,7 @@
* Represented factory.
*/
private final IPojoFactory m_factory;
-
+
/**
* Constructor.
* @param factory : represented factory.
@@ -58,7 +58,7 @@
public ComponentTypeDescription(IPojoFactory factory) {
m_factory = factory;
}
-
+
/**
* Gets the attached factory.
* @return the factory
@@ -86,6 +86,15 @@
}
/**
+ * Gets the component type version.
+ * @return the component type version or
+ * <code>null</code> if not set.
+ */
+ public String getVersion() {
+ return m_factory.getVersion();
+ }
+
+ /**
* Gets component-type properties.
* @return the list of configuration properties accepted by the component type type.
*/
@@ -101,7 +110,7 @@
public void addProperty(String name, String value) {
addProperty(name, value, false);
}
-
+
/**
* Adds a String property in the component type.
* @param name : property name.
@@ -118,8 +127,8 @@
* @param pd : the property to add
*/
public void addProperty(PropertyDescription pd) { //NOPMD remove the instance name of the 'name' property.
- String name = pd.getName();
-
+ String name = pd.getName();
+
// Check if the property is not already in the array
for (int i = 0; i < m_properties.length; i++) {
PropertyDescription desc = m_properties[i];
@@ -158,9 +167,9 @@
public String getName() {
return m_factory.getName();
}
-
+
/**
- * Computes the default service properties to publish :
+ * Computes the default service properties to publish :
* factory.name, service.pid, component.providedServiceSpecification, component.properties, component.description, factory.State.
* @return : the dictionary of properties to publish.
*/
@@ -170,10 +179,16 @@
props.put("factory.name", m_factory.getName());
props.put(Constants.SERVICE_PID, m_factory.getName()); // Service PID is required for the integration in the configuration admin.
+ // Add the version if set
+ String v = getVersion();
+ if (v != null) {
+ props.put("factory.version", v);
+ }
+
props.put("component.providedServiceSpecifications", m_providedServiceSpecification);
props.put("component.properties", m_properties);
props.put("component.description", this);
-
+
// add every immutable property
for (int i = 0; i < m_properties.length; i++) {
if (m_properties[i].isImmutable() && m_properties[i].getValue() != null) {
@@ -187,7 +202,7 @@
return props;
}
-
+
/**
* Gets the interfaces published by the factory.
* By default publish both {@link Factory} and {@link ManagedServiceFactory}.
@@ -196,7 +211,7 @@
public String[] getFactoryInterfacesToPublish() {
return new String[] {Factory.class.getName(), ManagedServiceFactory.class.getName()};
}
-
+
/**
* Gets the component type description.
* @return : the description
@@ -206,7 +221,7 @@
desc.addAttribute(new Attribute("name", m_factory.getName()));
desc.addAttribute(
- new Attribute("bundle",
+ new Attribute("bundle",
Long.toString(((ComponentFactory) m_factory).getBundleContext().getBundle().getBundleId())));
String state = "valid";
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 58f8091..4db3d6c 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
@@ -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
@@ -44,7 +44,7 @@
/**
* Provided Service represent a provided service by the component.
- *
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class ProvidedService implements ServiceFactory {
@@ -68,12 +68,12 @@
* Factory policy : SERVICE_FACTORY.
*/
public static final int SERVICE_STRATEGY = 1;
-
+
/**
* Factory policy : STATIC_FACTORY.
*/
public static final int STATIC_STRATEGY = 2;
-
+
/**
* Factory policy : INSTANCE.
* Creates one service object per instance consuming the service.
@@ -100,7 +100,7 @@
* Properties Array.
*/
private Property[] m_properties;
-
+
/**
* Service Object creation policy.
*/
@@ -108,7 +108,7 @@
/**
* Creates a provided service object.
- *
+ *
* @param handler the the provided service handler.
* @param specification the specifications provided by this provided service
* @param factoryPolicy the service providing policy
@@ -118,14 +118,18 @@
m_handler = handler;
m_serviceSpecification = specification;
-
- // Add instance name & factory name
+
+ // Add instance name, factory name and factory version is set.
try {
- addProperty(new Property("instance.name", null, null, handler.getInstanceManager().getInstanceName(), String.class.getName(), handler.getInstanceManager(), handler));
+ addProperty(new Property("instance.name", null, null, handler.getInstanceManager().getInstanceName(), String.class.getName(), handler.getInstanceManager(), handler));
addProperty(new Property("factory.name", null, null, handler.getInstanceManager().getFactory().getFactoryName(), String.class.getName(), handler.getInstanceManager(), handler));
+ if (handler.getInstanceManager().getFactory().getVersion() != null) {
+ addProperty(new Property("factory.version", null, null, handler.getInstanceManager().getFactory().getVersion(), String.class.getName(), handler.getInstanceManager(), handler));
+ }
} 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();
@@ -187,7 +191,7 @@
/**
* Add the given property to the property list.
- *
+ *
* @param prop : the element to add
*/
private synchronized void addProperty(Property prop) {
@@ -209,7 +213,7 @@
/**
* Remove a property.
- *
+ *
* @param name : the property to remove
*/
private synchronized void removeProperty(String name) {
@@ -261,7 +265,7 @@
/**
* The unget method.
- *
+ *
* @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle,
* org.osgi.framework.ServiceRegistration, java.lang.Object)
* @param bundle : bundle
@@ -274,10 +278,10 @@
/**
* Registers the service. The service object must be able to serve this
- * service.
+ * 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();
@@ -294,9 +298,9 @@
m_serviceRegistration.unregister();
m_serviceRegistration = null;
}
-
+
m_strategy.onUnpublication();
-
+
}
/**
@@ -318,7 +322,7 @@
/**
* Return the list of properties attached to this service. This list
* contains only property where a value are assigned.
- *
+ *
* @return the properties attached to the provided service.
*/
private Properties getServiceProperties() {
@@ -399,7 +403,7 @@
public ServiceRegistration getServiceRegistration() {
return m_serviceRegistration;
}
-
+
/**
* Singleton creation strategy.
* This strategy just creates one service object and
@@ -442,13 +446,13 @@
* @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) {
+ Object arg2) {
}
-
+
}
-
+
/**
- * Service object creation policy following the OSGi Service Factory
+ * Service object creation policy following the OSGi Service Factory
* policy {@link ServiceFactory}.
*/
private class FactoryStrategy extends CreationStrategy {
@@ -491,15 +495,15 @@
* @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) {
+ 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
+ * 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 {
@@ -510,17 +514,17 @@
/**
* A method is invoked on the proxy object.
- * If the method is the {@link IPOJOServiceFactory#getService(ComponentInstance)}
+ * 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.
+ * 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.
+ * 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',
+ * @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[])
@@ -529,12 +533,12 @@
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. ");
@@ -600,7 +604,7 @@
* @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(),
+ Object proxy = Proxy.newProxyInstance(getInstanceManager().getClazz().getClassLoader(),
getSpecificationsWithIPOJOServiceFactory(m_serviceSpecification, m_handler.getInstanceManager().getContext()), this);
return proxy;
}
@@ -615,7 +619,7 @@
*/
public void ungetService(Bundle arg0, ServiceRegistration arg1,
Object arg2) { }
-
+
/**
* Utility method returning the class array of provided service
* specification and the {@link IPOJOServiceFactory} interface.
@@ -637,8 +641,8 @@
classes[i] = IPOJOServiceFactory.class;
return classes;
}
-
-
+
+
}
}
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
index 643eaf6..f486c53 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.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
@@ -31,7 +31,7 @@
/**
* The Manifest Metadata parser reads a manifest file and builds
* the iPOJO metadata ({@link Element} / {@link Attribute} ) structure.
- *
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class ManifestMetadataParser {
@@ -79,7 +79,7 @@
/**
* Parses an Element to create an instance configuration dictionary.
* The 'name' attribute of the instance declaration is mapped
- * to the 'instance.name' property.
+ * to the 'instance.name' property.
* @param instance the Element describing an instance.
* @return the resulting dictionary
* @throws ParseException if a configuration cannot be parse correctly.
@@ -88,6 +88,8 @@
Dictionary dict = new Properties();
String name = instance.getAttribute("name");
String comp = instance.getAttribute("component");
+ String version = instance.getAttribute("version");
+
if (name != null) {
dict.put("instance.name", instance.getAttribute("name"));
}
@@ -97,6 +99,11 @@
}
dict.put("component", comp);
+
+ if (version != null) {
+ dict.put("factory.version", version);
+ }
+
Element[] props = instance.getElements("property");
for (int i = 0; props != null && i < props.length; i++) {
@@ -120,7 +127,7 @@
if (name == null) {
throw new ParseException("A property does not have the 'name' attribute: " + prop);
}
-
+
//case : the property element has no 'value' attribute
if (value == null) {
// Recursive case
@@ -145,19 +152,19 @@
obj = new Object[list.size()];
}
// Transform the list to array
- dict.put(name, list.toArray(obj));
+ dict.put(name, list.toArray(obj));
}
} else {
dict.put(prop.getAttribute("name"), prop.getAttribute("value"));
}
}
-
+
/**
- * Parses a complex property.
+ * Parses a complex property.
* This property will be built as a {@link Dictionary}.
* @param prop the Element to parse.
* @return the resulting dictionary
- * @throws ParseException if an internal property is incorrect.
+ * @throws ParseException if an internal property is incorrect.
*/
private Dictionary parseDictionary(Element prop) throws ParseException {
// Check if there is 'property' elements
@@ -173,9 +180,9 @@
return new Properties();
}
}
-
+
/**
- * Parses a complex property.
+ * Parses a complex property.
* This property will be built as a {@link Map}.
* The used {@link Map} implementation is {@link HashMap}.
* @param prop the property to parse
@@ -195,10 +202,10 @@
return new HashMap(0);
}
}
-
+
/**
* Parses a complex property. This property will be built as a {@link List}.
- * The used {@link List} implementation is {@link ArrayList}.
+ * The used {@link List} implementation is {@link ArrayList}.
* The order of elements is kept.
* @param prop the property to parse
* @return the resulting List
@@ -217,7 +224,7 @@
return new ArrayList(0);
}
}
-
+
/**
* Parse a property.
* This methods handles complex properties.
@@ -266,7 +273,7 @@
/**
* Parse an anonymous property.
* An anonymous property is a property with no name.
- * An anonymous property can be simple (just a value) or complex (i.e. a map, a dictionary
+ * An anonymous property can be simple (just a value) or complex (i.e. a map, a dictionary
* a list or an array).
* @param prop the property to parse
* @param list the list to populate with the resulting property
@@ -282,7 +289,7 @@
//case : the property element has no 'value' attribute
if (value == null) {
// Recursive case
-
+
// Get the type of the structure to create
String type = prop.getAttribute("type");
if (type == null || type.equalsIgnoreCase("dictionary")) {
@@ -314,7 +321,7 @@
Element[] subProps = prop.getElements("property");
if (subProps != null) {
// Create a list to store elements.
- List list2 = new ArrayList(subProps.length);
+ List list2 = new ArrayList(subProps.length);
for (int i = 0; i < subProps.length; i++) {
parseAnonymousProperty(subProps[i], list2); // Anonymous properties
}
@@ -342,7 +349,7 @@
} else {
list.add(prop.getAttribute("value"));
}
-
+
}
/**
@@ -384,7 +391,7 @@
/**
* Looks for the <code>iPOJO-Components</code> header
- * in the given dictionary. Then, initializes the
+ * in the given dictionary. Then, initializes the
* {@link ManifestMetadataParser#m_elements} list (adds the
* <code>iPOJO</code> root element) and parses the contained
* component type declarations and instance configurations.
@@ -399,9 +406,9 @@
}
/**
- * Parses the given header, initialized the
- * {@link ManifestMetadataParser#m_elements} list
- * (adds the <code>iPOJO</code> element) and parses
+ * Parses the given header, initialized the
+ * {@link ManifestMetadataParser#m_elements} list
+ * (adds the <code>iPOJO</code> element) and parses
* contained component type declarations and instance configurations.
* @param header the given header of the manifest file
* @throws ParseException if any error occurs
@@ -429,12 +436,12 @@
}
return parser.m_elements[0];
}
-
+
/**
* Parses the metadata from the given header string.
* This method creates a new {@link ManifestMetadataParser} object and then
* creates the <code>iPOJO</code> root element, parses content elements
- * (component types and instances declarations), and returns the resulting
+ * (component types and instances declarations), and returns the resulting
* {@link Element} / {@link Attribute} structure. The parsed string
* must be a tree (only one root element).
* @param header the header to parse
@@ -537,7 +544,7 @@
i = i + 1;
}
i = i + 1; // skip {
-
+
Element elem = null;
if (namespace == null) {
elem = new Element(name.toString(), null);
@@ -545,7 +552,7 @@
elem = new Element(name.toString(), namespace.toString());
}
addElement(elem);
-
+
break;
}
}
diff --git a/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/PrimitiveComponentTest.java b/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/PrimitiveComponentTest.java
index a0a3761..b954a27 100644
--- a/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/PrimitiveComponentTest.java
+++ b/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/PrimitiveComponentTest.java
@@ -4,7 +4,6 @@
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.provision;
@@ -35,28 +34,28 @@
@RunWith( JUnit4TestRunner.class )
public class PrimitiveComponentTest {
-
+
@Inject
private BundleContext context;
-
+
private OSGiHelper osgi;
-
+
private IPOJOHelper ipojo;
-
+
@Before
public void init() {
osgi = new OSGiHelper(context);
ipojo = new IPOJOHelper(context);
}
-
+
@After
public void stop() {
ipojo.dispose();
osgi.dispose();
}
-
+
@Configuration
- public static Option[] configure() {
+ public static Option[] configure() {
Option[] opt = options(
provision(
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo").version(asInProject()),
@@ -79,7 +78,7 @@
assertThat(ref, is(notNullValue()));
}
-
+
@Test
public void killTheFactory() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
assertThat( context, is( notNullValue() ) );
@@ -99,7 +98,7 @@
assertThat(ref, is(nullValue()));
}
-
+
@Test
public void createAServiceCons() throws Exception {
assertThat( context, is( notNullValue() ) );
@@ -111,45 +110,45 @@
is(ComponentInstance.INVALID));
}
-
+
@Test
public void createBoth() throws Exception {
ComponentInstance cons = createAConsumer().createInstance();
// cons is invalid
assertThat("cons is invalid", cons.getState(), is(ComponentInstance.INVALID));
-
+
ComponentInstance prov = createAProvider().createInstance();
assertThat("prov is valid", prov.getState(), is(ComponentInstance.VALID));
assertThat("cons is valid", cons.getState(), is(ComponentInstance.VALID));
}
-
+
@Test
public void createTwoCons() throws Exception {
ComponentInstance cons1 = createAConsumer().createInstance();
// cons is invalid
assertThat("cons is invalid", cons1.getState(), is(ComponentInstance.INVALID));
-
+
ComponentInstance prov = createAProvider().createInstance();
assertThat("prov is valid", prov.getState(), is(ComponentInstance.VALID));
assertThat("cons is valid", cons1.getState(), is(ComponentInstance.VALID));
-
+
ComponentInstance cons2 = createAnOptionalConsumer().createInstance();
-
+
assertThat("cons2 is valid", cons2.getState(), is(ComponentInstance.VALID));
-
+
prov.stop();
assertThat("cons is invalid", cons1.getState(), is(ComponentInstance.INVALID));
assertThat("cons2 is valid", cons2.getState(), is(ComponentInstance.VALID));
}
-
+
private PrimitiveComponentType createAProvider() {
return new PrimitiveComponentType()
.setBundleContext(context)
.setClassName(FooImpl.class.getName())
.addService(new Service()); // Provide the FooService
}
-
+
private PrimitiveComponentType createAConsumer() {
return new SingletonComponentType()
.setBundleContext(context)
@@ -157,7 +156,7 @@
.addDependency(new Dependency().setField("myFoo"))
.setValidateMethod("start");
}
-
+
private PrimitiveComponentType createAnOptionalConsumer() {
return new SingletonComponentType()
.setBundleContext(context)
diff --git a/ipojo/tests/composite/composite-runtime/src/main/java/org/apache/felix/ipojo/test/composite/infrastructure/FactoryManagementTest.java b/ipojo/tests/composite/composite-runtime/src/main/java/org/apache/felix/ipojo/test/composite/infrastructure/FactoryManagementTest.java
index c70b643..cf21a25 100644
--- a/ipojo/tests/composite/composite-runtime/src/main/java/org/apache/felix/ipojo/test/composite/infrastructure/FactoryManagementTest.java
+++ b/ipojo/tests/composite/composite-runtime/src/main/java/org/apache/felix/ipojo/test/composite/infrastructure/FactoryManagementTest.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
@@ -37,17 +37,17 @@
import org.osgi.framework.ServiceRegistration;
public class FactoryManagementTest extends OSGiTestCase {
-
+
private FakeFactory fake1 = new FakeFactory("fake");
private FakeFactory fake2 = new FakeFactory("fake2");
-
+
private Factory emptyFactory;
private ComponentInstance empty;
-
+
private class FakeFactory implements Factory {
-
+
private String m_name;
- public FakeFactory(String name) { m_name = name; }
+ public FakeFactory(String name) { m_name = name; }
public ComponentInstance createComponentInstance(Dictionary arg0) throws UnacceptableConfiguration { return null; }
public ComponentInstance createComponentInstance(Dictionary arg0, ServiceContext arg1) throws UnacceptableConfiguration { return null; }
@@ -63,9 +63,10 @@
public String getClassName() { return ""; }
public int getState() { return Factory.VALID; }
public BundleContext getBundleContext() { return getContext(); }
+ public String getVersion() { return null; }
}
-
+
public void setUp() {
emptyFactory = Utils.getFactoryByName(getContext(), "composite.empty");
Properties props = new Properties();
@@ -74,30 +75,30 @@
empty = emptyFactory.createComponentInstance(props);
} catch (Exception e) { fail("Cannot create empty instance " + e.getMessage()); }
}
-
+
public void tearDown() {
empty.dispose();
empty = null;
}
-
+
public void testOneLevelExposition() {
ServiceReference[] parentsFactoryReferences = Utils.getServiceReferences(getContext(), Factory.class.getName(), null);
ServiceContext sc = Utils.getServiceContext(empty);
ServiceReference[] internalFactoryReferences = Utils.getServiceReferences(sc, Factory.class.getName(), null);
-
+
assertEquals("Check the number of available factories", parentsFactoryReferences.length, internalFactoryReferences.length);
-
+
for(int i = 0; i < parentsFactoryReferences.length; i++) {
Factory factory = (Factory) getContext().getService(parentsFactoryReferences[i]);
assertTrue("Check the avaibility of " + factory.getName(), isExposed(factory, internalFactoryReferences, sc));
}
}
-
+
public void testTwoLevelExposition() {
ServiceReference[] parentsFactoryReferences = Utils.getServiceReferences(getContext(), Factory.class.getName(), null);
ServiceContext sc1 = Utils.getServiceContext(empty);
ServiceReference[] Level1FactoryReferences = Utils.getServiceReferences(sc1, Factory.class.getName(), null);
-
+
Factory fact = Utils.getFactoryByName(sc1, "composite.empty");
Properties p = new Properties();
p.put("instance.name","empty2");
@@ -107,27 +108,27 @@
} catch (Exception e) {
fail("Cannot instantiate empty2 instance : " + e.getMessage());
}
-
+
ServiceContext sc2 = Utils.getServiceContext(empty2);
ServiceReference[] Level2FactoryReferences = Utils.getServiceReferences(sc2, Factory.class.getName(), null);
-
+
assertEquals("Check the number of available factories - 1", parentsFactoryReferences.length, Level1FactoryReferences.length);
assertEquals("Check the number of available factories - 2", parentsFactoryReferences.length, Level2FactoryReferences.length);
assertEquals("Check the number of available factories - 3", Level1FactoryReferences.length, Level2FactoryReferences.length);
-
+
for(int i = 0; i < Level1FactoryReferences.length; i++) {
Factory factory = (Factory) getContext().getService(parentsFactoryReferences[i]);
assertTrue("Check the avaibility of " + factory.getName(), isExposed(factory, Level2FactoryReferences, sc2));
}
-
+
empty2.dispose();
}
-
+
public void testDynamism() {
ServiceReference[] parentsFactoryReferences = Utils.getServiceReferences(getContext(), Factory.class.getName(), null);
ServiceContext sc1 = Utils.getServiceContext(empty);
ServiceReference[] Level1FactoryReferences = Utils.getServiceReferences(sc1, Factory.class.getName(), null);
-
+
Factory fact = Utils.getFactoryByName(sc1, "composite.empty");
Properties p = new Properties();
p.put("instance.name","empty2");
@@ -137,74 +138,74 @@
} catch (Exception e) {
fail("Cannot instantiate empty2 instance : " + e.getMessage());
}
-
+
ServiceContext sc2 = Utils.getServiceContext(empty2);
ServiceReference[] Level2FactoryReferences = Utils.getServiceReferences(sc2, Factory.class.getName(), null);
-
+
assertEquals("Check the number of available factories - 1", parentsFactoryReferences.length, Level1FactoryReferences.length);
assertEquals("Check the number of available factories - 2", parentsFactoryReferences.length, Level2FactoryReferences.length);
assertEquals("Check the number of available factories - 3", Level1FactoryReferences.length, Level2FactoryReferences.length);
-
+
for(int i = 0; i < Level1FactoryReferences.length; i++) {
Factory factory = (Factory) getContext().getService(parentsFactoryReferences[i]);
assertTrue("Check the avaibility of " + factory.getName(), isExposed(factory, Level2FactoryReferences, sc2));
}
-
+
// Publish fake1
ServiceRegistration reg1 = getContext().registerService(Factory.class.getName(), fake1, null);
-
+
parentsFactoryReferences = Utils.getServiceReferences(getContext(), Factory.class.getName(), null);
sc1 = Utils.getServiceContext(empty);
Level1FactoryReferences = Utils.getServiceReferences(sc1, Factory.class.getName(), null);
sc2 = Utils.getServiceContext(empty2);
Level2FactoryReferences = Utils.getServiceReferences(sc2, Factory.class.getName(), null);
-
+
assertEquals("Check the number of available factories - 1.1", parentsFactoryReferences.length, Level1FactoryReferences.length);
assertEquals("Check the number of available factories - 1.2", parentsFactoryReferences.length, Level2FactoryReferences.length);
assertEquals("Check the number of available factories - 1.3", Level1FactoryReferences.length, Level2FactoryReferences.length);
-
+
// Publish fake2
ServiceRegistration reg2 = getContext().registerService(Factory.class.getName(), fake2, null);
-
+
parentsFactoryReferences = Utils.getServiceReferences(getContext(), Factory.class.getName(), null);
sc1 = Utils.getServiceContext(empty);
Level1FactoryReferences = Utils.getServiceReferences(sc1, Factory.class.getName(), null);
sc2 = Utils.getServiceContext(empty2);
Level2FactoryReferences = Utils.getServiceReferences(sc2, Factory.class.getName(), null);
-
+
assertEquals("Check the number of available factories - 1.1", parentsFactoryReferences.length, Level1FactoryReferences.length);
assertEquals("Check the number of available factories - 1.2", parentsFactoryReferences.length, Level2FactoryReferences.length);
assertEquals("Check the number of available factories - 1.3", Level1FactoryReferences.length, Level2FactoryReferences.length);
-
+
reg1.unregister();
-
+
parentsFactoryReferences = Utils.getServiceReferences(getContext(), Factory.class.getName(), null);
sc1 = Utils.getServiceContext(empty);
Level1FactoryReferences = Utils.getServiceReferences(sc1, Factory.class.getName(), null);
sc2 = Utils.getServiceContext(empty2);
Level2FactoryReferences = Utils.getServiceReferences(sc2, Factory.class.getName(), null);
-
+
assertEquals("Check the number of available factories - 1.1", parentsFactoryReferences.length, Level1FactoryReferences.length);
assertEquals("Check the number of available factories - 1.2", parentsFactoryReferences.length, Level2FactoryReferences.length);
assertEquals("Check the number of available factories - 1.3", Level1FactoryReferences.length, Level2FactoryReferences.length);
-
+
reg2.unregister();
-
+
parentsFactoryReferences = Utils.getServiceReferences(getContext(), Factory.class.getName(), null);
sc1 = Utils.getServiceContext(empty);
Level1FactoryReferences = Utils.getServiceReferences(sc1, Factory.class.getName(), null);
sc2 = Utils.getServiceContext(empty2);
Level2FactoryReferences = Utils.getServiceReferences(sc2, Factory.class.getName(), null);
-
+
assertEquals("Check the number of available factories - 1.1", parentsFactoryReferences.length, Level1FactoryReferences.length);
assertEquals("Check the number of available factories - 1.2", parentsFactoryReferences.length, Level2FactoryReferences.length);
assertEquals("Check the number of available factories - 1.3", Level1FactoryReferences.length, Level2FactoryReferences.length);
-
+
empty2.dispose();
}
-
+
public void testInvocation() {
- ServiceContext sc1 = Utils.getServiceContext(empty);
+ ServiceContext sc1 = Utils.getServiceContext(empty);
Factory fact = Utils.getFactoryByName(sc1, "composite.empty");
Properties p = new Properties();
p.put("instance.name","empty2");
@@ -214,9 +215,9 @@
} catch (Exception e) {
fail("Cannot instantiate empty2 instance : " + e.getMessage());
}
-
+
ServiceContext sc2 = Utils.getServiceContext(empty2);
-
+
Factory fact1 = Utils.getFactoryByName(sc2, "COMPO-SimpleCheckServiceProvider");
Properties props = new Properties();
props.put("instance.name","client");
@@ -224,7 +225,7 @@
try {
client = fact1.createComponentInstance(props);
} catch (Exception e) { e.printStackTrace(); fail("Cannot instantiate the client : " + e.getMessage()); }
-
+
Factory fact2 = Utils.getFactoryByName(sc2, "COMPO-FooProviderType-1");
Properties props2 = new Properties();
props2.put("instance.name","provider");
@@ -234,26 +235,26 @@
} catch (Exception e) {
fail("Cannot instantiate the provider : " + e.getMessage());
}
-
- ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
+
+ ServiceReference ref = sc2.getServiceReference(CheckService.class.getName());
assertNotNull("Check ref existency", ref);
CheckService check = (CheckService) sc2.getService(ref);
-
+
assertTrue("Check invocation", check.check());
client.dispose();
provider.dispose();
empty2.dispose();
}
-
-
-
-
+
+
+
+
private boolean isExposed(Factory fact, ServiceReference[] refs, ServiceContext sc) {
for(int i = 0; i < refs.length; i++) {
Factory f = (Factory) sc.getService(refs[i]);
if(fact.getName().equals(f.getName())) {
sc.ungetService(refs[i]);
- return true;
+ return true;
}
sc.ungetService(refs[i]);
}
diff --git a/ipojo/tests/core/factory-version/instances.xml b/ipojo/tests/core/factory-version/instances.xml
new file mode 100644
index 0000000..cda4486
--- /dev/null
+++ b/ipojo/tests/core/factory-version/instances.xml
@@ -0,0 +1,20 @@
+<ipojo>
+
+ <instance component="org.apache.felix.ipojo.tests.core.component.MyComponent"
+ version="1.0"
+ name="instance-v1"
+ />
+
+ <instance component="org.apache.felix.ipojo.tests.core.component.MyComponent"
+ version="1.1"
+ name="instance-v1.1"
+ />
+
+ <instance component="org.apache.felix.ipojo.tests.core.component.MyComponent"
+ name="instance-any"
+ />
+
+ <instance component="MyComponent"
+ name="MyComponentInstance"
+ />
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/tests/core/factory-version/pom.xml b/ipojo/tests/core/factory-version/pom.xml
new file mode 100644
index 0000000..af28557
--- /dev/null
+++ b/ipojo/tests/core/factory-version/pom.xml
@@ -0,0 +1,122 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>ipojo.tests</groupId>
+ <artifactId>tests.core.factory-version</artifactId>
+ <name>iPOJO Factory Version Test Suite</name>
+ <version>1.3.0-SNAPSHOT</version>
+ <description>Test the factory version attribute</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-depends-file</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- <plugin>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>maven-paxexam-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-paxexam-config</id>
+ <goals>
+ <goal>generate-paxexam-config</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <settings>
+ <platform>felix</platform>
+ </settings>
+ </configuration>
+ </plugin> -->
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ </dependency>
+
+ <!--
+ Pax Exam API:
+ -->
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam</artifactId>
+ <version>0.4.0</version>
+ </dependency>
+ <!--
+ During runtime Pax Exam will discover the OSGi container to use by
+ searching metadata available into classpath. Pax Exam comes with a
+ default container that uses [Pax Runner] for implementing the
+ container requirements:
+ -->
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-default
+ </artifactId>
+ <version>0.4.0</version>
+ </dependency>
+ <!--
+ If your test code is based on JUnit you will have to have the Junit
+ support artifact:
+ -->
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit</artifactId>
+ <version>0.4.0</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.5</version>
+ <type>jar</type>
+ <scope>test</scope>
+ </dependency>
+ <!-- Tinybundles -->
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>pax-tinybundles-core</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.pax.exam.target</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+
+ <repositories>
+ <repository>
+ <id>ops4j.releases</id>
+ <name>OPS4J Release</name>
+ <url> http://repository.ops4j.org/maven2/</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/tests/core/factory-version/provider-v1.1.xml b/ipojo/tests/core/factory-version/provider-v1.1.xml
new file mode 100644
index 0000000..77d4fdf
--- /dev/null
+++ b/ipojo/tests/core/factory-version/provider-v1.1.xml
@@ -0,0 +1,5 @@
+<ipojo>
+ <component classname="org.apache.felix.ipojo.tests.core.component.MyComponent" version="BuNdlE">
+ <provides/>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/tests/core/factory-version/provider-v1.xml b/ipojo/tests/core/factory-version/provider-v1.xml
new file mode 100644
index 0000000..24ce4c8
--- /dev/null
+++ b/ipojo/tests/core/factory-version/provider-v1.xml
@@ -0,0 +1,10 @@
+<ipojo>
+ <component classname="org.apache.felix.ipojo.tests.core.component.MyComponent" version="1.0">
+ <provides/>
+ </component>
+
+
+ <component classname="org.apache.felix.ipojo.tests.core.component.MyComponent" name="MyComponent">
+ <provides/>
+ </component>
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java
new file mode 100644
index 0000000..0148684
--- /dev/null
+++ b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java
@@ -0,0 +1,179 @@
+package org.apache.felix.ipojo.tests.core;
+
+import static org.apache.felix.ipojo.pax.exam.target.BundleAsiPOJO.asiPOJOBundle;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.asURL;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.newBundle;
+import static org.ops4j.pax.tinybundles.core.TinyBundles.with;
+
+import java.io.File;
+
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.tests.core.component.MyComponent;
+import org.apache.felix.ipojo.tests.core.service.MyService;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Inject;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+@RunWith( JUnit4TestRunner.class )
+public class FactoryVersionTest {
+
+ @Inject
+ private BundleContext context;
+
+ private OSGiHelper osgi;
+
+ private IPOJOHelper ipojo;
+
+ @Before
+ public void init() {
+ osgi = new OSGiHelper(context);
+ ipojo = new IPOJOHelper(context);
+ }
+
+ @After
+ public void stop() {
+ ipojo.dispose();
+ osgi.dispose();
+ }
+
+ @Configuration
+ public static Option[] configure() {
+
+ File tmp = new File("target/tmp");
+ tmp.mkdirs();
+
+ Option[] opt = options(
+ provision(
+ // Runtime.
+ mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo").version(asInProject()),
+ mavenBundle().groupId( "org.ops4j.pax.tinybundles" ).artifactId( "pax-tinybundles-core" ).version(asInProject())
+ ),
+ provision(
+ newBundle()
+ .addClass( MyService.class )
+ .prepare()
+ .set(Constants.BUNDLE_SYMBOLICNAME,"ServiceInterface")
+ .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
+ .build( asURL() ).toExternalForm()
+ ),
+ provision(
+ // Component V1
+ newBundle()
+ .addClass(MyComponent.class)
+ .prepare(
+ with()
+ .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV1")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
+ )
+ .build( asiPOJOBundle(new File(tmp, "provider-v1.jar"), new File("provider-v1.xml"))).toExternalForm(),
+ // Component V1.1 (Bundle Version)
+ newBundle()
+ .addClass(MyComponent.class)
+ .prepare(
+ with()
+ .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV1.1")
+ .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
+ .set(Constants.BUNDLE_VERSION, "1.1")
+ )
+ .build( asiPOJOBundle(new File(tmp, "provider-v1.1.jar"), new File("provider-v1.1.xml"))).toExternalForm(),
+ // Instance declaration
+ newBundle()
+ .prepare(
+ with()
+ .set(Constants.BUNDLE_SYMBOLICNAME,"Instances")
+ )
+ .build( asiPOJOBundle(new File(tmp, "instances.jar"), new File("instances.xml"))).toExternalForm()
+
+ )
+ );
+ return opt;
+ }
+
+ @Test
+ public void testDeploy() {
+ Bundle[] bundles = context.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ Assert.assertEquals(bundles[i].getSymbolicName() + " is not active", Bundle.ACTIVE, bundles[i].getState());
+ }
+ }
+
+ @Test
+ public void testInstanceArchitecture() {
+ // Version 1.0
+ ServiceReference refv1 = ipojo.getServiceReferenceByName(Architecture.class.getName(), "instance-v1");
+ Assert.assertNotNull(refv1);
+ Architecture archv1 = (Architecture) osgi.getServiceObject(refv1);
+
+ String version = archv1.getInstanceDescription().getComponentDescription().getVersion();
+ Assert.assertEquals("1.0", version);
+
+ // Version 1.1
+ ServiceReference refv11 = ipojo.getServiceReferenceByName(Architecture.class.getName(), "instance-v1.1");
+ Assert.assertNotNull(refv11);
+ Architecture archv11 = (Architecture) osgi.getServiceObject(refv11);
+
+ String version11 = archv11.getInstanceDescription().getComponentDescription().getVersion();
+ Assert.assertEquals("1.1", version11);
+
+ // No Version
+ ServiceReference refany = ipojo.getServiceReferenceByName(Architecture.class.getName(), "instance-any");
+ Assert.assertNotNull(refany);
+ Architecture archany = (Architecture) osgi.getServiceObject(refany);
+
+ String any = archany.getInstanceDescription().getComponentDescription().getVersion();
+ Assert.assertNotNull(any);
+
+ // No version set in the factory, so no version.
+ ServiceReference refmci = ipojo.getServiceReferenceByName(Architecture.class.getName(), "MyComponentInstance");
+ Assert.assertNotNull(refmci);
+ Architecture archmcy = (Architecture) osgi.getServiceObject(refmci);
+
+ String mci = archmcy.getInstanceDescription().getComponentDescription().getVersion();
+ Assert.assertNull(mci);
+
+ }
+
+ @Test
+ public void testServiceProperty() {
+ // Version 1.0
+ ServiceReference refv1 = ipojo.getServiceReferenceByName(MyService.class.getName(), "instance-v1");
+ Assert.assertNotNull(refv1);
+ String version = (String) refv1.getProperty("factory.version");
+ Assert.assertEquals("1.0", version);
+
+ // Version 1.1
+ ServiceReference refv11 = ipojo.getServiceReferenceByName(MyService.class.getName(), "instance-v1.1");
+ Assert.assertNotNull(refv11);
+ String version11 = (String) refv11.getProperty("factory.version");
+
+ Assert.assertEquals("1.1", version11);
+
+ // No Version
+ ServiceReference refany = ipojo.getServiceReferenceByName(MyService.class.getName(), "instance-any");
+ Assert.assertNotNull(refany);
+ String any = (String) refany.getProperty("factory.version");
+ Assert.assertNotNull(any);
+
+ // No version set in the factory, so no version.
+ ServiceReference refmci = ipojo.getServiceReferenceByName(MyService.class.getName(), "MyComponentInstance");
+ Assert.assertNotNull(refmci);
+ String mci = (String) refmci.getProperty("factory.version");
+ Assert.assertNull(mci);
+ }
+
+
+}
diff --git a/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/IPOJOHelper.java b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/IPOJOHelper.java
new file mode 100644
index 0000000..7755c08
--- /dev/null
+++ b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/IPOJOHelper.java
@@ -0,0 +1,730 @@
+/*
+ * 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.tests.core;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.HandlerFactory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ManagedServiceFactory;
+
+/**
+ * iPOJO Helper.
+ * This helper helps getting {@link Factory}, and managing
+ * {@link ComponentInstance}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class IPOJOHelper {
+
+ /**
+ * The bundle context.
+ */
+ private BundleContext m_context;
+
+
+ /**
+ * List of instances.
+ */
+ private List<ComponentInstance> m_instances;
+
+ /**
+ * Creates a IPOJOHelper.
+ * @param tc the OSGi Test Case
+ */
+ public IPOJOHelper(BundleContext context) {
+ m_context = context;
+ m_instances = new ArrayList<ComponentInstance>();
+ }
+
+ /**
+ * Disposes created instances.
+ * @see org.apache.felix.ipojo.junit4osgi.Helper#dispose()
+ */
+ public void dispose() {
+ for (int i = 0; i < m_instances.size(); i++) {
+ ((ComponentInstance) m_instances.get(i)).dispose();
+ }
+ m_instances.clear();
+ }
+
+ /**
+ * Gets a created instance from the instance name.
+ * @param name the instance name.
+ * @return the created {@link ComponentInstance} or <code>null</code>
+ * if the instance was not created during the session.
+ */
+ public ComponentInstance getInstanceByName(String name) {
+ for (int i = 0; i < m_instances.size(); i++) {
+ if (((ComponentInstance) m_instances.get(i)).getInstanceName()
+ .equals(name)) {
+ return (ComponentInstance) m_instances.get(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new component instance with the given name (and empty
+ * configuration), from the factory specified in the given bundle.
+ *
+ * @param bundle the bundle from which the component factory is defined.
+ * @param factoryName the name of the component factory, defined in the
+ * specified bundle.
+ * @param instanceName the name of the component instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(Bundle bundle,
+ String factoryName, String instanceName) {
+
+ // Create the instance configuration
+ Properties configuration = new Properties();
+ configuration.put("instance.name", instanceName);
+
+ return createComponentInstance(bundle, factoryName, configuration);
+ }
+
+ /**
+ * Creates a new component instance with the given configuration, from the
+ * factory specified in the given bundle.
+ *
+ * @param bundle the bundle from which the component factory is defined.
+ * @param factoryName the name of the component factory, defined in the
+ * specified bundle.
+ * @param configuration the configuration of the component instance to
+ * create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(Bundle bundle,
+ String factoryName, Dictionary configuration) {
+
+ // Retrieve the component factory.
+ Factory fact = getFactory(bundle, factoryName);
+
+ if (fact == null) {
+ // Factory not found...
+ throw new IllegalArgumentException(
+ "Cannot find the component factory (" + factoryName
+ + ") in the specified bundle ("
+ + bundle.getSymbolicName() + ").");
+ }
+
+ try {
+ return fact.createComponentInstance(configuration);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Cannot create the component instance with the given configuration:"
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a new component instance with the given name and configuration,
+ * from the factory specified in the given bundle.
+ *
+ * @param bundle the bundle from which the component factory is defined.
+ * @param factoryName the name of the component factory, defined in the
+ * specified bundle.
+ * @param instanceName the name of the component instance to create.
+ * @param configuration the configuration of the instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(Bundle bundle,
+ String factoryName, String instanceName, Dictionary configuration) {
+
+ // Add the instance name to the configuration
+ configuration.put("instance.name", instanceName);
+
+ return createComponentInstance(bundle, factoryName, configuration);
+ }
+
+ /**
+ * Creates a new component instance with the given name (and an empty
+ * configuration), from the factory specified in the given service context.
+ *
+ * @param serviceContext the service context in which the component factory
+ * service is registered.
+ * @param factoryName the name of the component factory, defined in the
+ * specified service context.
+ * @param instanceName the name of the component instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(
+ ServiceContext serviceContext, String factoryName,
+ String instanceName) {
+
+ // Create the instance configuration
+ Properties configuration = new Properties();
+ configuration.put("instance.name", instanceName);
+
+ return createComponentInstance(serviceContext, factoryName,
+ configuration);
+ }
+
+ /**
+ * Creates a new component instance with the given name and configuration,
+ * from the factory specified in the given service context.
+ *
+ * @param serviceContext the service context in which the component factory
+ * service is registered.
+ * @param factoryName the name of the component factory, defined in the
+ * specified service context.
+ * @param configuration the configuration of the instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(
+ ServiceContext serviceContext, String factoryName,
+ Dictionary configuration) {
+
+ // Retrieve the component factory.
+ Factory fact = getFactory(serviceContext, factoryName);
+
+ if (fact == null) {
+ // Factory not found...
+ throw new IllegalArgumentException(
+ "Cannot find the component factory (" + factoryName
+ + ") in the specified service context.");
+ }
+
+ try {
+ return fact.createComponentInstance(configuration);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Cannot create the component instance with the given configuration: "
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a new component instance with the given name and configuration,
+ * from the factory specified in the given service context.
+ *
+ * @param serviceContext the service context in which the component factory
+ * service is registered.
+ * @param factoryName the name of the component factory, defined in the
+ * specified service context.
+ * @param instanceName the name of the component instance to create.
+ * @param configuration the configuration of the instance to create.
+ * @return the newly created component instance.
+ */
+ public static ComponentInstance createComponentInstance(
+ ServiceContext serviceContext, String factoryName,
+ String instanceName, Dictionary configuration) {
+
+ // Add the instance name to the configuration
+ configuration.put("instance.name", instanceName);
+
+ return createComponentInstance(serviceContext, factoryName,
+ configuration);
+ }
+
+ /**
+ * Creates a new component instance with the given name (and empty
+ * configuration), from the factory specified in the local bundle.
+ *
+ * @param factoryName the name of the component factory, defined in the
+ * local bundle.
+ * @param instanceName the name of the component instance to create.
+ * @return the newly created component instance.
+ */
+ public ComponentInstance createComponentInstance(String factoryName,
+ String instanceName) {
+ ComponentInstance ci = createComponentInstance(m_context.getBundle(),
+ factoryName, instanceName);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Creates a new component instance with the given configuration, from the
+ * factory specified in the local bundle.
+ *
+ * @param factoryName the name of the component factory, in the local
+ * bundle.
+ * @param configuration the configuration of the component instance to
+ * create.
+ * @return the newly created component instance.
+ */
+ public ComponentInstance createComponentInstance(String factoryName,
+ Dictionary configuration) {
+ ComponentInstance ci = createComponentInstance(m_context.getBundle(),
+ factoryName, configuration);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Creates a new component instance with no configuration, from the factory
+ * specified in the local bundle.
+ *
+ * @param factoryName the name of the component factory, in the local
+ * bundle.
+ * @return the newly created component instance.
+ */
+ public ComponentInstance createComponentInstance(String factoryName) {
+ ComponentInstance ci = createComponentInstance(m_context.getBundle(),
+ factoryName, (Dictionary) null);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Creates a new component instance with the given name and configuration,
+ * from the factory specified in the given bundle.
+ *
+ * @param factoryName the name of the component factory, defined in the
+ * specified bundle.
+ * @param instanceName the name of the component instance to create.
+ * @param configuration the configuration of the instance to create.
+ * @return the newly created component instance.
+ */
+ public ComponentInstance createComponentInstance(String factoryName,
+ String instanceName, Dictionary configuration) {
+ ComponentInstance ci = createComponentInstance(m_context.getBundle(),
+ factoryName, instanceName, configuration);
+ m_instances.add(ci);
+ return ci;
+ }
+
+ /**
+ * Returns the component factory with the given name in the local bundle.
+ *
+ * @param factoryName the name of the factory to retrieve.
+ * @return the component factory with the given name in the local bundle, or
+ * {@code null} if not found.
+ */
+ public Factory getFactory(String factoryName) {
+ return getFactory(m_context.getBundle(), factoryName);
+ }
+
+ /**
+ * Returns the handler factory with the given name in the local bundle.
+ *
+ * @param factoryName the name of the handler factory to retrieve.
+ * @return the handler factory with the given name in the local bundle, or
+ * {@code null} if not found.
+ */
+ public HandlerFactory getHandlerFactory(String factoryName) {
+ return getHandlerFactory(m_context.getBundle(), factoryName);
+ }
+
+ /**
+ * Returns the metadata description of the component defined in this bundle.
+ *
+ * @param component the name of the locally defined component.
+ * @return the metadata description of the component with the given name,
+ * defined in this given bundle, or {@code null} if not found.
+ */
+ public Element getMetadata(String component) {
+ return getMetadata(m_context.getBundle(), component);
+ }
+
+ /**
+ * Returns the component factory with the given name in the given bundle.
+ *
+ * @param bundle the bundle from which the component factory is defined.
+ * @param factoryName the name of the defined factory.
+ * @return the component factory with the given name in the given bundle, or
+ * {@code null} if not found.
+ */
+ public static Factory getFactory(Bundle bundle, String factoryName) {
+ ServiceReference[] refs;
+ try {
+ // Retrieves the component factories services in the bundle.
+ refs = bundle.getBundleContext().getServiceReferences(
+ Factory.class.getName(),
+ "(factory.name=" + factoryName + ")");
+ if (refs != null) {
+ return (Factory) bundle.getBundleContext().getService(refs[0]);
+ }
+
+ // Factory not found...
+ return null;
+
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(
+ "Cannot get the component factory services: "
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the component factory with the given name, registered in the
+ * given service context.
+ *
+ * @param serviceContext the service context in which the factory service is
+ * defined.
+ * @param factoryName the name of the factory.
+ * @return the component factory with the given name, registered in the
+ * given service context.
+ */
+ public static Factory getFactory(ServiceContext serviceContext,
+ String factoryName) {
+ ServiceReference[] refs;
+ try {
+ // Retrieves the component factories services in the service
+ // context.
+ refs = serviceContext.getServiceReferences(Factory.class.getName(),
+ "(factory.name=" + factoryName + ")");
+ if (refs != null) {
+ return (Factory) serviceContext.getService(refs[0]);
+ }
+ return null;
+
+ } catch (InvalidSyntaxException e) {
+ System.err.println("Cannot get the factory " + factoryName + " : "
+ + e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * Returns the handler factory with the given name in the given bundle.
+ *
+ * @param bundle the bundle from which the handler factory is defined.
+ * @param factoryName the name of the handler factory to retrieve.
+ * @return the handler factory with the given name in the given bundle, or
+ * {@code null} if not found.
+ */
+ public static HandlerFactory getHandlerFactory(Bundle bundle,
+ String factoryName) {
+ ServiceReference[] refs;
+ try {
+ // Retrieves the handler factories services in the bundle.
+ refs = bundle.getBundleContext().getServiceReferences(
+ HandlerFactory.class.getName(),
+ "(" + Handler.HANDLER_NAME_PROPERTY + "=" + factoryName
+ + ")");
+ if (refs != null) {
+ return (HandlerFactory) bundle.getBundleContext().getService(
+ refs[0]);
+ }
+
+ // Factory not found...
+ return null;
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(
+ "Cannot get the handler factory services: "
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the metadata description of the component with the given name,
+ * defined in the given bundle.
+ *
+ * @param bundle the bundle from which the component is defined.
+ * @param component the name of the defined component.
+ * @return the metadata description of the component with the given name,
+ * defined in the given bundle, or {@code null} if not found.
+ */
+ public static Element getMetadata(Bundle bundle, String component) {
+
+ // Retrieves the component description from the bundle's manifest.
+ String elem = (String) bundle.getHeaders().get("iPOJO-Components");
+ if (elem == null) {
+ throw new IllegalArgumentException(
+ "Cannot find iPOJO-Components descriptor in the specified bundle ("
+ + bundle.getSymbolicName()
+ + "). Not an iPOJO bundle.");
+ }
+
+ // Parses the retrieved description and find the component with the
+ // given name.
+ try {
+ Element element = ManifestMetadataParser.parseHeaderMetadata(elem);
+ Element[] childs = element.getElements("component");
+ for (int i = 0; i < childs.length; i++) {
+ String name = childs[i].getAttribute("name");
+ String clazz = childs[i].getAttribute("classname");
+ if (name != null && name.equalsIgnoreCase(component)) {
+ return childs[i];
+ }
+ if (clazz.equalsIgnoreCase(component)) {
+ return childs[i];
+ }
+ }
+
+ // Component not found...
+ return null;
+
+ } catch (ParseException e) {
+ throw new IllegalStateException(
+ "Cannot parse the components from specified bundle ("
+ + bundle.getSymbolicName() + "): " + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the service object of a service registered in the specified
+ * service context, offering the specified interface and matching the given
+ * filter.
+ *
+ * @param serviceContext the service context in which the service is
+ * searched.
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service object provided by the specified bundle, offering the
+ * specified interface and matching the given filter.
+ */
+ public static Object getServiceObject(ServiceContext serviceContext,
+ String itf, String filter) {
+ ServiceReference ref = getServiceReference(serviceContext, itf, filter);
+ if (ref != null) {
+ return serviceContext.getService(ref);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service objects of the services registered in the specified
+ * service context, offering the specified interface and matching the given
+ * filter.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service objects provided by the specified bundle, offering
+ * the specified interface and matching the given filter.
+ */
+ public static Object[] getServiceObjects(ServiceContext serviceContext,
+ String itf, String filter) {
+ ServiceReference[] refs = getServiceReferences(serviceContext, itf,
+ filter);
+ if (refs != null) {
+ Object[] list = new Object[refs.length];
+ for (int i = 0; i < refs.length; i++) {
+ list[i] = serviceContext.getService(refs[i]);
+ }
+ return list;
+ } else {
+ return new Object[0];
+ }
+ }
+
+ /**
+ * Returns the service reference of a service registered in the specified
+ * service context, offering the specified interface and matching the given
+ * filter.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return a service reference registered in the specified service context,
+ * offering the specified interface and matching the given filter.
+ * If no service is found, {@code null} is returned.
+ */
+ public static ServiceReference getServiceReference(
+ ServiceContext serviceContext, String itf, String filter) {
+ ServiceReference[] refs = getServiceReferences(serviceContext, itf,
+ filter);
+ if (refs.length != 0) {
+ return refs[0];
+ } else {
+ // No service found
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service reference of the service registered in the specified
+ * service context, offering the specified interface and having the given
+ * persistent ID.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched service.
+ * @param pid the persistent ID of the searched service.
+ * @return a service registered in the specified service context, offering
+ * the specified interface and having the given persistent ID.
+ */
+ public static ServiceReference getServiceReferenceByPID(
+ ServiceContext serviceContext, String itf, String pid) {
+ String filter = "(" + "service.pid" + "=" + pid + ")";
+ ServiceReference[] refs = getServiceReferences(serviceContext, itf,
+ filter);
+ if (refs == null) {
+ return null;
+ } else if (refs.length == 1) {
+ return refs[0];
+ } else {
+ throw new IllegalStateException(
+ "A service lookup by PID returned several providers ("
+ + refs.length + ")" + " for " + itf + " with pid="
+ + pid);
+ }
+ }
+
+ /**
+ * Returns the service reference of all the services registered in the
+ * specified service context, offering the specified interface and matching
+ * the given filter.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return all the service references registered in the specified service
+ * context, offering the specified interface and matching the given
+ * filter. If no service matches, an empty array is returned.
+ */
+ public static ServiceReference[] getServiceReferences(
+ ServiceContext serviceContext, String itf, String filter) {
+ ServiceReference[] refs = null;
+ try {
+ // Get all the service references
+ refs = serviceContext.getServiceReferences(itf, filter);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(
+ "Cannot get service references: " + e.getMessage());
+ }
+ if (refs == null) {
+ return new ServiceReference[0];
+ } else {
+ return refs;
+ }
+ }
+
+ /**
+ * Returns the service reference of a service registered in the specified
+ * service context, offering the specified interface and having the given
+ * name.
+ *
+ * @param serviceContext the service context in which services are searched.
+ * @param itf the interface provided by the searched service.
+ * @param name the name of the searched service.
+ * @return a service registered in the specified service context, offering
+ * the specified interface and having the given name.
+ */
+ public static ServiceReference getServiceReferenceByName(
+ ServiceContext serviceContext, String itf, String name) {
+ String filter = null;
+ if (itf.equals(Factory.class.getName())
+ || itf.equals(ManagedServiceFactory.class.getName())) {
+ filter = "(" + "factory.name" + "=" + name + ")";
+ } else if (itf.equals(Architecture.class.getName())) {
+ filter = "(" + "architecture.instance" + "=" + name + ")";
+ } else {
+ filter = "(" + "instance.name" + "=" + name + ")";
+ }
+ return getServiceReference(serviceContext, itf, filter);
+ }
+
+ /**
+ * Checks the availability of a service inside the given service context.
+ * @param sc the service context
+ * @param itf the service interface to found
+ * @return <code>true</code> if the service is available in the service
+ * context, <code>false</code> otherwise.
+ */
+ public static boolean isServiceAvailable(ServiceContext sc, String itf) {
+ ServiceReference ref = getServiceReference(sc, itf, null);
+ return ref != null;
+ }
+
+ /**
+ * Checks the availability of a service inside the given service context.
+ * @param sc the service context
+ * @param itf the service interface to found
+ * @param name the service provider name
+ * @return <code>true</code> if the service is available in the service
+ * context, <code>false</code> otherwise.
+ */
+ public static boolean isServiceAvailableByName(ServiceContext sc,
+ String itf, String name) {
+ ServiceReference ref = getServiceReferenceByName(sc, itf, name);
+ return ref != null;
+ }
+
+ /**
+ * Checks the availability of a service inside the given service context.
+ * @param sc the service context
+ * @param itf the service interface to found
+ * @param pid the pid of the service
+ * @return <code>true</code> if the service is available in the service
+ * context, <code>false</code> otherwise.
+ */
+ public static boolean isServiceAvailableByPID(ServiceContext sc,
+ String itf, String pid) {
+ ServiceReference ref = getServiceReferenceByPID(sc, itf, pid);
+ return ref != null;
+ }
+
+ /**
+ * Returns the service reference of a service provided by the specified
+ * bundle, offering the specified interface and having the given name.
+ *
+ * @param bundle the bundle from which the service is searched.
+ * @param itf the interface provided by the searched service.
+ * @param name the name of the searched service.
+ * @return a service provided by the specified bundle, offering the
+ * specified interface and having the given name.
+ */
+ public static ServiceReference getServiceReferenceByName(Bundle bundle,
+ String itf, String name) {
+ String filter = null;
+ if (itf.equals(Factory.class.getName())
+ || itf.equals(ManagedServiceFactory.class.getName())) {
+ filter = "(" + "factory.name" + "=" + name + ")";
+ } else if (itf.equals(Architecture.class.getName())) {
+ filter = "(" + "architecture.instance" + "=" + name + ")";
+ } else {
+ filter = "(" + "instance.name" + "=" + name + ")";
+ }
+ return OSGiHelper.getServiceReference(bundle, itf, filter);
+ }
+
+ /**
+ * Returns the service reference of a service provided by the local bundle,
+ * offering the specified interface and having the given name.
+ *
+ * @param itf the interface provided by the searched service.
+ * @param name the name of the searched service.
+ * @return a service provided by the specified bundle, offering the
+ * specified interface and having the given name.
+ */
+ public ServiceReference getServiceReferenceByName(String itf, String name) {
+ return getServiceReferenceByName(m_context.getBundle(), itf, name);
+ }
+
+ /**
+ * Checks if the service is available.
+ * @param itf the service interface
+ * @param name the service provider name
+ * @return <code>true</code> if the service is available, <code>false</code>
+ * otherwise.
+ */
+ public boolean isServiceAvailableByName(String itf, String name) {
+ ServiceReference ref = getServiceReferenceByName(itf, name);
+ return ref != null;
+ }
+
+}
diff --git a/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/OSGiHelper.java b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/OSGiHelper.java
new file mode 100644
index 0000000..bf880f1
--- /dev/null
+++ b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/OSGiHelper.java
@@ -0,0 +1,456 @@
+package org.apache.felix.ipojo.tests.core;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+import static org.junit.Assert.fail;
+
+
+public class OSGiHelper {
+
+ /**
+ * The bundle context.
+ */
+ private BundleContext context;
+
+ /**
+ * List of get references.
+ */
+ private List<ServiceReference> m_references = new ArrayList<ServiceReference>();
+
+ public OSGiHelper(BundleContext context) {
+ this.context = context;
+ }
+
+ public void dispose() {
+ // Unget services
+ for (int i = 0; i < m_references.size(); i++) {
+ context.ungetService((ServiceReference) m_references.get(i));
+ }
+ m_references.clear();
+ }
+
+ /**
+ * Gets the Bundle Context.
+ * @return the bundle context.
+ */
+ public BundleContext getContext() {
+ return context;
+ }
+
+ /**
+ * Returns the service object of a service provided by the specified bundle,
+ * offering the specified interface and matching the given filter.
+ *
+ * @param bundle the bundle from which the service is searched.
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service object provided by the specified bundle, offering the
+ * specified interface and matching the given filter.
+ */
+ public static Object getServiceObject(Bundle bundle, String itf,
+ String filter) {
+ ServiceReference ref = getServiceReference(bundle, itf, filter);
+ if (ref != null) {
+ return bundle.getBundleContext().getService(ref);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service objects of the services provided by the specified
+ * bundle, offering the specified interface and matching the given filter.
+ *
+ * @param bundle the bundle from which services are searched.
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service objects provided by the specified bundle, offering
+ * the specified interface and matching the given filter.
+ */
+ public static Object[] getServiceObjects(Bundle bundle, String itf,
+ String filter) {
+ ServiceReference[] refs = getServiceReferences(bundle, itf, filter);
+ if (refs != null) {
+ Object[] list = new Object[refs.length];
+ for (int i = 0; i < refs.length; i++) {
+ list[i] = bundle.getBundleContext().getService(refs[i]);
+ }
+ return list;
+ } else {
+ return new Object[0];
+ }
+ }
+
+ /**
+ * Returns the service reference of a service provided by the specified
+ * bundle, offering the specified interface and matching the given filter.
+ *
+ * @param bundle the bundle from which the service is searched.
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return a service reference provided by the specified bundle, offering
+ * the specified interface and matching the given filter. If no
+ * service is found, {@code null} is returned.
+ */
+ public static ServiceReference getServiceReference(Bundle bundle,
+ String itf, String filter) {
+ ServiceReference[] refs = getServiceReferences(bundle, itf, filter);
+ if (refs.length != 0) {
+ return refs[0];
+ } else {
+ // No service found
+ return null;
+ }
+ }
+
+ /**
+ * Checks if the service is available.
+ * @param itf the service interface
+ * @return <code>true</code> if the service is available, <code>false</code>
+ * otherwise.
+ */
+ public boolean isServiceAvailable(String itf) {
+ ServiceReference ref = getServiceReference(itf, null);
+ return ref != null;
+ }
+
+ /**
+ * Checks if the service is available.
+ * @param itf the service interface
+ * @param pid the service pid
+ * @return <code>true</code> if the service is available, <code>false</code>
+ * otherwise.
+ */
+ public boolean isServiceAvailableByPID(String itf, String pid) {
+ ServiceReference ref = getServiceReferenceByPID(itf, pid);
+ return ref != null;
+ }
+
+ /**
+ * Returns the service reference of the service provided by the specified
+ * bundle, offering the specified interface and having the given persistent
+ * ID.
+ *
+ * @param bundle the bundle from which the service is searched.
+ * @param itf the interface provided by the searched service.
+ * @param pid the persistent ID of the searched service.
+ * @return a service provided by the specified bundle, offering the
+ * specified interface and having the given persistent ID.
+ */
+ public static ServiceReference getServiceReferenceByPID(Bundle bundle,
+ String itf, String pid) {
+ String filter = "(" + "service.pid" + "=" + pid + ")";
+ ServiceReference[] refs = getServiceReferences(bundle, itf, filter);
+ if (refs == null) {
+ return null;
+ } else if (refs.length == 1) {
+ return refs[0];
+ } else {
+ throw new IllegalStateException(
+ "A service lookup by PID returned several providers ("
+ + refs.length + ")" + " for " + itf + " with pid="
+ + pid);
+ }
+ }
+
+ /**
+ * Returns the service reference of all the services provided in the
+ * specified bundle, offering the specified interface and matching the given
+ * filter.
+ *
+ * @param bundle the bundle from which services are searched.
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return all the service references provided in the specified bundle,
+ * offering the specified interface and matching the given filter.
+ * If no service matches, an empty array is returned.
+ */
+ public static ServiceReference[] getServiceReferences(Bundle bundle,
+ String itf, String filter) {
+ ServiceReference[] refs = null;
+ try {
+ // Get all the service references
+ refs = bundle.getBundleContext().getServiceReferences(itf, filter);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(
+ "Cannot get service references: " + e.getMessage());
+ }
+ if (refs == null) {
+ return new ServiceReference[0];
+ } else {
+ return refs;
+ }
+ }
+
+ /**
+ * Returns the service object of a service provided by the local bundle,
+ * offering the specified interface and matching the given filter.
+ *
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service object provided by the local bundle, offering the
+ * specified interface and matching the given filter.
+ */
+ public Object getServiceObject(String itf, String filter) {
+ ServiceReference ref = getServiceReference(itf, filter);
+ if (ref != null) {
+ m_references.add(ref);
+ return context.getService(ref);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service object associated with this service reference.
+ *
+ * @param ref service reference
+ * @return the service object.
+ */
+ public Object getServiceObject(ServiceReference ref) {
+ if (ref != null) {
+ m_references.add(ref);
+ return context.getService(ref);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the service objects of the services provided by the local bundle,
+ * offering the specified interface and matching the given filter.
+ *
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return the service objects provided by the local bundle, offering the
+ * specified interface and matching the given filter.
+ */
+ public Object[] getServiceObjects(String itf, String filter) {
+ ServiceReference[] refs = getServiceReferences(itf, filter);
+ if (refs != null) {
+ Object[] list = new Object[refs.length];
+ for (int i = 0; i < refs.length; i++) {
+ m_references.add(refs[i]);
+ list[i] = context.getService(refs[i]);
+ }
+ return list;
+ } else {
+ return new Object[0];
+ }
+ }
+
+ /**
+ * Returns the service reference of a service provided by the local bundle,
+ * offering the specified interface and matching the given filter.
+ *
+ * @param itf the interface provided by the searched service.
+ * @param filter an additional filter (can be {@code null}).
+ * @return a service reference provided by the local bundle, offering the
+ * specified interface and matching the given filter. If no service
+ * is found, {@code null} is returned.
+ */
+ public ServiceReference getServiceReference(String itf, String filter) {
+ return getServiceReference(context.getBundle(), itf, filter);
+ }
+
+ /**
+ * Returns the service reference of a service provided offering the
+ * specified interface.
+ *
+ * @param itf the interface provided by the searched service.
+ * @return a service reference provided by the local bundle, offering the
+ * specified interface and matching the given filter. If no service
+ * is found, {@code null} is returned.
+ */
+ public ServiceReference getServiceReference(String itf) {
+ return getServiceReference(context.getBundle(), itf, null);
+ }
+
+ /**
+ * Returns the service reference of the service provided by the local
+ * bundle, offering the specified interface and having the given persistent
+ * ID.
+ *
+ * @param itf the interface provided by the searched service.
+ * @param pid the persistent ID of the searched service.
+ * @return a service provided by the local bundle, offering the specified
+ * interface and having the given persistent ID.
+ */
+ public ServiceReference getServiceReferenceByPID(String itf, String pid) {
+ return getServiceReferenceByPID(context.getBundle(), itf, pid);
+ }
+
+ /**
+ * Returns the service reference of all the services provided in the local
+ * bundle, offering the specified interface and matching the given filter.
+ *
+ * @param itf the interface provided by the searched services.
+ * @param filter an additional filter (can be {@code null}).
+ * @return all the service references provided in the local bundle, offering
+ * the specified interface and matching the given filter. If no
+ * service matches, an empty array is returned.
+ */
+ public ServiceReference[] getServiceReferences(String itf, String filter) {
+ return getServiceReferences(context.getBundle(), itf, filter);
+ }
+
+ /**
+ * Gets the package admin exposed by the framework.
+ * Fails if the package admin is not available.
+ * @return the package admin service.
+ */
+ public PackageAdmin getPackageAdmin() {
+ PackageAdmin pa = (PackageAdmin) getServiceObject(PackageAdmin.class.getName(), null);
+ if (pa == null) {
+ fail("No package admin available");
+ }
+ return pa;
+ }
+
+ /**
+ * Refresh the packages.
+ * Fails if the package admin service is not available.
+ */
+ public void refresh() {
+ getPackageAdmin().refreshPackages(null);
+ }
+
+ /**
+ * Waits for a service. Fails on timeout.
+ * If timeout is set to 0, it sets the timeout to 10s.
+ * @param itf the service interface
+ * @param filter the filter
+ * @param timeout the timeout
+ */
+ public void waitForService(String itf, String filter, long timeout) {
+ if (timeout == 0) {
+ timeout = 10000; // Default 10 secondes.
+ }
+ ServiceReference[] refs = getServiceReferences(itf, filter);
+ long begin = System.currentTimeMillis();
+ if (refs.length != 0) {
+ return;
+ } else {
+ while(refs.length == 0) {
+ try {
+ Thread.sleep(5);
+ } catch (InterruptedException e) {
+ // Interrupted
+ }
+ long now = System.currentTimeMillis();
+
+ if ((now - begin) > timeout) {
+ fail("Timeout ... no services matching with the request after " + timeout + "ms");
+ }
+ refs = getServiceReferences(itf, filter);
+ }
+ }
+ }
+
+
+ /**
+ * Installs a bundle.
+ * Fails if the bundle cannot be installed.
+ * Be aware that you have to uninstall the bundle yourself.
+ * @param url bundle url
+ * @return the installed bundle
+ */
+ public Bundle installBundle(String url) {
+ try {
+ return context.installBundle(url);
+ } catch (BundleException e) {
+ fail("Cannot install the bundle " + url + " : " + e.getMessage());
+ }
+ return null; // Can not happen
+ }
+
+ /**
+ * Installs a bundle.
+ * Fails if the bundle cannot be installed.
+ * Be aware that you have to uninstall the bundle yourself.
+ * @param url bundle url
+ * @param stream input stream containing the bundle
+ * @return the installed bundle
+ */
+ public Bundle installBundle(String url, InputStream stream) {
+ try {
+ return context.installBundle(url, stream);
+ } catch (BundleException e) {
+ fail("Cannot install the bundle " + url + " : " + e.getMessage());
+ }
+ return null; // Can not happen
+ }
+
+ /**
+ * Installs and starts a bundle.
+ * Fails if the bundle cannot be installed or an error occurs
+ * during startup. Be aware that you have to uninstall the bundle
+ * yourself.
+ * @param url the bundle url
+ * @return the Bundle object.
+ */
+ public Bundle installAndStart(String url) {
+ Bundle bundle = installBundle(url);
+ try {
+ bundle.start();
+ } catch (BundleException e) {
+ fail("Cannot start the bundle " + url + " : " + e.getMessage());
+ }
+ return bundle;
+ }
+
+ /**
+ * Installs and starts a bundle.
+ * Fails if the bundle cannot be installed or an error occurs
+ * during startup. Be aware that you have to uninstall the bundle
+ * yourself.
+ * @param url the bundle url
+ * @param stream input stream containing the bundle
+ * @return the Bundle object.
+ */
+ public Bundle installAndStart(String url, InputStream stream) {
+ Bundle bundle = installBundle(url, stream);
+ try {
+ bundle.start();
+ } catch (BundleException e) {
+ fail("Cannot start the bundle " + url + " : " + e.getMessage());
+ }
+ return bundle;
+ }
+
+ /**
+ * Get the bundle by its id.
+ * @param bundleId the bundle id.
+ * @return the bundle with the given id.
+ */
+ public Bundle getBundle(long bundleId) {
+ return context.getBundle(bundleId);
+ }
+
+ /**
+ * Gets a bundle by its symbolic name.
+ * Fails if no bundle matches.
+ * @param name the symbolic name of the bundle
+ * @return the bundle object.
+ */
+ public Bundle getBundle(String name) {
+ Bundle[] bundles = context.getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ if (name.equals(bundles[i].getSymbolicName())) {
+ return bundles[i];
+ }
+ }
+ fail("No bundles with the given symbolic name " + name);
+ return null; // should not happen
+ }
+
+}
diff --git a/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/component/MyComponent.java b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/component/MyComponent.java
new file mode 100644
index 0000000..71fcc94
--- /dev/null
+++ b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/component/MyComponent.java
@@ -0,0 +1,11 @@
+package org.apache.felix.ipojo.tests.core.component;
+
+import org.apache.felix.ipojo.tests.core.service.MyService;
+
+public class MyComponent implements MyService {
+
+ public void foo() {
+ // Nothing to do.
+ }
+
+}
diff --git a/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/service/MyService.java b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/service/MyService.java
new file mode 100644
index 0000000..9ffaa52
--- /dev/null
+++ b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/service/MyService.java
@@ -0,0 +1,7 @@
+package org.apache.felix.ipojo.tests.core.service;
+
+public interface MyService {
+
+ public void foo();
+
+}