Applied patch (FELIX-266) to add support to iPOJO for composite
services.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@527156 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo.metadata/src/main/java/org/apache/felix/ipojo/metadata/Element.java b/ipojo.metadata/src/main/java/org/apache/felix/ipojo/metadata/Element.java
index c9779a5..4a821f8 100644
--- a/ipojo.metadata/src/main/java/org/apache/felix/ipojo/metadata/Element.java
+++ b/ipojo.metadata/src/main/java/org/apache/felix/ipojo/metadata/Element.java
@@ -207,7 +207,7 @@
name = name.toLowerCase();
Element[] list = new Element[0];
for (int i = 0; i < m_elements.length; i++) {
- if (m_elements[i].getName().equals(name) && m_elements[i].getNameSpace().equals("")) {
+ if (m_elements[i].getName().equalsIgnoreCase(name) && m_elements[i].getNameSpace().equals("")) {
list = Element.addElement(list, m_elements[i]);
}
}
diff --git a/ipojo.plugin/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java b/ipojo.plugin/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
index 30fb273..d988294 100644
--- a/ipojo.plugin/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
+++ b/ipojo.plugin/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
@@ -72,8 +72,9 @@
/**
* @return the method list.
+ * Modified for performance issue.
*/
- public List getMethods() { return m_methods; }
+ public List getMethods() { /*return m_methods;*/ return new ArrayList(); }
/**
* Manipulate the class.
diff --git a/ipojo.plugin/src/main/java/org/apache/felix/ipojo/parser/XMLMetadataParser.java b/ipojo.plugin/src/main/java/org/apache/felix/ipojo/parser/XMLMetadataParser.java
index 66ac076..030eee5 100644
--- a/ipojo.plugin/src/main/java/org/apache/felix/ipojo/parser/XMLMetadataParser.java
+++ b/ipojo.plugin/src/main/java/org/apache/felix/ipojo/parser/XMLMetadataParser.java
@@ -18,6 +18,8 @@
*/
package org.apache.felix.ipojo.parser;
+import java.util.ArrayList;
+import java.util.List;
import java.util.logging.Level;
import org.apache.felix.ipojo.metadata.Attribute;
@@ -41,15 +43,38 @@
* @throws ParseException when an error occurs in the xml parsing
*/
public Element[] getComponentsMetadata() throws ParseException {
- return m_elements[0].getElements("Component");
+ Element[] comp = m_elements[0].getElements("Component");
+ Element[] compo = m_elements[0].getElements("Composite");
+ Element[] metadata = new Element[comp.length + compo.length];
+ int l = 0;
+ for(int i = 0; i < comp.length; i++) { metadata[l] = comp[i]; l++;}
+ for(int i = 0; i < compo.length; i++) { metadata[l] = compo[i]; l++;}
+ return metadata;
+ }
+
+ public List getReferredPackages() {
+ List referred = new ArrayList();
+ Element[] compo = m_elements[0].getElements("Composite");
+ for(int i= 0; i < compo.length; i++) {
+ for(int j = 0; j < compo[i].getElements().length; j++) {
+ if(compo[i].getElements()[j].containsAttribute("specification")) {
+ String p = compo[i].getElements()[j].getAttribute("specification");
+ int last = p.lastIndexOf('.');
+ if(last != -1) { referred.add(p.substring(0, last)); }
+ }
+ }
+ }
+ return referred;
}
public Element[] getMetadata() throws ParseException {
Element[] comp = m_elements[0].getElements("Component");
+ Element[] compo = m_elements[0].getElements("Composite");
Element[] conf = m_elements[0].getElements("Instance");
- Element[] metadata = new Element[comp.length + conf.length];
+ Element[] metadata = new Element[comp.length + conf.length + compo.length];
int l = 0;
for(int i = 0; i < comp.length; i++) { metadata[l] = comp[i]; l++;}
+ for(int i = 0; i < compo.length; i++) { metadata[l] = compo[i]; l++;}
for(int i = 0; i < conf.length; i++) { metadata[l] = conf[i]; l++;}
return metadata;
}
diff --git a/ipojo.plugin/src/main/java/org/apache/felix/ipojo/plugin/OsgiJarMojo.java b/ipojo.plugin/src/main/java/org/apache/felix/ipojo/plugin/OsgiJarMojo.java
index 29b9659..c61f91a 100644
--- a/ipojo.plugin/src/main/java/org/apache/felix/ipojo/plugin/OsgiJarMojo.java
+++ b/ipojo.plugin/src/main/java/org/apache/felix/ipojo/plugin/OsgiJarMojo.java
@@ -151,7 +151,8 @@
*/
private OsgiManifest osgiManifest;
- private String[][] namespaces;
+ private String[][] namespaces;
+ private List referedPackages;
/**
* Execute this Mojo
@@ -482,6 +483,12 @@
}
}
+ // Add refered imports form the metadata
+ for(int i = 0; i < referedPackages.size(); i++) {
+ String pack = (String) referedPackages.get(i);
+ referred.add(pack);
+ }
+
// Add org.apache.felix.ipojo, org.apache.felix.ipojo.architecture is not already in the set
referred.add(IPojoPluginConfiguration.ipojo_package);
referred.add(IPojoPluginConfiguration.ipojo_arch_package);
@@ -872,6 +879,7 @@
parser.parse(is);
meta = handler.getMetadata();
+ referedPackages = handler.getReferredPackages();
} catch (MalformedURLException e) {
getLog().error("Malformed URL for " + outputDirectory+path+ "("+e.getMessage()+")");
diff --git a/ipojo/pom.xml b/ipojo/pom.xml
index 08adf4d..eb1ea8d 100644
--- a/ipojo/pom.xml
+++ b/ipojo/pom.xml
@@ -52,6 +52,7 @@
org.apache.felix.ipojo.util,
org.apache.felix.ipojo.handlers.dependency,
org.apache.felix.ipojo.handlers.providedservice,
+ org.apache.felix.ipojo.composite,
org.osgi.service.cm; specification-version="1.2",
org.osgi.service.log; specification-version="1.3"
</exportPackage>
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/ComponentFactory.java b/ipojo/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
index b873c2f..2d66c3d 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/ComponentFactory.java
@@ -51,6 +51,11 @@
* The key of this hashmap is the name (i.e. pid) of the created instance
*/
private HashMap m_componentInstances = new HashMap();
+
+ /**
+ * Ture if the component is a composition.
+ */
+ private boolean m_isComposite = false;
/**
* The bundle context reference.
@@ -66,6 +71,11 @@
* Component Implementation Class Name.
*/
private String m_componentClassName = null;
+
+ /**
+ * Composition Name.
+ */
+ private String m_compositeName = null;
/**
* Classloader to delegate loading.
@@ -97,6 +107,11 @@
* Logger for the factory (and all component instance).
*/
private Logger m_logger;
+
+ /**
+ * True when the factory is active (non stopping and non starting).
+ */
+ private boolean m_active = false;
/**
* FactoryClassloader.
@@ -183,19 +198,44 @@
*/
public ComponentFactory(BundleContext bc, Element cm) {
m_context = bc;
- m_componentClassName = cm.getAttribute("className");
m_componentMetadata = cm;
-
- // Get factory PID :
- if (m_componentMetadata.containsAttribute("factory") && !m_componentMetadata.getAttribute("factory").equalsIgnoreCase("no")) {
- m_factoryName = m_componentMetadata.getAttribute("factory");
- } else { m_factoryName = m_componentMetadata.getAttribute("className"); }
-
- m_logger = new Logger(m_context, m_factoryName, Logger.WARNING);
+ if (cm.getName().equalsIgnoreCase("composite")) {
+ m_componentClassName = null;
+ m_isComposite = true;
+ // Get the name
+ if (cm.containsAttribute("name")) {
+ m_compositeName = cm.getAttribute("name");
+ } else {
+ System.err.println("A composite needs a name"); return;
+ }
+ // Compute factory name
+ if (m_componentMetadata.containsAttribute("factory") && !m_componentMetadata.getAttribute("factory").equalsIgnoreCase("no")) {
+ m_factoryName = m_componentMetadata.getAttribute("factory");
+ } else { m_factoryName = m_compositeName; }
+ } else {
+ if (cm.containsAttribute("className")) {
+ m_componentClassName = cm.getAttribute("className");
+ } else {
+ System.err.println("A component needs a class name"); return;
+ }
+ if (m_componentMetadata.containsAttribute("factory") && !m_componentMetadata.getAttribute("factory").equalsIgnoreCase("no")) {
+ m_factoryName = m_componentMetadata.getAttribute("factory");
+ } else { m_factoryName = m_componentMetadata.getAttribute("className"); }
+ }
+ if (m_factoryName != null) {
+ m_logger = new Logger(m_context, m_factoryName, Logger.WARNING);
+ } else {
+ if (m_isComposite) {
+ m_logger = new Logger(m_context, m_compositeName, Logger.WARNING);
+ } else {
+ m_logger = new Logger(m_context, m_componentClassName, Logger.WARNING);
+ }
+ }
}
/**
* Create a instance manager factory. The class is given in parameter.
+ * The component type is not a composite.
* @param bc : bundle context
* @param clazz : the component class
* @param cm : metadata of the component
@@ -217,12 +257,15 @@
/**
* Stop all the instance managers.
*/
- public void stop() {
+ public synchronized void stop() {
+ m_active = false;
Collection col = m_componentInstances.values();
Iterator it = col.iterator();
while (it.hasNext()) {
ComponentInstance ci = (ComponentInstance) it.next();
- if (ci.isStarted()) { ci.stop(); }
+ if (ci.isStarted()) {
+ ci.stop();
+ }
}
m_componentInstances.clear();
if (m_sr != null) { m_sr.unregister(); }
@@ -232,20 +275,33 @@
/**
* Start all the instance managers.
*/
- public void start() {
+ public synchronized void start() {
Properties props = new Properties();
// create a ghost component
- InstanceManager ghost = new InstanceManager(this, m_context);
- Properties p = new Properties();
- p.put("name", "ghost");
- ghost.configure(m_componentMetadata, p);
- m_componentDesc = ghost.getComponentDescription();
+ if (!m_isComposite) {
+ InstanceManager ghost = new InstanceManager(this, m_context);
+ Properties p = new Properties();
+ p.put("name", "ghost");
+ ghost.configure(m_componentMetadata, p);
+ m_componentDesc = ghost.getComponentDescription();
+ } else {
+ CompositeManager ghost = new CompositeManager(this, m_context);
+ Properties p = new Properties();
+ p.put("name", "ghost");
+ ghost.configure(m_componentMetadata, p);
+ m_componentDesc = ghost.getComponentDescription();
+ }
// Check if the factory should be exposed
if (m_componentMetadata.containsAttribute("factory") && m_componentMetadata.getAttribute("factory").equalsIgnoreCase("no")) { return; }
- props.put("component.class", m_componentClassName);
+ if (!m_isComposite) {
+ props.put("component.class", m_componentClassName);
+ } else {
+ props.put("component.class", "no implementation class");
+ }
+ props.put("factory.name", m_factoryName);
props.put("component.providedServiceSpecifications", m_componentDesc.getprovidedServiceSpecification());
props.put("component.properties", m_componentDesc.getProperties());
props.put("component.description", m_componentDesc);
@@ -255,8 +311,19 @@
props.put(Constants.SERVICE_PID, m_factoryName);
// Exposition of the factory service
+ m_active = true;
m_sr = m_context.registerService(new String[] {Factory.class.getName(), ManagedServiceFactory.class.getName()}, this, props);
}
+
+ /**
+ * Callback called by instance when stopped.
+ * @param ci : the instance stopping
+ */
+ protected synchronized void stopped(ComponentInstance ci) {
+ if (m_active) {
+ m_componentInstances.remove(ci.getInstanceName());
+ }
+ }
/**
* @see org.apache.felix.ipojo.Factory#getComponentInfo()
@@ -318,15 +385,30 @@
}
IPojoContext context = new IPojoContext(m_context);
- InstanceManager instance = new InstanceManager(this, context);
- context.setComponentInstance(instance);
- instance.configure(m_componentMetadata, configuration);
+ ComponentInstance instance = null;
+ if (!m_isComposite) {
+ InstanceManager inst = new InstanceManager(this, context);
+ //context.setComponentInstance(inst);
+ inst.configure(m_componentMetadata, configuration);
+ instance = inst;
+ } else {
+ CompositeManager inst = new CompositeManager(this, context);
+ //context.setComponentInstance(inst);
+ inst.configure(m_componentMetadata, configuration);
+ instance = inst;
+ }
String pid = null;
if (configuration.get("name") != null) {
pid = (String) configuration.get("name");
- } else { pid = m_componentMetadata.getAttribute("className"); }
-
+ } else {
+ throw new UnacceptableConfiguration("The name attribute is missing");
+ }
+
+ if (m_componentInstances.containsKey(pid)) {
+ throw new UnacceptableConfiguration("Name already used : " + pid);
+ }
+
m_componentInstances.put(pid, instance);
instance.start();
return instance;
@@ -342,17 +424,30 @@
m_logger.log(Logger.ERROR, "The configuration is not acceptable : " + e.getMessage());
throw new UnacceptableConfiguration("The configuration " + configuration + " is not acceptable for " + m_factoryName + ": " + e.getMessage());
}
-
- IPojoContext context = new IPojoContext(m_context, serviceContext);
- InstanceManager instance = new InstanceManager(this, context);
- context.setComponentInstance(instance);
- instance.configure(m_componentMetadata, configuration);
- String pid = null;
+ IPojoContext context = new IPojoContext(m_context, serviceContext);
+ ComponentInstance instance = null;
+ if (!m_isComposite) {
+ InstanceManager inst = new InstanceManager(this, context);
+ //context.setComponentInstance(inst);
+ inst.configure(m_componentMetadata, configuration);
+ instance = inst;
+ } else {
+ CompositeManager inst = new CompositeManager(this, context);
+ //context.setComponentInstance(inst);
+ inst.configure(m_componentMetadata, configuration);
+ instance = inst;
+ }
+
+ String pid = null;
if (configuration.get("name") != null) {
pid = (String) configuration.get("name");
- } else {
- pid = m_componentMetadata.getAttribute("className");
+ } else {
+ throw new UnacceptableConfiguration("The name attribute is missing");
+ }
+
+ if (m_componentInstances.containsKey(pid)) {
+ throw new UnacceptableConfiguration("Name already used : " + pid);
}
m_componentInstances.put(pid, instance);
@@ -450,7 +545,12 @@
public void reconfigure(Dictionary properties) throws UnacceptableConfiguration {
if (properties == null || properties.get("name") == null) { throw new UnacceptableConfiguration("The configuration does not contains the \"name\" property"); }
String name = (String) properties.get("name");
- InstanceManager cm = (InstanceManager) m_componentInstances.get(name);
+ ComponentInstance cm = null;
+ if (m_isComposite) {
+ cm = (CompositeManager) m_componentInstances.get(name);
+ } else {
+ cm = (InstanceManager) m_componentInstances.get(name);
+ }
if (cm == null) {
return; // The instance does not exist.
} else {
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/ComponentInstance.java b/ipojo/src/main/java/org/apache/felix/ipojo/ComponentInstance.java
index 3fd4acd..9578dda 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/ComponentInstance.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/ComponentInstance.java
@@ -80,7 +80,7 @@
ComponentFactory getFactory();
/**
- * @return the context of the instance manager
+ * @return the context of the component instance
*/
BundleContext getContext();
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/CompositeHandler.java b/ipojo/src/main/java/org/apache/felix/ipojo/CompositeHandler.java
new file mode 100644
index 0000000..8dab9a6
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/CompositeHandler.java
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Composite Handler Abstract Class.
+ * An composite handler need implements these method to be notifed of lifecycle change...
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public abstract class CompositeHandler {
+
+ /**
+ * Configure the handler.
+ * @param im : the instance manager
+ * @param metadata : the metadata of the component
+ * @param configuration : the instance configuration
+ */
+ public abstract void configure(CompositeManager im, Element metadata, Dictionary configuration);
+
+ /**
+ * Stop the handler : stop the management.
+ */
+ public abstract void stop();
+
+ /**
+ * Start the handler : start the management.
+ */
+ public abstract void start();
+
+ /**
+ * Is the actual state valid for this handler ?
+ * @return true is the state seems valid for the handler
+ */
+ public boolean isValid() { return true; }
+
+ /**
+ * This method is called when the component state changed.
+ * @param state : the new state
+ */
+ public void stateChanged(int state) { }
+
+ /**
+ * @return the description of the handler..
+ */
+ public HandlerDescription getDescription() { return new HandlerDescription(this.getClass().getName(), isValid()); }
+
+ /**
+ * The instance is reconfiguring.
+ * @param configuration : New instance configuration.
+ */
+ public void reconfigure(Dictionary configuration) { }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/CompositeManager.java b/ipojo/src/main/java/org/apache/felix/ipojo/CompositeManager.java
new file mode 100644
index 0000000..d17f45d
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/CompositeManager.java
@@ -0,0 +1,364 @@
+/*
+ * 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;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.ComponentDescription;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.composite.CompositeServiceContext;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * iPOJO Composite manager.
+ * The composite manager class manages one instance of a component type which is a composition.
+ * It manages component lifecycle, and handlers...
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class CompositeManager implements ComponentInstance {
+
+ /**
+ * Parent factory (ComponentFactory).
+ */
+ private ComponentFactory m_factory;
+
+ /**
+ * Name of the component instance.
+ */
+ private String m_name;
+
+ /**
+ * The context of the component.
+ */
+ private BundleContext m_context;
+
+ /**
+ * Composite Handler list.
+ */
+ private CompositeHandler[] m_handlers = new CompositeHandler[0];
+
+ /**
+ * Component state (STOPPED at the beginning).
+ */
+ private int m_state = STOPPED;
+
+ /**
+ * Component type information.
+ */
+ private ComponentDescription m_componentDesc;
+
+ /**
+ * Internal service context of the composition.
+ */
+ private CompositeServiceContext m_internalContext;
+
+
+ // Constructor
+ /**
+ * Construct a new Component Manager.
+ * @param factory : the factory managing the instance manager
+ * @param bc : the bundle context to give to the instance
+ */
+ public CompositeManager(ComponentFactory factory, BundleContext bc) {
+ m_factory = factory;
+ m_context = bc;
+ // Initialize the service context.
+ m_internalContext = new CompositeServiceContext(m_context, this);
+ m_factory.getLogger().log(Logger.INFO, "[Bundle " + m_context.getBundle().getBundleId() + "] Create an instance manager from the factory " + m_factory);
+ }
+
+ /**
+ * Configure the instance manager.
+ * Stop the existings handler, clear the handler list, change the metadata, recreate the handlers
+ * @param cm : the component type metadata
+ * @param configuration : the configuration of the instance
+ */
+ public void configure(Element cm, Dictionary configuration) {
+ // Stop all previous registred handler
+ if (m_handlers.length != 0) { stop(); }
+
+ // Clear the handler list
+ m_handlers = new CompositeHandler[0];
+
+ // ComponentInfo initialization
+ m_componentDesc = new ComponentDescription(m_factory.getName());
+
+ // Add the name
+ m_name = (String) configuration.get("name");
+
+ // Create the standard handlers and add these handlers to the list
+ for (int i = 0; i < IPojoConfiguration.INTERNAL_COMPOSITE_HANDLERS.length; i++) {
+ // Create a new instance
+ try {
+ CompositeHandler h = (CompositeHandler) IPojoConfiguration.INTERNAL_COMPOSITE_HANDLERS[i].newInstance();
+ h.configure(this, cm, configuration);
+ } catch (InstantiationException e) {
+ m_factory.getLogger().log(Logger.ERROR, "[" + m_name + "] Cannot instantiate the handler " + IPojoConfiguration.INTERNAL_HANDLERS[i] + " : " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ m_factory.getLogger().log(Logger.ERROR, "[" + m_name + "] Cannot instantiate the handler " + IPojoConfiguration.INTERNAL_HANDLERS[i] + " : " + e.getMessage());
+ }
+ }
+
+ // Look for namespaces
+ for (int i = 0; i < cm.getNamespaces().length; i++) {
+ if (!cm.getNamespaces()[i].equals("")) {
+ // It is not an internal handler, try to load it
+ try {
+ Class c = m_context.getBundle().loadClass(cm.getNamespaces()[i]);
+ CompositeHandler h = (CompositeHandler) c.newInstance();
+ h.configure(this, cm, configuration);
+ } catch (ClassNotFoundException e) {
+ m_factory.getLogger().log(Logger.ERROR, "[" + m_name + "] Cannot instantiate the handler " + cm.getNamespaces()[i] + " : " + e.getMessage());
+ } catch (InstantiationException e) {
+ m_factory.getLogger().log(Logger.ERROR, "[" + m_name + "] Cannot instantiate the handler " + cm.getNamespaces()[i] + " : " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ m_factory.getLogger().log(Logger.ERROR, "[" + m_name + "] Cannot instantiate the handler " + cm.getNamespaces()[i] + " : " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
+ * @return the component type information.
+ */
+ public ComponentDescription getComponentDescription() { return m_componentDesc; }
+
+ /**
+ * @return the instance description.
+ */
+ public synchronized InstanceDescription getInstanceDescription() {
+ int componentState = getState();
+ InstanceDescription instanceDescription = new InstanceDescription(m_name, componentState, getContext().getBundle().getBundleId(), m_componentDesc);
+ CompositeHandler[] handlers = getRegistredCompositeHandlers();
+ for (int i = 0; i < handlers.length; i++) {
+ instanceDescription.addHandler(handlers[i].getDescription());
+ }
+
+ // Get instances description of internal instance
+ ServiceReference[] refs;
+ try {
+ refs = m_internalContext.getServiceReferences(Architecture.class.getName(), null);
+ if (refs != null) {
+ for (int i = 0; i < refs.length; i++) {
+ Architecture arch = (Architecture) m_internalContext.getService(refs[i]);
+ instanceDescription.addInstance(arch.getInstanceDescription());
+ m_internalContext.ungetService(refs[i]);
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace(); // Should not happen
+ }
+ return instanceDescription;
+ }
+
+ /**
+ * @return the list of the registred handlers.
+ */
+ public CompositeHandler[] getRegistredCompositeHandlers() { return m_handlers; }
+
+ /**
+ * Return a specified handler.
+ * @param name : class name of the handler to find
+ * @return : the handler, or null if not found
+ */
+ public CompositeHandler getCompositeHandler(String name) {
+ for (int i = 0; i < m_handlers.length; i++) {
+ if (m_handlers[i].getClass().getName().equalsIgnoreCase(name)) { return m_handlers[i]; }
+ }
+ return null;
+ }
+
+ // ===================== Lifecycle management =====================
+
+ /**
+ * Start the instance manager.
+ */
+ public void start() {
+ if (m_state != STOPPED) { return; } // Instance already started
+
+ // Start all the handlers
+ m_factory.getLogger().log(Logger.INFO, "[" + m_name + "] Start the instance manager with " + m_handlers.length + " handlers");
+
+ // The new state of the component is UNRESOLVED
+ m_state = INVALID;
+
+ m_internalContext.start(); // Turn on the factory tracking
+
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].start();
+ }
+
+ // Defines the state of the component :
+ checkInstanceState();
+ }
+
+ /**
+ * Stop the instance manager.
+ */
+ public void stop() {
+ if (m_state == STOPPED) { return; } // Instance already stopped
+
+ setState(INVALID);
+ // Stop all the handlers
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].stop();
+ }
+
+ m_internalContext.stop(); // Turn off the factory tracking
+ m_state = STOPPED;
+ m_factory.stopped(this);
+ }
+
+ /**
+ * Set the state of the component.
+ * if the state changed call the stateChanged(int) method on the handlers
+ */
+ public void setState(int state) {
+ if (m_state != state) {
+
+ // Log the state change
+ if (state == INVALID) { m_factory.getLogger().log(Logger.INFO, "[" + m_name + "] State -> INVALID"); }
+ if (state == VALID) { m_factory.getLogger().log(Logger.INFO, "[" + m_name + "] State -> VALID"); }
+
+ // The state changed call the handler stateChange method
+ m_state = state;
+ for (int i = m_handlers.length - 1; i > -1; i--) {
+ m_handlers[i].stateChanged(state);
+ }
+ }
+ }
+
+ /**
+ * @return the actual state of the component.
+ */
+ public int getState() { return m_state; }
+
+ /**
+ * @see org.apache.felix.ipojo.ComponentInstance#isStarted()
+ */
+ public boolean isStarted() { return m_state != STOPPED; }
+
+ // ===================== end Lifecycle management =====================
+
+ // ================== Class & Instance management ===================
+
+ /**
+ * @return the factory of the component
+ */
+ public ComponentFactory getFactory() { return m_factory; }
+
+ // ======================== Handlers Management ======================
+
+ /**
+ * Register the given handler to the current instance manager.
+ * @param h : the handler to register
+ */
+ public void register(CompositeHandler h) {
+ for (int i = 0; (m_handlers != null) && (i < m_handlers.length); i++) {
+ if (m_handlers[i] == h) {
+ return;
+ }
+ }
+
+ if (m_handlers != null) {
+ CompositeHandler[] newList = new CompositeHandler[m_handlers.length + 1];
+ System.arraycopy(m_handlers, 0, newList, 0, m_handlers.length);
+ newList[m_handlers.length] = h;
+ m_handlers = newList;
+ }
+ }
+
+ /**
+ * Unregister the given handler.
+ * @param h : the handler to unregiter
+ */
+ public void unregister(CompositeHandler h) {
+ int idx = -1;
+ for (int i = 0; i < m_handlers.length; i++) {
+ if (m_handlers[i] == h) {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx >= 0) {
+ if ((m_handlers.length - 1) == 0) {
+ m_handlers = new CompositeHandler[0];
+ } else {
+ CompositeHandler[] newList = new CompositeHandler[m_handlers.length - 1];
+ System.arraycopy(m_handlers, 0, newList, 0, idx);
+ if (idx < newList.length) {
+ System.arraycopy(
+ m_handlers, idx + 1, newList, idx, newList.length - idx);
+ }
+ m_handlers = newList;
+ }
+ }
+ }
+
+
+ /**
+ * @return the parent context of the instance.
+ */
+ public BundleContext getContext() { return m_context; }
+
+ /**
+ * Check the state of all handlers.
+ */
+ public void checkInstanceState() {
+ m_factory.getLogger().log(Logger.INFO, "[" + m_name + "] Check the instance state");
+ boolean isValid = true;
+ for (int i = 0; i < m_handlers.length; i++) {
+ boolean b = m_handlers[i].isValid();
+ isValid = isValid && b;
+ }
+
+ // Update the component state if necessary
+ if (!isValid && m_state == VALID) {
+ // Need to update the state to UNRESOLVED
+ setState(INVALID);
+ return;
+ }
+ if (isValid && m_state == INVALID) { setState(VALID); }
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ComponentInstance#getInstanceName()
+ */
+ public String getInstanceName() { return m_name; }
+
+ /**
+ * @see org.apache.felix.ipojo.ComponentInstance#reconfigure(java.util.Dictionary)
+ */
+ public void reconfigure(Dictionary configuration) {
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].reconfigure(configuration);
+ }
+ }
+
+ /**
+ * @return the internal service context.
+ */
+ public ServiceContext getServiceContext() { return m_internalContext; }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/IPojoConfiguration.java b/ipojo/src/main/java/org/apache/felix/ipojo/IPojoConfiguration.java
index 2df12ee..e431196 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/IPojoConfiguration.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/IPojoConfiguration.java
@@ -18,6 +18,8 @@
*/
package org.apache.felix.ipojo;
+import org.apache.felix.ipojo.composite.service.importer.ImportExportHandler;
+import org.apache.felix.ipojo.composite.service.instantiator.ServiceInstantiatorHandler;
import org.apache.felix.ipojo.handlers.architecture.ArchitectureHandler;
import org.apache.felix.ipojo.handlers.configuration.ConfigurationHandler;
import org.apache.felix.ipojo.handlers.dependency.DependencyHandler;
@@ -49,4 +51,13 @@
ArchitectureHandler.class
};
+ /**
+ * Available composite handlers in the iPOJO bundle.
+ */
+ public static final Class[] INTERNAL_COMPOSITE_HANDLERS = new Class[] {
+ ServiceInstantiatorHandler.class,
+ ImportExportHandler.class,
+ org.apache.felix.ipojo.composite.architecture.ArchitectureHandler.class
+ };
+
}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/IPojoContext.java b/ipojo/src/main/java/org/apache/felix/ipojo/IPojoContext.java
index a654eeb..85166b7 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/IPojoContext.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/IPojoContext.java
@@ -196,12 +196,12 @@
* Set the instance to the service context.
* @param ci : the component instance
*/
- public void setComponentInstance(ComponentInstance ci) { m_serviceContext.setComponentInstance(ci); }
+ //public void setComponentInstance(ComponentInstance ci) { m_serviceContext.setComponentInstance(ci); }
/**
* Get the instance manager from the service context.
* @return the component manager of the service context
*/
- public ComponentInstance getComponentInstance() { return m_serviceContext.getComponentInstance(); }
+ //public ComponentInstance getComponentInstance() { return m_serviceContext.getComponentInstance(); }
}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/InstanceManager.java b/ipojo/src/main/java/org/apache/felix/ipojo/InstanceManager.java
index 29e885f..5f9cda3 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/InstanceManager.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/InstanceManager.java
@@ -165,7 +165,7 @@
*/
public InstanceDescription getInstanceDescription() {
int componentState = getState();
- InstanceDescription instanceDescription = new InstanceDescription(m_name, m_className, componentState, getContext().getBundle().getBundleId());
+ InstanceDescription instanceDescription = new InstanceDescription(m_name, componentState, getContext().getBundle().getBundleId(), m_componentDesc);
String[] objects = new String[getPojoObjects().length];
for (int i = 0; i < getPojoObjects().length; i++) {
@@ -243,6 +243,8 @@
m_pojoObjects = new Object[0];
m_state = STOPPED;
+
+ m_factory.stopped(this);
}
/**
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/ServiceContext.java b/ipojo/src/main/java/org/apache/felix/ipojo/ServiceContext.java
index 6afbe1b..24a4176 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/ServiceContext.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/ServiceContext.java
@@ -108,6 +108,6 @@
* Set the component instance using the service context.
* @param ci
*/
- void setComponentInstance(ComponentInstance ci);
+ //void setComponentInstance(ComponentInstance ci);
}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/architecture/ComponentDescription.java b/ipojo/src/main/java/org/apache/felix/ipojo/architecture/ComponentDescription.java
index 8598404..a55db2c 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/architecture/ComponentDescription.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/architecture/ComponentDescription.java
@@ -55,11 +55,23 @@
}
/**
+ * Constructor for composite.
+ * @param name : name of the component type (factory name).
+ */
+ public ComponentDescription(String name) {
+ m_name = name;
+ }
+
+ /**
* @see java.lang.Object#toString()
*/
public String toString() {
String res = "";
- res += "Component Type : " + m_name + " (" + m_className + ") \n";
+ if (m_className == null) {
+ res += "Component Type : " + m_name + " (Composition) \n";
+ } else {
+ res += "Component Type : " + m_name + " (" + m_className + ") \n";
+ }
for (int i = 0; i < m_providedServiceSpecification.length; i++) {
res += "\tProvides : " + m_providedServiceSpecification[i] + "\n";
}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/architecture/InstanceDescription.java b/ipojo/src/main/java/org/apache/felix/ipojo/architecture/InstanceDescription.java
index ba0f895..39b7b6b 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/architecture/InstanceDescription.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/architecture/InstanceDescription.java
@@ -25,12 +25,6 @@
public class InstanceDescription {
/**
- * The Component class name.
- * This String is the identifier of the component.
- */
- private String m_className;
-
- /**
* The name of the component (instance).
*/
private String m_name;
@@ -51,24 +45,35 @@
private int m_state;
/**
- * BundleId of the component.
+ * BundleId who create the instance.
*/
private long m_bundleId;
+
+ /**
+ * Component Type of the instance.
+ */
+ private ComponentDescription m_type;
+
+ /**
+ * COntained instance list.
+ */
+ private InstanceDescription[] m_containedInstances = new InstanceDescription[0];
/**
* Constructor.
* @param name : the name of the component instance.
* @param state : the state of the instance.
- * @param className : implementation class name.
* @param bundleId : bundle id owning this instance.
+ * @param cd : the component type description of this instance.
*/
- public InstanceDescription(String name, String className, int state, long bundleId) {
+ public InstanceDescription(String name, int state, long bundleId, ComponentDescription cd) {
m_name = name;
- m_className = className;
m_state = state;
m_createdObjects = new String[0];
m_handlers = new HandlerDescription[0];
+ m_containedInstances = new InstanceDescription[0];
m_bundleId = bundleId;
+ m_type = cd;
}
/**
@@ -87,9 +92,9 @@
public void setCreatedObjects(String[] objects) { m_createdObjects = objects; }
/**
- * @return : the class name of the component
+ * @return : the component type description of this instance.
*/
- public String getClassName() { return m_className; }
+ public ComponentDescription getComponentDescription() { return m_type; }
/**
* @return the live handler list
@@ -113,6 +118,24 @@
newHd[m_handlers.length] = hd;
m_handlers = newHd;
}
+
+ /**
+ * Add an instance description to the contained instance list.
+ * @param inst : the handler description to add
+ */
+ public void addInstance(InstanceDescription inst) {
+ // Verify that the dependency description is not already in the array.
+ for (int i = 0; (i < m_containedInstances.length); i++) {
+ if (m_containedInstances[i] == inst) {
+ return; //NOTHING TO DO, the description is already in the array
+ }
+ }
+ // The component Description is not in the array, add it
+ InstanceDescription[] newCi = new InstanceDescription[m_containedInstances.length + 1];
+ System.arraycopy(m_containedInstances, 0, newCi, 0, m_containedInstances.length);
+ newCi[m_containedInstances.length] = inst;
+ m_containedInstances = newCi;
+ }
/**
* Set the state of the component.
@@ -129,6 +152,11 @@
* @return the bundle id owning the component implementation class.
*/
public long getBundleId() { return m_bundleId; }
+
+ /**
+ * @return the list of contained instances.
+ */
+ public InstanceDescription[] getContainedInstances() { return m_containedInstances; }
}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/CompositeServiceContext.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/CompositeServiceContext.java
new file mode 100644
index 0000000..5f4bb40
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/CompositeServiceContext.java
@@ -0,0 +1,267 @@
+/*
+ * 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.composite;
+
+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.ServiceContext;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * CompositeServiceContext Class.
+ * This class provides an implementation of the service context for composite.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class CompositeServiceContext implements ServiceContext, ServiceListener {
+
+ private class Record {
+ private ServiceReference m_ref;
+ private ServiceRegistration m_reg;
+ private FactoryProxy m_fact;
+ }
+
+ private List m_factories = new ArrayList();
+
+ private BundleContext m_parent;
+
+ /**
+ * Internal service registry.
+ */
+ private ServiceRegistry m_registry;
+
+ /**
+ * Component Instance who creates this registry.
+ */
+ private ComponentInstance m_instance;
+
+ /**
+ * Constructor.
+ * This constructor instantiate a service registry with the given bundle context.
+ * @param bc : the bundle context
+ */
+ public CompositeServiceContext(BundleContext bc) {
+ m_registry = new ServiceRegistry(bc);
+ m_parent = bc;
+ }
+
+ /**
+ * Constructor.
+ * @param bc : the bundle context
+ * @param ci : the component instance owning this context
+ */
+ public CompositeServiceContext(BundleContext bc, ComponentInstance ci) {
+ this(bc);
+ m_parent = bc;
+ m_instance = ci;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener)
+ */
+ public void addServiceListener(ServiceListener arg0) {
+ m_registry.addServiceListener(arg0);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#addServiceListener(org.osgi.framework.ServiceListener, java.lang.String)
+ */
+ public void addServiceListener(ServiceListener arg0, String arg1) throws InvalidSyntaxException {
+ m_registry.addServiceListener(arg0, arg1);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#getAllServiceReferences(java.lang.String, java.lang.String)
+ */
+ public ServiceReference[] getAllServiceReferences(String arg0, String arg1) throws InvalidSyntaxException {
+ return m_registry.getAllServiceReferences(arg0, arg1);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#getComponentInstance()
+ */
+ public ComponentInstance getComponentInstance() {
+ return m_instance;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#getService(org.osgi.framework.ServiceReference)
+ */
+ public Object getService(ServiceReference arg0) {
+ return m_registry.getService(m_instance, arg0);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#getServiceReference(java.lang.String)
+ */
+ public ServiceReference getServiceReference(String arg0) {
+ return m_registry.getServiceReference(arg0);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#getServiceReferences(java.lang.String, java.lang.String)
+ */
+ public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ return m_registry.getServiceReferences(clazz, filter);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
+ */
+ public ServiceRegistration registerService(String[] arg0, Object arg1, Dictionary arg2) {
+ return m_registry.registerService(m_instance, arg0, arg1, arg2);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#registerService(java.lang.String, java.lang.Object, java.util.Dictionary)
+ */
+ public ServiceRegistration registerService(String arg0, Object arg1, Dictionary arg2) {
+ return m_registry.registerService(m_instance, arg0, arg1, arg2);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#removeServiceListener(org.osgi.framework.ServiceListener)
+ */
+ public void removeServiceListener(ServiceListener arg0) {
+ m_registry.removeServiceListener(arg0);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.ServiceContext#ungetService(org.osgi.framework.ServiceReference)
+ */
+ public boolean ungetService(ServiceReference arg0) {
+ return m_registry.ungetService(m_instance, arg0);
+ }
+
+ /**
+ * Initiate the factory list.
+ */
+ private void importFactories() {
+ try {
+ ServiceReference[] refs = m_parent.getServiceReferences(Factory.class.getName(), null);
+ if (refs != null) {
+ for (int i = 0; i < refs.length; i++) {
+ importFactory(refs[i]);
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace(); // Should not happen
+ }
+ }
+
+ /**
+ * Import a factory form the parent to the internal registry.
+ * @param ref : the reference of the factory to import.
+ */
+ private void importFactory(ServiceReference ref) {
+ //System.out.println("Add a new factory in the scope : " + ref.getProperty(Constants.SERVICE_PID));
+ Record rec = new Record();
+ m_factories.add(rec);
+ Dictionary dict = new Properties();
+ for (int j = 0; j < ref.getPropertyKeys().length; j++) {
+ dict.put(ref.getPropertyKeys()[j], ref.getProperty(ref.getPropertyKeys()[j]));
+ }
+ rec.m_fact = new FactoryProxy((Factory) m_parent.getService(ref), this);
+ rec.m_reg = registerService(Factory.class.getName(), rec.m_fact, dict);
+ rec.m_ref = ref;
+ }
+
+ /**
+ * Remove a factory of the available factory list.
+ * @param ref : the reference on the factory to remove.
+ */
+ private void removeFactory(ServiceReference ref) {
+ //System.out.println("Remove a factory from the scope : " + ref.getProperty(Constants.SERVICE_PID));
+ for (int i = 0; i < m_factories.size(); i++) {
+ Record rec = (Record) m_factories.get(i);
+ if (rec.m_ref == ref) {
+ rec.m_reg.unregister();
+ rec.m_fact = null;
+ m_parent.ungetService(rec.m_ref);
+ m_factories.remove(rec);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Start the registry management.
+ */
+ public void start() {
+ importFactories();
+ try {
+ m_parent.addServiceListener(this, "(" + Constants.OBJECTCLASS + "=" + Factory.class.getName() + ")");
+ } catch (InvalidSyntaxException e) {
+ // Should not happen
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Stop the registry management.
+ */
+ public synchronized void stop() {
+ m_parent.removeServiceListener(this);
+ m_registry.reset();
+ for (int i = 0; i < m_factories.size(); i++) {
+ Record rec = (Record) m_factories.get(i);
+ removeFactory(rec.m_ref);
+ }
+ }
+
+ /**
+ * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+ */
+ public void serviceChanged(ServiceEvent event) {
+ if (event.getType() == ServiceEvent.REGISTERED) {
+ if (!containsRef(event.getServiceReference())) {
+ importFactory(event.getServiceReference());
+ }
+ return;
+ }
+ if (event.getType() == ServiceEvent.UNREGISTERING) {
+ if (containsRef(event.getServiceReference())) {
+ removeFactory(event.getServiceReference());
+ }
+ }
+ }
+
+ /**
+ * Check if the factory list contain the given reference.
+ * @param ref : the reference to find.
+ * @return true if the list contains the given reference.
+ */
+ private boolean containsRef(ServiceReference ref) {
+ for (int i = 0; i < m_factories.size(); i++) {
+ Record rec = (Record) m_factories.get(i);
+ if (rec.m_ref == ref) { return true; }
+ }
+ return false;
+ }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.java
new file mode 100644
index 0000000..0244ae9
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/FactoryProxy.java
@@ -0,0 +1,82 @@
+/*
+ * 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.composite;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.architecture.ComponentDescription;
+
+/**
+ * Bridge representing a Factory inside a composition.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class FactoryProxy implements Factory {
+
+ private Factory m_delegate;
+ private ServiceContext m_context;
+
+ /**
+ * Constructor.
+ * @param fact : the targetted factory.
+ * @param s : the service context to target.
+ */
+ public FactoryProxy(Factory fact, ServiceContext s) {
+ m_delegate = fact;
+ m_context = s;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Factory#createComponentInstance(java.util.Dictionary)
+ */
+ public ComponentInstance createComponentInstance(Dictionary configuration) throws UnacceptableConfiguration {
+ return m_delegate.createComponentInstance(configuration, m_context);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Factory#createComponentInstance(java.util.Dictionary, org.apache.felix.ipojo.ServiceContext)
+ */
+ public ComponentInstance createComponentInstance(Dictionary configuration, ServiceContext serviceContext) throws UnacceptableConfiguration {
+ return m_delegate.createComponentInstance(configuration, serviceContext);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Factory#getComponentDescription()
+ */
+ public ComponentDescription getComponentDescription() { return m_delegate.getComponentDescription(); }
+
+ /**
+ * @see org.apache.felix.ipojo.Factory#getName()
+ */
+ public String getName() { return m_delegate.getName(); }
+
+ /**
+ * @see org.apache.felix.ipojo.Factory#isAcceptable(java.util.Dictionary)
+ */
+ public boolean isAcceptable(Dictionary conf) { return m_delegate.isAcceptable(conf); }
+
+ /**
+ * @see org.apache.felix.ipojo.Factory#reconfigure(java.util.Dictionary)
+ */
+ public void reconfigure(Dictionary conf) throws UnacceptableConfiguration { m_delegate.reconfigure(conf); }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/ServiceReferenceImpl.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/ServiceReferenceImpl.java
new file mode 100644
index 0000000..ae2f1aa
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/ServiceReferenceImpl.java
@@ -0,0 +1,87 @@
+/*
+ * 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.composite;
+
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Internal service reference implemenation.
+ * This class is used for in the composition.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ServiceReferenceImpl implements ServiceReference {
+
+ /**
+ * Service Registration attached to the service reference.
+ */
+ private ServiceRegistrationImpl m_registration = null;
+
+ /**
+ * Constructor.
+ * @param cm : component instance publishing the service.
+ * @param sr : registration attached to this service reference.
+ */
+ public ServiceReferenceImpl(ComponentInstance cm, ServiceRegistrationImpl sr) { m_registration = sr; }
+
+ /**
+ * Not supported in composite.
+ * @see org.osgi.framework.ServiceReference#getBundle()
+ */
+ public Bundle getBundle() {
+ throw new UnsupportedOperationException("getUsingBundles is not supported in scope");
+ }
+
+ /**
+ * @return the service registration for this service reference.
+ */
+ public ServiceRegistrationImpl getServiceRegistration() { return m_registration; }
+
+ /**
+ * @see org.osgi.framework.ServiceReference#getProperty(java.lang.String)
+ */
+ public Object getProperty(String s) {
+ return m_registration.getProperty(s);
+ }
+
+ /**
+ * @see org.osgi.framework.ServiceReference#getPropertyKeys()
+ */
+ public String[] getPropertyKeys() {
+ return m_registration.getPropertyKeys();
+ }
+
+ /**
+ * Not supported in composite.
+ * @see org.osgi.framework.ServiceReference#getUsingBundles()
+ */
+ public Bundle[] getUsingBundles() {
+ throw new UnsupportedOperationException("getUsingBundles is not supported in scope");
+ }
+
+ /**
+ * @see org.osgi.framework.ServiceReference#isAssignableTo(org.osgi.framework.Bundle, java.lang.String)
+ */
+ public boolean isAssignableTo(Bundle arg0, String arg1) {
+ return true;
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/ServiceRegistrationImpl.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/ServiceRegistrationImpl.java
new file mode 100644
index 0000000..4734c86
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/ServiceRegistrationImpl.java
@@ -0,0 +1,232 @@
+/*
+ * 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.composite;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.InstanceManager;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Internal service registration implemenation.
+ * This class is used for in the composition.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ServiceRegistrationImpl implements ServiceRegistration {
+
+ /**
+ * Service Registry.
+ */
+ private ServiceRegistry m_registry = null;
+
+ /**
+ * Interfaces associated with the service object.
+ */
+ private String[] m_classes = null;
+
+ /**
+ * Service Id associated with the service object.
+ */
+ private Long m_serviceId = null;
+
+ /**
+ * Service object.
+ */
+ private Object m_svcObj = null;
+
+ /**
+ * Service factory interface.
+ */
+ private ServiceFactory m_factory = null;
+
+ /**
+ * Associated property dictionary.
+ */
+ private Map m_propMap = null;
+
+ /**
+ * Re-usable service reference.
+ */
+ private ServiceReferenceImpl m_ref = null;
+
+ /**
+ * Constructor.
+ * @param registry : the service registry
+ * @param cm : component instance
+ * @param classes : published interfaces array
+ * @param serviceId : the unique service id
+ * @param svcObj : the service object or the service factory object
+ * @param dict : service properties
+ */
+ public ServiceRegistrationImpl(ServiceRegistry registry, ComponentInstance cm, String[] classes, Long serviceId, Object svcObj, Dictionary dict) {
+ m_registry = registry;
+ m_classes = classes;
+ m_serviceId = serviceId;
+ m_svcObj = svcObj;
+ m_factory = (m_svcObj instanceof ServiceFactory)
+ ? (ServiceFactory) m_svcObj : null;
+
+ initializeProperties(dict);
+
+ // This reference is the "standard" reference for this service and will always be returned by getReference().
+ // Since all reference to this service are supposed to be equal, we use the hashcode of this reference for
+ // a references to this service in ServiceReference.
+ m_ref = new ServiceReferenceImpl(cm, this);
+ }
+
+ /**
+ * @return true if the service registration is valid.
+ */
+ protected boolean isValid() { return (m_svcObj != null); }
+
+ /**
+ * @see org.osgi.framework.ServiceRegistration#getReference()
+ */
+ public ServiceReference getReference() { return m_ref; }
+
+ /**
+ * @see org.osgi.framework.ServiceRegistration#setProperties(java.util.Dictionary)
+ */
+ public void setProperties(Dictionary dict) {
+ // Make sure registration is valid.
+ if (!isValid()) { throw new IllegalStateException("The service registration is no longer valid."); }
+ // Set the properties.
+ initializeProperties(dict);
+ // Tell registry about it.
+ m_registry.servicePropertiesModified(this);
+ }
+
+ /**
+ * @see org.osgi.framework.ServiceRegistration#unregister()
+ */
+ public void unregister() {
+ if (m_svcObj != null) {
+ m_registry.unregisterService(this);
+ m_svcObj = null;
+ m_factory = null;
+ } else {
+ throw new IllegalStateException("Service already unregistered.");
+ }
+ }
+
+ /**
+ * Look for a property in the service properties.
+ * @param key : property key
+ * @return the object associated with the key or null if the key is not present.
+ */
+ protected Object getProperty(String key) {
+ return m_propMap.get(key);
+ }
+
+ /**
+ * Property Keys List.
+ */
+ private transient ArrayList m_list = new ArrayList();
+
+ /**
+ * @return the property keys list.
+ */
+ protected String[] getPropertyKeys() {
+ synchronized (m_propMap) {
+ m_list.clear();
+ Iterator i = m_propMap.entrySet().iterator();
+ while (i.hasNext()) {
+ Map.Entry entry = (Map.Entry) i.next();
+ m_list.add(entry.getKey());
+ }
+ return (String[]) m_list.toArray(new String[m_list.size()]);
+ }
+ }
+
+ /**
+ * @return the service object. Call the service factory if needed.
+ */
+ protected Object getService() {
+ // If the service object is a service factory, then
+ // let it create the service object.
+ if (m_factory != null) {
+ return getFactoryUnchecked();
+ } else { return m_svcObj; }
+ }
+
+ /**
+ * Initialize properties.
+ * @param dict : serivce properties to publish.
+ */
+ private void initializeProperties(Dictionary dict) {
+ // Create a case insensitive map.
+ if (m_propMap == null) {
+ m_propMap = new StringMap(false);
+ } else {
+ m_propMap.clear();
+ }
+
+ if (dict != null) {
+ Enumeration keys = dict.keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ m_propMap.put(key, dict.get(key));
+ }
+ }
+ // Add the framework assigned properties.
+ m_propMap.put(Constants.OBJECTCLASS, m_classes);
+ m_propMap.put(Constants.SERVICE_ID, m_serviceId);
+ }
+
+ /**
+ * @return the service object via the service factory invocation.
+ */
+ private Object getFactoryUnchecked() {
+ return m_factory.getService(null, this);
+ }
+
+ /**
+ * Unget a service.
+ * (Internal Method)
+ * @param cm : component instance using the service.
+ * @param svcObj : the unget service object.
+ */
+ private void ungetFactoryUnchecked(ComponentInstance cm, Object svcObj) {
+ if (cm instanceof InstanceManager) {
+ m_factory.ungetService(((InstanceManager) cm).getContext().getBundle(), this, svcObj);
+ }
+
+ }
+
+ /**
+ * Unget a service.
+ * @param cm : component instance using the service.
+ * @param srvObj : the unget service object.
+ */
+ public void ungetService(ComponentInstance cm, Object srvObj) {
+ // If the service object is a service factory, then let is release the service object.
+ if (m_factory != null) {
+ ungetFactoryUnchecked(cm, srvObj);
+ }
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/ServiceRegistry.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/ServiceRegistry.java
new file mode 100644
index 0000000..381b16b
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/ServiceRegistry.java
@@ -0,0 +1,306 @@
+/*
+ * 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.composite;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Internal Service Registry.
+ * This class is used for in the composition.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ServiceRegistry {
+
+ /**
+ * Service Id index.
+ */
+ private long m_serviceId = 1L;
+
+ /**
+ * List of service listeners.
+ */
+ private ArrayList m_listeners = new ArrayList(); // ListenerInfo List
+
+ /**
+ * List of service registration.
+ */
+ private ArrayList m_regs = new ArrayList();
+
+ /**
+ * A "real" bundle context to create LDAP filter.
+ */
+ private BundleContext m_bc; //BundleContext to create Filter
+
+ /**
+ * Listener info structure.
+ */
+ private class ListenerInfo {
+ private ServiceListener m_listener;
+ private Filter m_filter;
+ }
+
+ /**
+ * Constructor.
+ * @param bc : bundle context.
+ */
+ public ServiceRegistry(BundleContext bc) {
+ m_bc = bc;
+ }
+
+ /**
+ * Add a given service listener with no filter.
+ * @param arg0 : the service listener to add
+ */
+ public void addServiceListener(ServiceListener arg0) {
+ ListenerInfo li = new ListenerInfo();
+ li.m_listener = arg0;
+ li.m_filter = null;
+ m_listeners.add(li);
+ }
+
+ /**
+ * Unget a service.
+ * @param cm : instance releasing the service.
+ * @param ref : released reference.
+ * @return true if the unget success
+ */
+ public boolean ungetService(ComponentInstance cm, ServiceReference ref) {
+
+ ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
+ if (!reg.isValid()) {
+ return false;
+ } else {
+ reg.ungetService(cm, reg.getService());
+ return true;
+ }
+ }
+
+ /**
+ * Unregister a service listener.
+ * @param arg0 : the service listenenr to remove
+ */
+ public void removeServiceListener(ServiceListener arg0) {
+ m_listeners.remove(arg0);
+ }
+
+ /**
+ * Register a service.
+ * @param cm : provider instance.
+ * @param clazz : provided interface.
+ * @param svcObj : service object of service factory object.
+ * @param dict : service properties.
+ * @return the created service registration.
+ */
+ public ServiceRegistration registerService(ComponentInstance cm, String clazz, Object svcObj, Dictionary dict) {
+ synchronized (m_regs) {
+ ServiceRegistrationImpl reg = new ServiceRegistrationImpl(this, cm, new String[] {clazz}, new Long(m_serviceId++), svcObj, dict);
+ m_regs.add(reg);
+ fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
+ return reg;
+ }
+ }
+
+ /**
+ * Register a service.
+ * @param cm : provider instance.
+ * @param clazzes : provided interfaces.
+ * @param svcObj : service object of service factory object.
+ * @param dict : service properties.
+ * @return the created service registration.
+ */
+ public ServiceRegistration registerService(ComponentInstance cm, String[] clazzes, Object svcObj, Dictionary dict) {
+ synchronized (m_regs) {
+ ServiceRegistrationImpl reg = new ServiceRegistrationImpl(this, cm, clazzes, new Long(m_serviceId++), svcObj, dict);
+ m_regs.add(reg);
+ fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
+ return reg;
+ }
+ }
+
+ /**
+ * Dispatch a service event.
+ * @param event : the service to dispatch
+ */
+ private void fireServiceChanged(ServiceEvent event) {
+ synchronized (this) {
+ // Iterate on the service listenner list to notify service listener
+ for (int i = 0; i < m_listeners.size(); i++) {
+ ListenerInfo li = (ListenerInfo) m_listeners.get(i);
+ ServiceReference sr = event.getServiceReference();
+ if (li.m_filter == null) { li.m_listener.serviceChanged(event); }
+ if (li.m_filter != null && li.m_filter.match(sr)) { li.m_listener.serviceChanged(event); }
+ }
+ }
+ }
+
+ /**
+ * Get available (and accessible) service references.
+ * @param className : required interface
+ * @param expr : LDAP filter
+ * @return : the list of available service references.
+ * @throws InvalidSyntaxException occurs when the LDAP filter is malformed.
+ */
+ public ServiceReference[] getServiceReferences(String className, String expr) throws InvalidSyntaxException {
+ synchronized (this) {
+ // Define filter if expression is not null.
+ Filter filter = null;
+ if (expr != null) { filter = m_bc.createFilter(expr); }
+
+ ArrayList refs = new ArrayList();
+
+ for (int i = 0; i < m_regs.size(); i++) {
+ ServiceRegistrationImpl reg = (ServiceRegistrationImpl) m_regs.get(i);
+ // Determine if the registered services matches the search criteria.
+ boolean matched = false;
+
+ // If className is null, then look at filter only.
+ if ((className == null) && ((filter == null) || filter.match(reg.getReference()))) {
+ matched = true;
+ } else if (className != null) {
+ // If className is not null, then first match the
+ // objectClass property before looking at the
+ // filter.
+ String[] objectClass = (String[]) ((ServiceRegistrationImpl) reg).getProperty(Constants.OBJECTCLASS);
+ for (int classIdx = 0; classIdx < objectClass.length; classIdx++) {
+ if (objectClass[classIdx].equals(className) && ((filter == null) || filter.match(reg.getReference()))) {
+ matched = true;
+ break;
+ }
+ }
+ }
+
+ // Add reference if it was a match.
+ if (matched) { refs.add(reg.getReference()); }
+ }
+
+ if (refs.size() > 0) { return (ServiceReference[]) refs.toArray(new ServiceReference[refs.size()]); }
+ return null;
+ }
+ }
+
+ /**
+ * Look for a service reference.
+ * @param clazz : required interface.
+ * @return the first available provider or null if none available.
+ */
+ public ServiceReference getServiceReference(String clazz) {
+ synchronized (this) {
+ try {
+ ServiceReference[] refs = getServiceReferences(clazz, null);
+ if (refs != null) { return refs[0]; } // If the refs != null we are sure that it exist one references or more.
+ } catch (InvalidSyntaxException ex) { System.err.println("Scope Service Registry : Problem when look for service reference" + ex.getMessage()); }
+ return null;
+ }
+ }
+
+ /**
+ * Get a service object.
+ * @param cm : component instance requiring the service.
+ * @param ref : the required reference.
+ * @return the service object.
+ */
+ public Object getService(ComponentInstance cm, ServiceReference ref) {
+ synchronized (this) {
+ // Look for the service registration for this ref
+ ServiceRegistrationImpl reg = ((ServiceReferenceImpl) ref).getServiceRegistration();
+ if (reg.isValid()) {
+ // Delegate the service providing to the service registration
+ return reg.getService();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Get all service references consistent with the given interface and filter.
+ * @param clazz : the required interface.
+ * @param filter : the LDAP filter.
+ * @return the list of all service reference or null if none available.
+ * @throws InvalidSyntaxException
+ */
+ public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ synchronized (this) {
+ // Can delegate on getServiceReference, indeed their is no test on the "modularity" conflict.
+ return getServiceReferences(clazz, filter);
+ }
+ }
+
+ /**
+ * Add a service listener with a filter.
+ * @param listener : the service listener to add
+ * @param filter : LDAP filter
+ */
+ public void addServiceListener(ServiceListener listener, String filter) {
+ synchronized (this) {
+ ListenerInfo li = new ListenerInfo();
+ li.m_listener = listener;
+ try {
+ li.m_filter = m_bc.createFilter(filter);
+ } catch (InvalidSyntaxException ex) { System.err.println("Scope Service Registry : Problem when creatin a service listener " + ex.getMessage()); }
+ m_listeners.add(li);
+ }
+ }
+
+ /**
+ * Dispatch a service properties modified event.
+ * @param reg : the implicated service registration.
+ */
+ public void servicePropertiesModified(ServiceRegistrationImpl reg) {
+ fireServiceChanged(new ServiceEvent(ServiceEvent.MODIFIED, reg.getReference()));
+ }
+
+ /**
+ * Unregister a service.
+ * @param reg : the service registration to unregister
+ */
+ public void unregisterService(ServiceRegistrationImpl reg) {
+ synchronized (this) {
+ m_regs.remove(reg);
+ fireServiceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, reg.getReference()));
+ }
+ }
+
+ /**
+ * @return the size of the service registry.
+ */
+ protected int getSize() {
+ return m_regs.size();
+ }
+
+ /**
+ * Reset the service registry.
+ */
+ protected void reset() {
+ m_serviceId = 1L;
+ m_listeners = new ArrayList();
+ m_regs = new ArrayList();
+ }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/StringMap.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/StringMap.java
new file mode 100644
index 0000000..5800a02
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/StringMap.java
@@ -0,0 +1,131 @@
+/*
+ * 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.composite;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Simple utility class that creates a map for string-based keys by
+ * extending <tt>TreeMap</tt>. This map can be set to use case-sensitive
+ * or case-insensitive comparison when searching for the key.
+ * Any keys put into this map will be converted to
+ * a <tt>String</tt> using the <tt>toString()</tt> method,
+ * since it is only intended to compare strings.
+**/
+public class StringMap extends TreeMap {
+
+ /**
+ * serialVersionUID.
+ */
+ private static final long serialVersionUID = 6948801857034259744L;
+
+ /**
+ * Constructor.
+ */
+ public StringMap() {
+ this(true);
+ }
+
+ /**
+ * Constructor.
+ * @param caseSensitive : fix if the map if case sensitive or not.
+ */
+ public StringMap(boolean caseSensitive) {
+ super(new StringComparator(caseSensitive));
+ }
+
+ /**
+ * Constructor.
+ * @param map : initial properties.
+ * @param caseSensitive : fix if the map if case sensitive or not.
+ */
+ public StringMap(Map map, boolean caseSensitive) {
+ this(caseSensitive);
+ putAll(map);
+ }
+
+ /**
+ * @see java.util.TreeMap#put(K, V)
+ */
+ public Object put(Object key, Object value) {
+ return super.put(key.toString(), value);
+ }
+
+ /**
+ * @return true if the map is case sensitive.
+ */
+ public boolean isCaseSensitive() {
+ return ((StringComparator) comparator()).isCaseSensitive();
+ }
+
+ /**
+ * Set the case sensitivity.
+ * @param b : the new case sensitivity.
+ */
+ public void setCaseSensitive(boolean b) {
+ ((StringComparator) comparator()).setCaseSensitive(b);
+ }
+
+ private static class StringComparator implements Comparator {
+ private boolean m_isCaseSensitive = true;
+
+ /**
+ * Constructor.
+ * @param b : true to enable the case sensitivity.
+ */
+ public StringComparator(boolean b) {
+ m_isCaseSensitive = b;
+ }
+
+ /**
+ * @see java.util.Comparator#compare(T, T)
+ */
+ public int compare(Object o1, Object o2) {
+ if (m_isCaseSensitive) {
+ return o1.toString().compareTo(o2.toString());
+ } else {
+ return o1.toString().compareToIgnoreCase(o2.toString());
+ }
+ }
+
+ /**
+ * @return true if the map is case sensitive.
+ */
+ public boolean isCaseSensitive() {
+ return m_isCaseSensitive;
+ }
+
+ /**
+ * Set the case sensitivity.
+ * @param b : true to enable the case sensitivity
+ */
+ public void setCaseSensitive(boolean b) {
+ m_isCaseSensitive = b;
+ }
+
+ /**
+ * @see java.lang.Object#clone()
+ */
+ public Object clone() {
+ return this;
+ }
+ }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/architecture/ArchitectureHandler.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/architecture/ArchitectureHandler.java
new file mode 100644
index 0000000..697decb
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/architecture/ArchitectureHandler.java
@@ -0,0 +1,100 @@
+/*
+ * 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.composite.architecture;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.CompositeHandler;
+import org.apache.felix.ipojo.CompositeManager;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.InstanceDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Composite Architecture Handler.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ArchitectureHandler extends CompositeHandler implements Architecture {
+
+ /**
+ * Composite Manager.
+ */
+ private CompositeManager m_manager;
+
+ /**
+ * Service Registration of the Architecture service provided by this handler.
+ */
+ private ServiceRegistration m_sr;
+
+ /**
+ * Name of the component.
+ */
+ private String m_name;
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#configure(org.apache.felix.ipojo.CompositeManager, org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(CompositeManager im, Element metadata, Dictionary configuration) {
+ if (metadata.containsAttribute("architecture")) {
+ String isArchitectureEnabled = (metadata.getAttribute("architecture")).toLowerCase();
+ if (isArchitectureEnabled.equalsIgnoreCase("true")) { im.register(this); }
+ }
+
+ m_name = (String) configuration.get("name");
+
+ m_manager = im;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ try {
+ if (m_sr != null) { m_sr.unregister(); m_sr = null; }
+ } catch (Exception e) { return; }
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ // Unregister the service if already registred
+ if (m_sr != null) { m_sr.unregister(); }
+
+ // Register the ManagedService
+ BundleContext bc = m_manager.getContext();
+ Dictionary properties = new Properties();
+ properties.put("Component.Type", m_manager.getComponentDescription().getName());
+ properties.put(Constants.SERVICE_PID, m_name);
+
+ m_sr = bc.registerService(Architecture.class.getName(), this, properties);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.architecture.Architecture#getComponentDescription()
+ */
+ public InstanceDescription getInstanceDescription() {
+ return m_manager.getInstanceDescription();
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ImportExportDescription.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ImportExportDescription.java
new file mode 100644
index 0000000..df213dc
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ImportExportDescription.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.composite.service.importer;
+
+import java.util.List;
+
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+
+/**
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ImportExportDescription extends HandlerDescription {
+
+ private List m_imports;
+ private List m_exports;
+
+ /**
+ * Constructor.
+ * @param name
+ * @param isValid
+ * @param importers
+ * @param exporters
+ */
+ public ImportExportDescription(String name, boolean isValid, List importers, List exporters) {
+ super(name, isValid);
+ m_imports = importers;
+ m_exports = exporters;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public String getHandlerInfo() {
+ String s = "";
+ for (int i = 0; i < m_imports.size(); i++) {
+ ServiceImporter imp = (ServiceImporter) m_imports.get(i);
+ if (imp.isSatisfied()) {
+ s += "\t Specification " + imp.getSpecification() + " provided by \n \t";
+ for (int j = 0; j < imp.getProviders().size(); j++) {
+ String prov = (String) imp.getProviders().get(j);
+ s += prov + " ";
+ }
+ } else {
+ s += "\t Specification " + imp.getSpecification() + " is not statisfied \n";
+ }
+ }
+ for (int i = 0; i < m_exports.size(); i++) {
+ ServiceExporter exp = (ServiceExporter) m_exports.get(i);
+ if (exp.isSatisfied()) {
+ s += "\t Specification " + exp.getSpecification() + " is exported or optional";
+ } else {
+ s += "\t Specification " + exp.getSpecification() + " is not exported";
+ }
+ }
+ return s;
+
+ }
+
+
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ImportExportHandler.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ImportExportHandler.java
new file mode 100644
index 0000000..cf55240
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ImportExportHandler.java
@@ -0,0 +1,241 @@
+/*
+ * 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.composite.service.importer;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.CompositeHandler;
+import org.apache.felix.ipojo.CompositeManager;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This handler manages the importation and the exportation of services from / to the parent context.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ImportExportHandler extends CompositeHandler {
+
+ /**
+ * Composite Manager.
+ */
+ private CompositeManager m_manager;
+
+ /**
+ * Service Scope.
+ */
+ private ServiceContext m_scope;
+
+ /**
+ * Parent context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * List of importers.
+ */
+ private List m_importers = new ArrayList();
+
+ /**
+ * List of exporters.
+ */
+ private List m_exporters = new ArrayList();
+
+ /**
+ * Is the handler valid ?
+ */
+ private boolean m_valid;
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#configure(org.apache.felix.ipojo.CompositeManager, org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(CompositeManager im, Element metadata, Dictionary conf) {
+ m_manager = im;
+ m_context = im.getContext();
+ m_scope = m_manager.getServiceContext();
+
+ Element[] imp = metadata.getElements("import");
+ Element[] exp = metadata.getElements("export");
+
+ for (int i = 0; i < imp.length; i++) {
+ boolean optional = false;
+ boolean aggregate = false;
+ String specification = null;
+
+ if (!imp[i].containsAttribute("specification")) { // Malformed import
+ im.getFactory().getLogger().log(Logger.ERROR, "Malformed import : the specification attribute is mandatory");
+ } else {
+ specification = imp[i].getAttribute("specification");
+ String filter = "(&(objectClass=" + specification + ")(!(service.pid=" + m_manager.getInstanceName() + ")))"; // Cannot import yourself
+ if (imp[i].containsAttribute("optional") && imp[i].getAttribute("optional").equalsIgnoreCase("true")) { optional = true; }
+ if (imp[i].containsAttribute("aggregate") && imp[i].getAttribute("aggregate").equalsIgnoreCase("true")) { aggregate = true; }
+ if (imp[i].containsAttribute("filter")) {
+ String classnamefilter = "(objectClass=" + specification + ")";
+ filter = "";
+ if (!imp[i].getAttribute("filter").equals("")) {
+ filter = "(&" + classnamefilter + imp[i].getAttribute("filter") + ")";
+ } else {
+ filter = classnamefilter;
+ }
+ }
+ ServiceImporter si = new ServiceImporter(specification, filter, aggregate, optional, this);
+ m_importers.add(si);
+ }
+ }
+
+ for (int i = 0; i < exp.length; i++) {
+ boolean optional = false;
+ boolean aggregate = false;
+ String specification = null;
+
+ if (!exp[i].containsAttribute("specification")) { // Malformed exports
+ im.getFactory().getLogger().log(Logger.ERROR, "Malformed exports : the specification attribute is mandatory");
+ } else {
+ specification = exp[i].getAttribute("specification");
+ String filter = "(objectClass=" + specification + ")";
+ if (exp[i].containsAttribute("optional") && exp[i].getAttribute("optional").equalsIgnoreCase("true")) { optional = true; }
+ if (exp[i].containsAttribute("aggregate") && exp[i].getAttribute("aggregate").equalsIgnoreCase("true")) { aggregate = true; }
+ if (exp[i].containsAttribute("filter")) {
+ String classnamefilter = "(objectClass=" + specification + ")";
+ filter = "";
+ if (!imp[i].getAttribute("filter").equals("")) {
+ filter = "(&" + classnamefilter + exp[i].getAttribute("filter") + ")";
+ } else {
+ filter = classnamefilter;
+ }
+ }
+ ServiceExporter si = new ServiceExporter(specification, filter, aggregate, optional, this);
+ // Update the componenet type description
+
+ m_manager.getComponentDescription().addProvidedServiceSpecification(specification);
+ m_exporters.add(si);
+ }
+ }
+
+ if (m_importers.size() > 0 || m_exporters.size() > 0) {
+ im.register(this);
+ }
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#start()
+ */
+ public void start() {
+ for (int i = 0; i < m_importers.size(); i++) {
+ ServiceImporter si = (ServiceImporter) m_importers.get(i);
+ si.configure(m_context, m_scope);
+ si.start();
+ }
+
+ for (int i = 0; i < m_exporters.size(); i++) {
+ ServiceExporter se = (ServiceExporter) m_exporters.get(i);
+ se.configure(m_scope, m_context);
+ se.start();
+ }
+
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_importers.size(); i++) {
+ ServiceImporter si = (ServiceImporter) m_importers.get(i);
+ si.stop();
+ }
+
+ for (int i = 0; i < m_exporters.size(); i++) {
+ ServiceExporter se = (ServiceExporter) m_exporters.get(i);
+ se.stop();
+ }
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#isValid()
+ */
+ public boolean isValid() {
+ for (int i = 0; i < m_importers.size(); i++) {
+ ServiceImporter si = (ServiceImporter) m_importers.get(i);
+ if (!si.isSatisfied()) { m_valid = false; return false; }
+ }
+
+ for (int i = 0; i < m_exporters.size(); i++) {
+ ServiceExporter se = (ServiceExporter) m_exporters.get(i);
+ if (!se.isSatisfied()) { m_valid = false; return false; }
+ }
+
+ m_valid = true;
+ return true;
+ }
+
+ /**
+ * Notify the handler that an importer is no more valid.
+ * @param importer : the implicated importer.
+ */
+ protected void invalidating(ServiceImporter importer) {
+ // An import is no more valid
+ if (m_valid) { m_manager.checkInstanceState(); }
+
+ }
+
+ /**
+ * Notify the handler that an importer becomes valid.
+ * @param importer : the implicated importer.
+ */
+ protected void validating(ServiceImporter importer) {
+ // An import becomes valid
+ if (!m_valid && isValid()) { m_manager.checkInstanceState(); }
+
+ }
+
+ /**
+ * Notify the handler that an exporter becomes invalid.
+ * @param exporter : the impcated exporter.
+ */
+ protected void invalidating(ServiceExporter exporter) {
+ // An import is no more valid
+ if (m_valid) { m_manager.checkInstanceState(); }
+
+ }
+
+ /**
+ * Notify the handler that an exporter becomes valid.
+ * @param exporter : the impcated exporter.
+ */
+ protected void validating(ServiceExporter exporter) {
+ // An import becomes valid
+ if (!m_valid && isValid()) { m_manager.checkInstanceState(); }
+
+ }
+
+ /**
+ * @return the attached composite manager.
+ */
+ protected CompositeManager getManager() { return m_manager; }
+
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#getDescription()
+ */
+ public HandlerDescription getDescription() { return new ImportExportDescription(this.getClass().getName(), isValid(), m_importers, m_exporters); }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ServiceExporter.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ServiceExporter.java
new file mode 100644
index 0000000..0b8b570
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ServiceExporter.java
@@ -0,0 +1,301 @@
+/*
+ * 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.composite.service.importer;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ServiceContext;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Export an service from the scope to the parent context.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ServiceExporter implements ServiceListener {
+
+ private BundleContext m_destination;
+ private ServiceContext m_origin;
+
+ private String m_specification;
+ private Filter m_filter;
+ private String m_filterStr;
+
+ private boolean m_aggregate = false;
+ private boolean m_optional = false;
+
+ private ImportExportHandler m_handler;
+
+ private boolean m_isValid;
+
+ private class Record {
+ private ServiceReference m_ref;
+ private ServiceRegistration m_reg;
+ private Object m_svcObject;
+ }
+
+ private List/*<Record>*/ m_records = new ArrayList()/*<Record>*/;
+
+ /**
+ * Constructor.
+ * @param specification
+ * @param filter
+ * @param multiple
+ * @param optional
+ * @param from
+ * @param to
+ * @param exp
+ */
+ public ServiceExporter(String specification, String filter, boolean multiple, boolean optional, ServiceContext from, BundleContext to, ImportExportHandler exp) {
+ this.m_destination = to;
+ this.m_origin = from;
+ this.m_handler = exp;
+ try {
+ this.m_filter = to.createFilter(filter);
+ } catch (InvalidSyntaxException e) { e.printStackTrace(); return; }
+ this.m_aggregate = multiple;
+ this.m_specification = specification;
+ this.m_optional = optional;
+ }
+
+ /**
+ * @param specification
+ * @param filter
+ * @param multiple
+ * @param optional
+ * @param exp
+ */
+ public ServiceExporter(String specification, String filter, boolean multiple, boolean optional, ImportExportHandler exp) {
+ this.m_handler = exp;
+ this.m_filterStr = filter;
+ this.m_aggregate = multiple;
+ this.m_specification = specification;
+ this.m_optional = optional;
+ }
+
+ /**
+ * @param from
+ * @param to
+ */
+ public void configure(ServiceContext from, BundleContext to) {
+ this.m_destination = to;
+ this.m_origin = from;
+ try {
+ this.m_filter = to.createFilter(m_filterStr);
+ } catch (InvalidSyntaxException e) { e.printStackTrace(); return; }
+ }
+
+ /**
+ *
+ */
+ public void start() {
+ try {
+ ServiceReference[] refs = m_origin.getServiceReferences(m_specification, null);
+ if (refs != null) {
+ for (int i = 0; i < refs.length; i++) {
+ if (m_filter.match(refs[i])) {
+ Record rec = new Record();
+ rec.m_ref = refs[i];
+ m_records.add(rec);
+ }
+ }
+ }
+ } catch (InvalidSyntaxException e) { e.printStackTrace(); }
+
+ // Publish available services
+ if (m_records.size() > 0) {
+ if (m_aggregate) {
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ rec.m_svcObject = m_origin.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ } else {
+ Record rec = (Record) m_records.get(0);
+ rec.m_svcObject = m_origin.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ }
+
+ // Register service listener
+ try {
+ m_origin.addServiceListener(this, "(" + Constants.OBJECTCLASS + "=" + m_specification + ")");
+ } catch (InvalidSyntaxException e) { e.printStackTrace(); }
+
+ m_isValid = isSatisfied();
+ }
+
+ /**
+ * @param ref
+ * @return
+ */
+ private Dictionary getProps(ServiceReference ref) {
+ Properties prop = new Properties();
+ String[] keys = ref.getPropertyKeys();
+ for (int i = 0; i < keys.length; i++) {
+ prop.put(keys[i], ref.getProperty(keys[i]));
+ }
+
+ prop.put(Constants.SERVICE_PID, m_handler.getManager().getInstanceName());
+ prop.put("factory.pid", m_handler.getManager().getFactory().getFactoryName());
+
+ return prop;
+ }
+
+ /**
+ *
+ */
+ public void stop() {
+ m_origin.removeServiceListener(this);
+
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ rec.m_svcObject = null;
+ if (rec.m_reg != null) {
+ rec.m_reg.unregister();
+ m_origin.ungetService(rec.m_ref);
+ rec.m_ref = null;
+ }
+ }
+
+ m_records.clear();
+
+ }
+
+ /**
+ * @return
+ */
+ public boolean isSatisfied() {
+ return m_optional || m_records.size() > 0;
+ }
+
+ /**
+ * @param ref
+ * @return
+ */
+ private List/*<Record>*/ getRecordsByRef(ServiceReference ref) {
+ List l = new ArrayList();
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ if (rec.m_ref == ref) { l.add(rec); }
+ }
+ return l;
+ }
+
+ /**
+ * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+ */
+ public void serviceChanged(ServiceEvent ev) {
+ if (ev.getType() == ServiceEvent.REGISTERED) { arrivalManagement(ev.getServiceReference()); }
+ if (ev.getType() == ServiceEvent.UNREGISTERING) { departureManagement(ev.getServiceReference()); }
+
+ if (ev.getType() == ServiceEvent.MODIFIED) {
+ if (m_filter.match(ev.getServiceReference())) {
+ // Test if the ref is always matching with the filter
+ List l = getRecordsByRef(ev.getServiceReference());
+ if (l.size() > 0) { // The ref is already contained => update the properties
+ for (int i = 0; i < l.size(); i++) { // Stop the implied record
+ Record rec = (Record) l.get(i);
+ if (rec.m_reg != null) { rec.m_reg.setProperties(getProps(rec.m_ref)); }
+ }
+ } else { // it is a new mathcing service => add it
+ arrivalManagement(ev.getServiceReference());
+ }
+ } else {
+ List l = getRecordsByRef(ev.getServiceReference());
+ if (l.size() > 0) { // The ref is already contained => the service does no more match
+ departureManagement(ev.getServiceReference());
+ }
+ }
+ }
+ }
+
+ /**
+ * @param ref
+ */
+ private void arrivalManagement(ServiceReference ref) {
+ // Check if the new service match
+ if (m_filter.match(ref)) {
+ // Add it to the record list
+ Record rec = new Record();
+ rec.m_ref = ref;
+ m_records.add(rec);
+ // Publishing ?
+ if (m_records.size() == 1 || m_aggregate) { // If the service is the first one, or if it is a multiple imports
+ rec.m_svcObject = m_origin.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ // Compute the new state
+ if (!m_isValid && isSatisfied()) {
+ m_isValid = true;
+ m_handler.validating(this);
+ }
+ }
+ }
+
+ /**
+ * @param ref
+ */
+ private void departureManagement(ServiceReference ref) {
+ List l = getRecordsByRef(ref);
+ for (int i = 0; i < l.size(); i++) { // Stop the implied record
+ Record rec = (Record) l.get(i);
+ if (rec.m_reg != null) {
+ rec.m_svcObject = null;
+ rec.m_reg.unregister();
+ rec.m_reg = null;
+ m_origin.ungetService(rec.m_ref);
+ }
+ }
+ m_records.removeAll(l);
+
+ // Check the validity & if we need to reimport the service
+ if (m_records.size() > 0) {
+ // There is other available services
+ if (!m_aggregate) { // Import the next one
+ Record rec = (Record) m_records.get(0);
+ if (rec.m_svcObject == null) { // It is the first service who disappears - create the next one
+ rec.m_svcObject = m_origin.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ }
+ } else {
+ if (!m_optional) {
+ m_isValid = false;
+ m_handler.invalidating(this);
+ }
+ }
+ }
+
+ /**
+ * @return the exported specification.
+ */
+ protected String getSpecification() {
+ return m_specification;
+ }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ServiceImporter.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ServiceImporter.java
new file mode 100644
index 0000000..79ef6f7
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/importer/ServiceImporter.java
@@ -0,0 +1,316 @@
+/*
+ * 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.composite.service.importer;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ServiceContext;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Import a service form the parent to the internal service registry.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ServiceImporter implements ServiceListener {
+
+ private ServiceContext m_destination;
+ private BundleContext m_origine;
+
+ private String m_specification;
+ private Filter m_filter;
+ private String m_filterStr;
+
+ private boolean m_aggregate = false;
+ private boolean m_optional = false;
+
+ private boolean m_isValid;
+
+ private ImportExportHandler m_handler;
+
+ private class Record {
+ private ServiceReference m_ref;
+ private ServiceRegistration m_reg;
+ private Object m_svcObject;
+ }
+
+ private List/*<Record>*/ m_records = new ArrayList()/*<Record>*/;
+
+ /**
+ * Constructor.
+ * @param specification : targetted specification
+ * @param filter : LDAP filter
+ * @param multiple : should the importer imports several services ?
+ * @param optional : is the import optional ?
+ * @param from : parent context
+ * @param to : internal context
+ * @param in : handler
+ */
+ public ServiceImporter(String specification, String filter, boolean multiple, boolean optional, BundleContext from, ServiceContext to, ImportExportHandler in) {
+ this.m_destination = to;
+ this.m_origine = from;
+ try {
+ this.m_filter = from.createFilter(filter);
+ } catch (InvalidSyntaxException e) { e.printStackTrace(); return; }
+ this.m_aggregate = multiple;
+ this.m_specification = specification;
+ this.m_optional = optional;
+ this.m_handler = in;
+ }
+
+ /**
+ * Constructor.
+ * @param specification : targetted specification
+ * @param filter : LDAP filter
+ * @param multiple : should the importer imports several services ?
+ * @param optional : is the import optional ?
+ * @param in : handler
+ */
+ public ServiceImporter(String specification, String filter, boolean multiple, boolean optional, ImportExportHandler in) {
+ this.m_filterStr = filter;
+ this.m_aggregate = multiple;
+ this.m_filterStr = filter;
+ this.m_specification = specification;
+ this.m_optional = optional;
+ this.m_handler = in;
+ }
+
+ /**
+ * Configure the origin and the destination of the import.
+ * @param from : origine (parent)
+ * @param to : destination (internal scope)
+ */
+ public void configure(BundleContext from, ServiceContext to) {
+ this.m_destination = to;
+ this.m_origine = from;
+ try {
+ this.m_filter = from.createFilter(m_filterStr);
+ } catch (InvalidSyntaxException e) { e.printStackTrace(); return; }
+ }
+
+ /**
+ * Start method to begin the import.
+ */
+ public void start() {
+ try {
+ ServiceReference[] refs = m_origine.getServiceReferences(m_specification, null);
+ if (refs != null) {
+ for (int i = 0; i < refs.length; i++) {
+ if (m_filter.match(refs[i])) {
+ Record rec = new Record();
+ rec.m_ref = refs[i];
+ m_records.add(rec);
+ }
+ }
+ }
+ } catch (InvalidSyntaxException e) { e.printStackTrace(); }
+
+ // Publish available services
+ if (m_records.size() > 0) {
+ if (m_aggregate) {
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ rec.m_svcObject = m_origine.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ } else {
+ Record rec = (Record) m_records.get(0);
+ rec.m_svcObject = m_origine.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ }
+
+ // Register service listener
+ try {
+ m_origine.addServiceListener(this, "(" + Constants.OBJECTCLASS + "=" + m_specification + ")");
+ } catch (InvalidSyntaxException e) { e.printStackTrace(); }
+
+ m_isValid = isSatisfied();
+ }
+
+ /**
+ * Get the properties for the exposed service from the given reference.
+ * @param ref : the reference.
+ * @return the property dictionary
+ */
+ private Dictionary getProps(ServiceReference ref) {
+ Properties prop = new Properties();
+ String[] keys = ref.getPropertyKeys();
+ for (int i = 0; i < keys.length; i++) {
+ prop.put(keys[i], ref.getProperty(keys[i]));
+ }
+ return prop;
+ }
+
+ /**
+ * Stop the management of the import.
+ */
+ public void stop() {
+
+ m_origine.removeServiceListener(this);
+
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ rec.m_svcObject = null;
+ if (rec.m_reg != null) {
+ rec.m_reg.unregister();
+ m_origine.ungetService(rec.m_ref);
+ rec.m_ref = null;
+ }
+ }
+
+ m_records.clear();
+
+ }
+
+ /**
+ * @return true if the import is satisfied.
+ */
+ public boolean isSatisfied() {
+ return m_optional || m_records.size() > 0;
+ }
+
+ /**
+ * Get the record list using the given reference.
+ * @param ref : the reference
+ * @return the list containing all record using the given reference
+ */
+ private List/*<Record>*/ getRecordsByRef(ServiceReference ref) {
+ List l = new ArrayList();
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ if (rec.m_ref == ref) { l.add(rec); }
+ }
+ return l;
+ }
+
+ /**
+ * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+ */
+ public void serviceChanged(ServiceEvent ev) {
+ if (ev.getType() == ServiceEvent.REGISTERED) { arrivalManagement(ev.getServiceReference()); }
+ if (ev.getType() == ServiceEvent.UNREGISTERING) { departureManagement(ev.getServiceReference()); }
+
+ if (ev.getType() == ServiceEvent.MODIFIED) {
+ if (m_filter.match(ev.getServiceReference())) {
+ // Test if the ref is always matching with the filter
+ List l = getRecordsByRef(ev.getServiceReference());
+ if (l.size() > 0) { // The ref is already contained => update the properties
+ for (int i = 0; i < l.size(); i++) { // Stop the implied record
+ Record rec = (Record) l.get(i);
+ if (rec.m_reg != null) { rec.m_reg.setProperties(getProps(rec.m_ref)); }
+ }
+ } else { // it is a new mathcing service => add it
+ arrivalManagement(ev.getServiceReference());
+ }
+ } else {
+ List l = getRecordsByRef(ev.getServiceReference());
+ if (l.size() > 0) { // The ref is already contained => the service does no more match
+ departureManagement(ev.getServiceReference());
+ }
+ }
+ }
+ }
+
+ /**
+ * Manage the arrival of a consitent service.
+ * @param ref : the arrival service reference
+ */
+ private void arrivalManagement(ServiceReference ref) {
+ // Check if the new service match
+ if (m_filter.match(ref)) {
+ // Add it to the record list
+ Record rec = new Record();
+ rec.m_ref = ref;
+ m_records.add(rec);
+ // Publishing ?
+ if (m_records.size() == 1 || m_aggregate) { // If the service is the first one, or if it is a multiple imports
+ rec.m_svcObject = m_origine.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ // Compute the new state
+ if (!m_isValid && isSatisfied()) {
+ m_isValid = true;
+ m_handler.validating(this);
+ }
+ }
+ }
+
+ /**
+ * Manage the departure of a used reference.
+ * @param ref : the leaving reference
+ */
+ private void departureManagement(ServiceReference ref) {
+ List l = getRecordsByRef(ref);
+ for (int i = 0; i < l.size(); i++) { // Stop the implied record
+ Record rec = (Record) l.get(i);
+ if (rec.m_reg != null) {
+ rec.m_svcObject = null;
+ rec.m_reg.unregister();
+ rec.m_reg = null;
+ m_origine.ungetService(rec.m_ref);
+ }
+ }
+ m_records.removeAll(l);
+
+ // Check the validity & if we need to reimport the service
+ if (m_records.size() > 0) {
+ // There is other available services
+ if (!m_aggregate) { // Import the next one
+ Record rec = (Record) m_records.get(0);
+ if (rec.m_svcObject == null) { // It is the first service who disappears - create the next one
+ rec.m_svcObject = m_origine.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ }
+ } else {
+ if (!m_optional) {
+ m_isValid = false;
+ m_handler.invalidating(this);
+ }
+ }
+ }
+
+ /**
+ * @return the targetted specification.
+ */
+ public String getSpecification() { return m_specification; }
+
+ /**
+ * @return the list of all imported services.
+ */
+ protected List getProviders() {
+ List l = new ArrayList();
+ for (int i = 0; i < m_records.size(); i++) {
+ l.add((((Record) m_records.get(i)).m_ref).getProperty(Constants.SERVICE_PID));
+ }
+ return l;
+
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceInstantiatorDescription.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceInstantiatorDescription.java
new file mode 100644
index 0000000..598faa3
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceInstantiatorDescription.java
@@ -0,0 +1,73 @@
+/*
+ * 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.composite.service.instantiator;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Description of the Service Instantiator Handler.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ServiceInstantiatorDescription extends HandlerDescription {
+
+ /**
+ * List of managed service instances.
+ */
+ private List m_instances;
+
+ /**
+ * Constructor.
+ * @param arg0 : name of the handler
+ * @param arg1 : validity of the handler
+ * @param insts : list of service instance
+ */
+ public ServiceInstantiatorDescription(String arg0, boolean arg1, List insts) {
+ super(arg0, arg1);
+ m_instances = insts;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public String getHandlerInfo() {
+ String r = "";
+ for (int i = 0; i < m_instances.size(); i++) {
+ SvcInstance inst = (SvcInstance) m_instances.get(i);
+ HashMap map = inst.getUsedReferences();
+ Set keys = map.keySet();
+ Iterator it = keys.iterator();
+ while (it.hasNext()) {
+ ServiceReference ref = (ServiceReference) it.next();
+ Object o = map.get(ref);
+ if (o != null && o instanceof ComponentInstance) {
+ r += "\t Specification " + inst.getSpecification() + " instantiated from " + ((ComponentInstance) o).getComponentDescription().getName() + " \n";
+ }
+ }
+ }
+ return r;
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceInstantiatorHandler.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceInstantiatorHandler.java
new file mode 100644
index 0000000..1810c5f
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ServiceInstantiatorHandler.java
@@ -0,0 +1,158 @@
+/*
+ * 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.composite.service.instantiator;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.CompositeHandler;
+import org.apache.felix.ipojo.CompositeManager;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Service Instantiator Class.
+ * This handler allows to instantiate service instance inside the composition.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ServiceInstantiatorHandler extends CompositeHandler {
+
+ /**
+ * Composite Manager.
+ */
+ private CompositeManager m_manager;
+
+ /**
+ * Is the handler valid ?
+ */
+ private boolean m_isValid = false;
+
+ /**
+ * List of instances to manage.
+ */
+ private List/*<SvcInstance>*/ m_instances = new ArrayList();
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#configure(org.apache.felix.ipojo.CompositeManager, org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(CompositeManager im, Element metadata, Dictionary conf) {
+ m_manager = im;
+ Element[] services = metadata.getElements("service");
+ for (int i = 0; i < services.length; i++) {
+ String spec = services[i].getAttribute("specification");
+ String filter = "(objectClass=" + Factory.class.getName() + ")";
+ if (services[i].containsAttribute("filter")) {
+ String classnamefilter = "(&(objectClass=" + Factory.class.getName() + ")(!(service.pid=" + m_manager.getInstanceName() + ")))"; // Cannot instantaite yourself
+ filter = "";
+ if (!services[i].getAttribute("filter").equals("")) {
+ filter = "(&" + classnamefilter + services[i].getAttribute("filter") + ")";
+ } else {
+ filter = classnamefilter;
+ }
+ }
+ Properties prop = new Properties();
+ for (int k = 0; k < services[i].getElements("property").length; k++) {
+ String key = services[i].getElements("property")[k].getAttribute("name");
+ String value = services[i].getElements("property")[k].getAttribute("value");
+ prop.put(key, value);
+ }
+ boolean agg = false;
+ if (services[i].containsAttribute("aggregate") && services[i].getAttribute("aggregate").equalsIgnoreCase("true")) { agg = true; }
+ boolean opt = false;
+ if (services[i].containsAttribute("optional") && services[i].getAttribute("optional").equalsIgnoreCase("true")) { opt = true; }
+ SvcInstance inst = new SvcInstance(this, spec, prop, agg, opt, filter);
+ m_instances.add(inst);
+ }
+ if (m_instances.size() > 0) {
+ m_manager.register(this);
+ }
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#start()
+ */
+ public void start() {
+ // Init
+ for (int i = 0; i < m_instances.size(); i++) {
+ SvcInstance inst = (SvcInstance) m_instances.get(i);
+ inst.start();
+ }
+
+ m_isValid = isValid();
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#isValid()
+ */
+ public boolean isValid() {
+ for (int i = 0; i < m_instances.size(); i++) {
+ SvcInstance inst = (SvcInstance) m_instances.get(i);
+ if (!inst.isSatisfied()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_instances.size(); i++) {
+ SvcInstance inst = (SvcInstance) m_instances.get(i);
+ inst.stop();
+ }
+ m_instances.clear();
+ }
+
+ /**
+ * An service instance becomes valid.
+ */
+ public void validate() {
+ if (!m_isValid) {
+ if (isValid()) { m_manager.checkInstanceState(); }
+ m_isValid = true;
+ }
+ }
+
+ /**
+ * A service instance becomes invalid.
+ */
+ public void invalidate() {
+ if (m_isValid) {
+ if (!isValid()) { m_manager.checkInstanceState(); }
+ m_isValid = false;
+ }
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.CompositeHandler#getDescription()
+ */
+ public HandlerDescription getDescription() {
+ return new ServiceInstantiatorDescription(this.getClass().getName(), isValid(), m_instances);
+ }
+
+ /**
+ * @return the composite manager.
+ */
+ protected CompositeManager getManager() { return m_manager; }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java
new file mode 100644
index 0000000..848d73f
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/SvcInstance.java
@@ -0,0 +1,347 @@
+/*
+ * 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.composite.service.instantiator;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Manage a service instantiation.
+ * This service create componenet instance providing the required service specification.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class SvcInstance implements ServiceListener {
+
+ /**
+ * Required specification.
+ */
+ private String m_specification;
+
+ /**
+ * Configuration to push to the instance.
+ */
+ private Dictionary m_configuration;
+
+ /**
+ * Map of factory references => instance or NO_INSTANCE.
+ */
+ private HashMap /*ServiceReference*/ m_usedRef = new HashMap();
+
+ /**
+ * Does we instantiate several provider ?
+ */
+ private boolean m_isAggregate = false;
+
+ /**
+ * Is the service optional ?
+ */
+ private boolean m_isOptional = false;
+
+ /**
+ * Handler creating the service instance.
+ */
+ private ServiceInstantiatorHandler m_handler;
+
+ /**
+ * Service Context (internal scope).
+ */
+ private ServiceContext m_context;
+
+ /**
+ * Parent context.
+ */
+ //private BundleContext m_parent;
+
+ /**
+ * True if the service instantiation is valid.
+ */
+ private boolean m_isValid = false;
+
+ /**
+ * String form of the factory filter.
+ */
+ private String m_filterStr;
+
+ /**
+ * Name of the last create instance.
+ */
+ private long m_index = 0;
+
+ /**
+ * Constructor.
+ * @param h : the handler.
+ * @param spec : required specification.
+ * @param conf : instance configuration.
+ * @param isAgg : is the svc instance an aggregate service ?
+ * @param isOpt : is the svc instance optional ?
+ */
+ public SvcInstance(ServiceInstantiatorHandler h, String spec, Dictionary conf, boolean isAgg, boolean isOpt, String filt) {
+ m_handler = h;
+ m_context = h.getManager().getServiceContext();
+ //m_parent = h.getManager().getContext();
+ m_specification = spec;
+ m_configuration = conf;
+ m_isAggregate = isAgg;
+ m_isOptional = isOpt;
+ m_filterStr = filt;
+ }
+
+ /**
+ * Start the service instance.
+ * @param sc
+ */
+ public void start() {
+ initFactoryList();
+ // Register factory listener
+ try {
+ m_context.addServiceListener(this, m_filterStr);
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace(); // Should not happens
+ }
+
+ // Init the instances
+ if (m_usedRef.size() > 0) {
+ Set keys = m_usedRef.keySet();
+ Iterator it = keys.iterator();
+ if (m_isAggregate) {
+ while (it.hasNext()) {
+ ServiceReference ref = (ServiceReference) it.next();
+ createInstance(ref);
+ }
+ } else {
+ ServiceReference ref = (ServiceReference) it.next();
+ createInstance(ref);
+ }
+ }
+ m_isValid = isSatisfied();
+ }
+
+ /**
+ * Stop the service instance.
+ */
+ public void stop() {
+ m_context.removeServiceListener(this);
+ Set keys = m_usedRef.keySet();
+ Iterator it = keys.iterator();
+ while (it.hasNext()) {
+ ServiceReference ref = (ServiceReference) it.next();
+ Object o = m_usedRef.get(ref);
+ if (o != null) {
+ ((ComponentInstance) o).stop();
+ }
+ }
+ m_usedRef.clear();
+ m_isValid = false;
+ }
+
+ /**
+ * @return true if at least one instance is created.
+ */
+ private boolean isAnInstanceCreated() {
+ Set keys = m_usedRef.keySet();
+ Iterator it = keys.iterator();
+ ServiceReference ref = (ServiceReference) it.next();
+ Object o = m_usedRef.get(ref);
+ return o != null;
+ }
+
+ /**
+ * Create an instance for the given reference.
+ */
+ private void createInstance(ServiceReference ref) {
+ try {
+ Factory factory = (Factory) m_context.getService(ref);
+ ComponentInstance instance = factory.createComponentInstance(m_configuration);
+ m_usedRef.put(ref, instance);
+ m_context.ungetService(ref);
+ } catch (UnacceptableConfiguration e) {
+ System.err.println("A matching factory (" + ref.getProperty("service.pid") + ") seems to refuse the given configuration : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Create an instance for the next available factory.
+ */
+ private void createNextInstance() {
+ Set keys = m_usedRef.keySet();
+ Iterator it = keys.iterator();
+ ServiceReference ref = (ServiceReference) it.next();
+ try {
+ Factory factory = (Factory) m_context.getService(ref);
+ ComponentInstance instance = factory.createComponentInstance(m_configuration);
+ m_usedRef.put(ref, instance);
+ m_context.ungetService(ref);
+ } catch (UnacceptableConfiguration e) {
+ System.err.println("A matching factory seems to refuse the given configuration : " + e.getMessage());
+ }
+ }
+
+ /**
+ * Kill an instance (if exist).
+ */
+ private void stopInstance(ServiceReference ref) {
+ Object o = m_usedRef.get(ref);
+ if (o != null) {
+ ((ComponentInstance) o).stop();
+ }
+ }
+
+
+ /**
+ * Init the list of available factory.
+ */
+ public void initFactoryList() {
+ // Init factory list
+ try {
+ ServiceReference[] refs = m_context.getServiceReferences(Factory.class.getName(), m_filterStr);
+ if (refs == null) { return; }
+ for (int i = 0; i < refs.length; i++) {
+ ServiceReference ref = refs[i];
+ Factory fact = (Factory) m_context.getService(ref);
+ // Check provided spec & conf
+ if (match(fact)) {
+ m_usedRef.put(ref, null);
+ }
+ fact = null;
+ m_context.ungetService(ref);
+ }
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace(); // Should not happen
+ }
+ }
+
+ /**
+ * @return true if the service instance if satisfied.
+ */
+ public boolean isSatisfied() {
+ return m_isOptional || m_usedRef.size() > 0;
+ }
+
+ /**
+ * Does the service instance match with the given factory.
+ * @param fact : the factory to test.
+ * @return true if the factory match, false otherwise.
+ */
+ private boolean match(Factory fact) {
+ // Check if the factory can provide the spec
+ for (int i = 0; i < fact.getComponentDescription().getprovidedServiceSpecification().length; i++) {
+ if (fact.getComponentDescription().getprovidedServiceSpecification()[i].equals(m_specification)) {
+
+ // Check that the factory needs every properties contained in the configuration
+ Enumeration e = m_configuration.keys();
+ while (e.hasMoreElements()) {
+ String k = (String) e.nextElement();
+ if (!containsProperty(k, fact)) {
+ return false;
+ }
+ }
+
+ // Add an unique name if not specified.
+ if (m_configuration.get("name") == null) {
+ m_configuration.put("name", this.toString() + "-" + m_index);
+ m_index++;
+ }
+
+ // Check the acceptability.
+ return (fact.isAcceptable(m_configuration));
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Does the factory support the given property ?
+ * @param name : name of the property
+ * @param factory : factory to test
+ * @return true if the factory support this property
+ */
+ private boolean containsProperty(String name, Factory factory) {
+ PropertyDescription[] props = factory.getComponentDescription().getProperties();
+ for (int i = 0; i < props.length; i++) {
+ if (props[i].getName().equalsIgnoreCase(name)) { return true; }
+ }
+ if (name.equalsIgnoreCase("name")) { return true; } // Skip the name property
+ return false;
+ }
+
+ /**
+ * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+ */
+ public void serviceChanged(ServiceEvent ev) {
+ if (ev.getType() == ServiceEvent.REGISTERED) {
+ // Check the matching
+ Factory fact = (Factory) m_context.getService(ev.getServiceReference());
+ if (match(fact)) {
+ m_usedRef.put(ev.getServiceReference(), null);
+ if (m_isAggregate) { // Create an instance for the new factory
+ createInstance(ev.getServiceReference());
+ if (!m_isValid) { m_isValid = true; m_handler.validate(); }
+ } else {
+ if (!isAnInstanceCreated()) { createInstance(ev.getServiceReference()); }
+ if (!m_isValid) { m_isValid = true; m_handler.validate(); }
+ }
+ }
+ fact = null;
+ m_context.ungetService(ev.getServiceReference());
+ return;
+ }
+ if (ev.getType() == ServiceEvent.UNREGISTERING) {
+ // Remove the ref is contained
+ Object o = m_usedRef.remove(ev.getServiceReference());
+ if (o != null) {
+ stopInstance(ev.getServiceReference());
+ if (m_usedRef.size() > 0) {
+ if (!m_isAggregate) {
+ createNextInstance(); // Create an instance with another factory
+ }
+ } else { // No more candidate
+ if (!m_isOptional) { m_isValid = false; m_handler.invalidate(); }
+ }
+ }
+ }
+ }
+
+ /**
+ * @return the required specification.
+ */
+ public String getSpecification() {
+ return m_specification;
+ }
+
+ /**
+ * @return the map of used references.
+ */
+ protected HashMap getUsedReferences() {
+ return m_usedRef;
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java b/ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
index ccd81c7..64bc089 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
@@ -296,7 +296,6 @@
// If a service goes way.
if (event.getType() == ServiceEvent.UNREGISTERING) {
- m_handler.getInstanceManager().getFactory().getLogger().log(Logger.INFO, "[" + m_handler.getInstanceManager().getClassName() + "] A service is gone -> " + event.getServiceReference().getBundle());
if (containsSR(event.getServiceReference())) { departureManagement(event.getServiceReference()); }
return;
}
@@ -311,12 +310,10 @@
// If a service is modified
if (event.getType() == ServiceEvent.MODIFIED) {
if (m_filter.match(event.getServiceReference())) {
- m_handler.getInstanceManager().getFactory().getLogger().log(Logger.INFO, "[" + m_handler.getInstanceManager().getClassName() + "] A service with a filter matching is arrived -> " + event.getServiceReference().getBundle());
if (!containsSR(event.getServiceReference())) {
arrivalManagement(event.getServiceReference());
}
} else {
- m_handler.getInstanceManager().getFactory().getLogger().log(Logger.INFO, "[" + m_handler.getInstanceManager().getClassName() + "] A service with a filter matching has gone -> " + event.getServiceReference().getBundle());
if (containsSR(event.getServiceReference())) {
departureManagement(event.getServiceReference());
}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java b/ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
index 23adeb1..58ff68a 100644
--- a/ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
@@ -42,11 +42,23 @@
private Element[] m_elements = new Element[0];
/**
- * @return the component metadata.
+ * @return the component metadata (composite & component).
* @throws ParseException when a parsing error occurs
*/
public Element[] getComponentsMetadata() throws ParseException {
- return m_elements[0].getElements("Component");
+ Element[] components = m_elements[0].getElements("Component");
+ Element[] composites = m_elements[0].getElements("Composite");
+ Element[] all = new Element[components.length + composites.length];
+ int l = 0;
+ for (int i = 0; i < components.length; i++) {
+ all[l] = components[i];
+ l++;
+ }
+ for (int i = 0; i < composites.length; i++) {
+ all[l] = composites[i];
+ l++;
+ }
+ return all;
}
/**
@@ -152,7 +164,6 @@
//Add the ipojo element inside the element list
addElement(new Element("iPOJO", ""));
parseElements(componentClassesStr.trim());
-
}
/**