Initial commit of iPOJO source, which was accepted as a subproject
contribution by a vote.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@414287 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Activator.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Activator.java
new file mode 100644
index 0000000..827be0d
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Activator.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.io.IOException;
+import java.util.Dictionary;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+
+/**
+ * iPOJO generic activator.
+ * Date : 31 mars 2006
+ * @author clement escoffier
+ */
+public class Activator implements BundleActivator {
+
+
+ // STATIC
+ /**
+ * The iPOJO static logger. This logger is used by each iPOJO instance.
+ */
+ private static Logger m_logger = Logger.getLogger("org.apache.felix.ipojo");
+
+ /**
+ * @return Returns the static ipojo logger : org.apache.felix.ipojo
+ */
+ public static Logger getLogger() {
+ return Activator.m_logger;
+ }
+ // END STATIC
+
+ // NON STATIC PART
+
+ /**
+ * The m_bundle context.
+ * m_bundleContext : BundleContext
+ */
+ private BundleContext m_bundleContext = null;
+
+ /**
+ * The component manager for this activator.
+ * m_handler : ComponentManagerFactory
+ */
+ private ComponentManagerFactory[] m_factories;
+
+ // Field accessors :
+
+ /**
+ * @return the m_bundle context
+ */
+ public BundleContext getBundleContext() {
+ return m_bundleContext;
+ }
+
+ /**
+ * Add a component manager factory to the factory list.
+ * @param cm : the new component metadata.
+ */
+ public void addComponentFactory(Element cm) {
+ // Create the factory :
+ ComponentManagerFactory factory = new ComponentManagerFactory(this, cm);
+
+ // If the factory array is not empty add the new factory at the end
+ if (m_factories.length != 0) {
+ ComponentManagerFactory[] newFactory = new ComponentManagerFactory[m_factories.length + 1];
+ System.arraycopy(m_factories, 0, newFactory, 0, m_factories.length);
+ newFactory[m_factories.length] = factory;
+ m_factories = newFactory;
+ }
+ // Else create an array of size one with the new Factory
+ else { m_factories = new ComponentManagerFactory[] {factory}; }
+ }
+
+ /**
+ * Remove a component manager factory to the factory list.
+ * @param factory : the componet facotry to remove
+ */
+ public void removeComponentFactory(ComponentManagerFactory factory) {
+
+ int idx = -1;
+ for (int i = 0; i < m_factories.length; i++) {
+ if (m_factories[i] == factory) {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx >= 0) {
+ // If this is the factory, then point to empty list.
+ if ((m_factories.length - 1) == 0) {
+ m_factories = new ComponentManagerFactory[0];
+ }
+ // Otherwise, we need to do some array copying.
+ else {
+ ComponentManagerFactory[] newFactories = new ComponentManagerFactory[m_factories.length - 1];
+ System.arraycopy(m_factories, 0, newFactories, 0, idx);
+ if (idx < newFactories.length) {
+ System.arraycopy(m_factories, idx + 1, newFactories, idx, newFactories.length - idx);
+ }
+ m_factories = newFactories;
+ }
+ }
+ }
+
+ // End field accesors
+
+ // Constructors :
+
+ /**
+ * Constructor used by Felix.
+ */
+ public Activator() {
+ super();
+ m_factories = new ComponentManagerFactory[0];
+ }
+
+ // End constuctors
+
+ // Bundle Lifecycle CallBack
+
+ /**
+ * Start method.
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ * @param bc : the m_bundle context to use to manage the component.
+ * @throws Exception : when a problem occurs
+ */
+ public void start(final BundleContext bc) throws Exception {
+ m_bundleContext = bc;
+
+ // Set the trace level
+ String level = System.getProperty("ipojo.loglevel");
+ if (level != null) {
+ if (level.equals("ALL")) {
+ Activator.getLogger().setLevel(Level.ALL);
+ }
+ if (level.equals("FINEST")) {
+ Activator.getLogger().setLevel(Level.FINEST);
+ }
+ if (level.equals("WARNING")) {
+ Activator.getLogger().setLevel(Level.WARNING);
+ }
+ }
+ else { Activator.getLogger().setLevel(IPojoConfiguration.LOG_LEVEL); }
+
+ try {
+ parse();
+ } catch (Exception e) {
+ Activator.getLogger().log(Level.SEVERE, "Parse error for the bundle " + m_bundleContext.getBundle().getBundleId() + " : " + e.getMessage());
+ return;
+ }
+ Activator.getLogger().log(Level.INFO, "[Bundle" + m_bundleContext.getBundle().getBundleId() + "] Called start after the parsing");
+
+ // Call the internal start method
+ start();
+
+ }
+
+ /**
+ * Stop method.
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ * @param arg0 : the m_bundle context
+ * @throws Exception : ???
+ */
+ public void stop(BundleContext arg0) throws Exception {
+ for (int i = 0; i < m_factories.length; i++) {
+ ComponentManagerFactory factory = m_factories[i];
+ factory.stop();
+ }
+ }
+
+ // End Bundle Lifecycle CallBack
+
+ // Parsing methods :
+
+ /**
+ * Parse the file who is at the Metadata-Location place, manipulate the bytecode of the component implementation class
+ * and set the manager.
+ * @throws IOException
+ * @throws ParseException
+ */
+ private void parse() throws IOException, ParseException {
+
+ String componentClasses = (String)m_bundleContext.getBundle().getHeaders().get("iPOJO-Components");
+ if (componentClasses != null) {
+ parseManifest(m_bundleContext.getBundle().getHeaders());
+ } else {
+ Activator.getLogger().log(Level.SEVERE, "[Bundle" + m_bundleContext.getBundle().getBundleId() + "] Components-Metadata are not in the manifest");
+ throw new ParseException("[Bundle" + m_bundleContext.getBundle().getBundleId() + "] Component-Metadata are not in the manifest");
+ }
+ }
+
+ private void parseManifest(Dictionary dict) throws ParseException {
+ ManifestMetadataParser parser = new ManifestMetadataParser();
+ parser.parse(dict);
+ // Create the components Factory according to the declared component
+ Element[] componentsMetadata = parser.getComponentsMetadata();
+ for (int i = 0; i < componentsMetadata.length; i++) {
+ Activator.getLogger().log(Level.INFO, "[Bundle" + m_bundleContext.getBundle().getBundleId() + "] Create a component factory for " + componentsMetadata[i].getAttribute("classname"));
+ addComponentFactory(componentsMetadata[i]);
+ }
+ }
+
+ /**
+ * Start the management : Manipulate the classes and start the component manager.
+ */
+ private void start() {
+ for (int i = 0; i < m_factories.length; i++) {
+ ComponentManagerFactory factory = m_factories[i];
+ factory.start(); // Start the management
+ }
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Callback.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Callback.java
new file mode 100644
index 0000000..5f93351
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Callback.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.logging.Level;
+
+
+
+/**
+ * A callback allows calling a method on the component.
+ * @author Clement Escoffier
+ */
+public class Callback {
+
+ /**
+ * Name of the method to call.
+ */
+ private String m_method;
+
+ /**
+ * Is the method a static method ?
+ */
+ private boolean m_isStatic;
+
+ /**
+ * Reference on the component manager.
+ */
+ private ComponentManager m_manager;
+
+ /**
+ * LifecycleCallback constructor.
+ * @param method : the name of the method to call
+ * @param isStatic : is the method a static method
+ * @param cm : the component manager of the component containing the method
+ */
+ public Callback(String method, boolean isStatic, ComponentManager cm) {
+ m_method = method;
+ m_isStatic = isStatic;
+ m_manager = cm;
+ }
+
+ /**
+ * Call the method.
+ * @throws NoSuchMethodException : Method is not found in the class
+ * @throws InvocationTargetException : The method is not static
+ * @throws IllegalAccessException : The method can not be invoked
+ */
+ public void call() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ Activator.getLogger().log(Level.INFO, "[" + m_manager.getComponentMetatada().getClassName() + "] Call an callback method : " + m_method);
+ Method method = m_manager.getClazz().getMethod(m_method, new Class[] {});
+ method.setAccessible(true);
+
+ if (m_isStatic) { method.invoke(null, new Object[]{}); }
+ else {
+ // Two cases :
+ // - if instances already exists : call on each instances
+ // - if no instance exists : create an instance
+ if (m_manager.getInstances().length == 0) {
+ Activator.getLogger().log(Level.INFO, "[" + m_manager.getComponentMetatada().getClassName() + "] Create the first instance " + m_manager.getInstance());
+ method.invoke(m_manager.getInstance(), new Object[]{});
+ } else {
+ for (int i = 0; i < m_manager.getInstances().length; i++) {
+ Activator.getLogger().log(Level.INFO, "[" + m_manager.getComponentMetatada().getClassName() + "] Call the callback on the instance " + m_manager.getInstances()[i]);
+ method.invoke(m_manager.getInstances()[i], new Object[]{});
+ }
+ }
+ }
+ }
+
+ /**
+ * Call the callback on the method with the argument given in parameter.
+ * @param arg : the parameters
+ * @throws NoSuchMethodException : the callback method is not found
+ * @throws IllegalAccessException : the callbback method cannot be called
+ * @throws InvocationTargetException : an error occurs inside the called method
+ */
+ public void call(Object[] arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ Activator.getLogger().log(Level.INFO, "[" + m_manager.getComponentMetatada().getClassName() + "] Call an callback method : " + m_method);
+
+ // Build an array of call for arg :
+ Class[] classes = new Class[arg.length];
+ for (int i = 0; i < arg.length; i++) {
+ classes[i] = arg[i].getClass();
+ }
+ Method method = m_manager.getClazz().getMethod(m_method, classes);
+ method.setAccessible(true);
+
+ if (m_isStatic) { method.invoke(null, arg); }
+ else {
+ // Two cases :
+ // - if instances already exists : call on each instances
+ // - if no instance exists : create an instance
+ if (m_manager.getInstances().length == 0) {
+ Activator.getLogger().log(Level.INFO, "[" + m_manager.getComponentMetatada().getClassName() + "] Create the first instance " + m_manager.getInstance());
+ method.invoke(m_manager.getInstance(), new Object[]{});
+ } else {
+ for (int i = 0; i < m_manager.getInstances().length; i++) {
+ method.invoke(m_manager.getInstances()[i], arg);
+ }
+ }
+ }
+ }
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/ComponentManager.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/ComponentManager.java
new file mode 100644
index 0000000..6d2eb6f
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/ComponentManager.java
@@ -0,0 +1,502 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.logging.Level;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The component manager class manage one "version" of a component.
+ * It manages component lifecycle, component instance creation and handlers.
+ * @author Clement Escoffier
+ */
+public class ComponentManager {
+
+ // STATIC PART
+
+ /**
+ * Component State : INVALID.
+ * The component is invalid when it start or when a component dependency is unvalid.
+ */
+ public static final int INVALID = 1;
+
+ /**
+ * Component State : VALID.
+ * The component is resolved when it is running and all its component dependencies are valid.
+ */
+ public static final int VALID = 2;
+
+ // END STATIC PART
+
+ /**
+ * Parent factory (ComponentManagerFactory).
+ */
+ private ComponentManagerFactory m_factory;
+
+ /**
+ * Attached metadata of the managed component.
+ */
+ private ComponentMetadata m_metadata;
+
+ /**
+ * The context of the component.
+ */
+ private BundleContext m_context;
+
+ /**
+ * Handler list.
+ */
+ private Handler[] m_handlers = new Handler[0];
+
+ /**
+ * Component state (STOPPED at the beginning).
+ */
+ private int m_state = INVALID;
+
+ // Fields use for the manipulation, the loading of the class and for the instance creation
+
+ /**
+ * Manipulatd clazz.
+ */
+ private Class m_clazz;
+
+ /**
+ * Instances of the components.
+ */
+ private Object[] m_instances = new Object[0];
+
+ // Constructor
+ /**
+ * Construct a new Component Manager.
+ * @param factory : the factory managing the component manager
+ */
+ public ComponentManager(ComponentManagerFactory factory) {
+ m_factory = factory;
+ m_context = factory.getBundleContext();
+ Activator.getLogger().log(Level.INFO, "[Bundle " + m_context.getBundle().getBundleId() + "] Create a component manager from the factory " + m_factory);
+ }
+
+ /**
+ * Configure the component manager.
+ * Stop the existings handler, clear the handler list, change the metadata, recreate the handlers
+ * @param cm
+ */
+ public void configure(Element cm) {
+ Activator.getLogger().log(Level.INFO, "[Bundle " + m_context.getBundle().getBundleId() + "] Configure the component manager " + cm.getAttribute("className"));
+
+ // Stop all previous registred handler
+ if (m_handlers.length != 0) { stop(); }
+
+ // Clear the handler list
+ m_handlers = new Handler[0];
+
+ // Change the metadata
+ m_metadata = new ComponentMetadata(cm);
+
+ // Create the standard handlers and add these handlers to the list
+ for (int i = 0; i < IPojoConfiguration.INTERNAL_HANDLERS.length; i++) {
+ // Create a new instance
+ try {
+ Handler h = (Handler)IPojoConfiguration.INTERNAL_HANDLERS[i].newInstance();
+ h.configure(this, cm);
+ } catch (InstantiationException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] Cannot instantiate the handler " + IPojoConfiguration.INTERNAL_HANDLERS[i] + " : " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] 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("")) {
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] Look for class for the namespace : " + cm.getNamespaces()[i]);
+ // It is not an internal handler, try to load it
+ try {
+ Class c = m_context.getBundle().loadClass(cm.getNamespaces()[i]);
+ //Class c = Class.forName(cm.getNamespaces()[i]);
+ Handler h = (Handler) c.newInstance();
+ h.configure(this, cm);
+ } catch (ClassNotFoundException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] Cannot instantiate the handler " + cm.getNamespaces()[i] + " : " + e.getMessage());
+ } catch (InstantiationException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] Cannot instantiate the handler " + cm.getNamespaces()[i] + " : " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] Cannot instantiate the handler " + cm.getNamespaces()[i] + " : " + e.getMessage());
+ }
+
+ }
+ }
+ }
+
+ /**
+ * @return the component metadata.
+ */
+ public ComponentMetadata getComponentMetatada() { return m_metadata; }
+
+ /**
+ * @return the list of the registred handlers.
+ */
+ public Handler[] getRegistredHandlers() { 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 Handler getHandler(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 component manager.
+ */
+ public void start() {
+ // Start all the handlers
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] Start the component manager with " + m_handlers.length + " handlers");
+
+ // The new state of the component is UNRESOLVED
+ m_state = INVALID;
+
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].start();
+ }
+
+ // Defines the state of the component :
+ check();
+ }
+
+ /**
+ * Stop the component manager.
+ */
+ public void stop() {
+ setState(INVALID);
+ // Stop all the handlers
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].stop();
+ }
+ m_instances = new Object[0];
+ }
+
+ /**
+ * 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) { Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] Component " + m_metadata.getClassName() + " State -> UNRESOLVED"); }
+ if (state == VALID) { Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] Component " + m_metadata.getClassName() + " State -> VALID"); }
+
+ // The state changed call the handler stateChange method
+ m_state = state;
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].stateChanged(state);
+ }
+ }
+ }
+
+ /**
+ * @return the actual state of the component
+ */
+ public int getState() {
+ return m_state;
+ }
+
+ // ===================== end Lifecycle management =====================
+
+ // ================== Class & Instance management ===================
+
+ /**
+ * @return the factory of the component
+ */
+ public ComponentManagerFactory getFactory() { return m_factory; }
+
+ /**
+ * Load the manipulated class.
+ */
+ private void load() {
+ try {
+ m_clazz = m_factory.getBundleContext().getBundle().loadClass(m_metadata.getClassName());
+ } catch (Exception e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] Class not found during the loading phase : " + e.getMessage());
+ return;
+ }
+ }
+
+ /**
+ * @return true if the class is loaded
+ */
+ private boolean isLoaded() {
+ return (m_clazz != null);
+ }
+
+ private void addInstance(Object o) {
+ for (int i = 0; (m_instances != null) && (i < m_instances.length); i++) {
+ if (m_instances[i] == o) { return; }
+ }
+
+ if (m_instances.length > 0) {
+ Object[] newInstances = new Object[m_instances.length + 1];
+ System.arraycopy(m_instances, 0, newInstances, 0, m_instances.length);
+ newInstances[m_instances.length] = o;
+ m_instances = newInstances;
+ }
+ else {
+ m_instances = new Object[] {o};
+ }
+ }
+
+ private void removeInstance(Object o) {
+ int idx = -1;
+ for (int i = 0; i < m_instances.length; i++) {
+ if (m_instances[i] == o) { idx = i; break; }
+ }
+
+ if (idx >= 0) {
+ if ((m_instances.length - 1) == 0) { m_instances = new Element[0]; }
+ else {
+ Object[] newInstances = new Object[m_instances.length - 1];
+ System.arraycopy(m_instances, 0, newInstances, 0, idx);
+ if (idx < newInstances.length) {
+ System.arraycopy(m_instances, idx + 1, newInstances, idx, newInstances.length - idx); }
+ m_instances = newInstances;
+ }
+ }
+ }
+
+ /**
+ * @return the created instance of the component.
+ */
+ public Object[] getInstances() { return m_instances; }
+
+ /**
+ * Delete the created instance (remove it from the list, to allow the garbage collector to eat the instance).
+ * @param o : the instance to delete
+ */
+ public void deleteInstance(Object o) { removeInstance(o); }
+
+ /**
+ * Create an instance of the component.
+ * This method need to be called one time only for singleton provided service
+ * @return a new instance
+ */
+ public Object createInstance() {
+ if (!isLoaded()) { load(); }
+ Object instance = null;
+ try {
+
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] createInstance -> call setComponentManager");
+ // Invoke the static method setComponentManager on the manipulated class
+ Method method = m_clazz.getMethod("setComponentManager", new Class[] {this.getClass()});
+ method.invoke(null, new Object[] {this});
+
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] createInstance -> Try to find the constructor");
+
+ // Try to find if there is a constructor with a bundle context as parameter :
+ try {
+ Constructor constructor = m_clazz.getConstructor(new Class[] {BundleContext.class});
+ constructor.setAccessible(true);
+ instance = constructor.newInstance(new Object[] {m_factory.getBundleContext()});
+ }
+ catch (NoSuchMethodException e) {
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] createInstance -> No constructor with a bundle context");
+ }
+
+ // Create an instance if no instance are already created with <init>()BundleContext
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] createInstance -> Try to create the object with an empty constructor");
+ if (instance == null) { instance = m_clazz.newInstance(); }
+
+ } catch (InstantiationException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] createInstance -> The Component Instance cannot be instancied : " + e.getMessage());
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] createInstance -> The Component Instance is not accessible : " + e.getMessage());
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] createInstance -> The Component Instance is not accessible (security reason) : " + e.getMessage());
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] createInstance -> Cannot invoke the setComponentManager method (illegal argument) : " + e.getMessage());
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] createInstance -> Cannot invoke the setComponentManager method (illegal target) : " + e.getMessage());
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_metadata.getClassName() + "] createInstance -> Cannot invoke the setComponentManager method (method not found) : " + e.getMessage());
+ e.printStackTrace();
+ }
+
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] createInstance -> Return the instance " + instance);
+
+ // Register the new instance
+ addInstance(instance);
+ return instance;
+ }
+
+ /**
+ * @return the instance of the component to use for singleton component
+ */
+ public Object getInstance() {
+ if (m_instances.length == 0) { createInstance(); }
+ return m_instances[0];
+ }
+
+ /**
+ * @return the manipulated class
+ */
+ public Class getClazz() {
+ if (!isLoaded()) { load(); }
+ return m_clazz;
+ }
+
+ // ================== end Class & Instance management ================
+
+ // ======================== Handlers Management ======================
+
+ /**
+ * Register the given handler to the current component manager.
+ * @param h : the handler to register
+ */
+ public void register(Handler h) {
+ for (int i = 0; (m_handlers != null) && (i < m_handlers.length); i++) {
+ if (m_handlers[i] == h) {
+ return;
+ }
+ }
+
+ if (m_handlers != null) {
+ Handler[] newList = new Handler[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(Handler 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 Handler[0];
+ }
+ else {
+ Handler[] newList = new Handler[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;
+ }
+ }
+ }
+
+ /**
+ * This method is called by the manipulated class each time that a GETFIELD instruction is found.
+ * The method ask to each handler which value need to be returned.
+ * @param fieldName : the field name on which the GETFIELD instruction is called
+ * @param initialValue : the value of the field in the code
+ * @return the value decided by the last asked handler (throw a warining if two fields decide two different values)
+ */
+ public Object getterCallback(String fieldName, Object initialValue) {
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] Call the getterCallbackMethod on " + fieldName + " with " + initialValue);
+ Object result = null;
+ for (int i = 0; i < m_handlers.length; i++) {
+ Object handlerResult = m_handlers[i].getterCallback(fieldName, initialValue);
+ if (handlerResult != initialValue) { result = handlerResult; }
+ }
+
+ if (result != null) {
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] getterCallbackMethod return for " + fieldName + " -> " + result);
+ return result;
+ } else {
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] getterCallbackMethod return for " + fieldName + " -> " + initialValue);
+ return initialValue;
+ }
+ }
+
+ /**
+ * This method is called by the manipulated class each time that a PUTFILED instruction is found.
+ * the method send to each handler the new value.
+ * @param fieldName : the field name on which the PUTFIELD instruction is called
+ * @param objectValue : the value of the field
+ */
+ public void setterCallback(String fieldName, Object objectValue) {
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] Call the setterCallbackMethod on " + fieldName + " with " + objectValue);
+
+ for (int i = 0; i < m_handlers.length; i++) {
+ m_handlers[i].setterCallback(fieldName, objectValue);
+ }
+ }
+
+ /**
+ * @return the context of the component.
+ */
+ public BundleContext getContext() { return m_context; }
+
+ /**
+ * Check the state of all handlers.
+ */
+ public void check() {
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] Check the component state");
+ boolean isValid = true;
+ for (int i = 0; i < m_handlers.length; i++) {
+ boolean b = m_handlers[i].isValid();
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] Validity of the handler : " + m_handlers[i] + " = " + b);
+ isValid = isValid && b;
+ }
+
+ // Update the component state if necessary
+ if (!isValid && m_state == VALID) {
+ // Need to update the state to UNRESOLVED
+ setState(INVALID);
+ m_instances = new Object[0];
+ return;
+ }
+ if (isValid && m_state == INVALID) {
+ setState(VALID);
+ if (m_metadata.isImmediate() && m_instances.length == 0) { createInstance(); }
+ }
+
+ Activator.getLogger().log(Level.INFO, "[" + m_metadata.getClassName() + "] Component Manager : " + m_state);
+ }
+
+
+ // ======================= end Handlers Management =====================
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/ComponentManagerFactory.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/ComponentManagerFactory.java
new file mode 100644
index 0000000..92678da
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/ComponentManagerFactory.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.logging.Level;
+
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The component manager factory class manages component manager object.
+ * @author Clement Escoffier
+ */
+public class ComponentManagerFactory {
+
+ // Fields :
+ /**
+ * List of the managed component manager.
+ */
+ private ComponentManager[] m_componentManagers = new ComponentManager[0];
+
+ /**
+ * The bundle context reference.
+ */
+ private BundleContext m_bundleContext = null;
+
+ //End field
+
+ // Field accessors
+
+ /**
+ * Add a component manager factory to the component manager list.
+ * @param cm : the new component metadata.
+ */
+ private void addComponent(ComponentManager cm) {
+
+ // If the component manager array is not empty add the new factory at the end
+ if (m_componentManagers.length != 0) {
+ ComponentManager[] newCM = new ComponentManager[m_componentManagers.length + 1];
+ System.arraycopy(m_componentManagers, 0, newCM, 0, m_componentManagers.length);
+ newCM[m_componentManagers.length] = cm;
+ m_componentManagers = newCM;
+ }
+ // Else create an array of size one with the new component manager
+ else {
+ m_componentManagers = new ComponentManager[] {cm};
+ }
+ }
+
+ /**
+ * Remove the component manager for m the list.
+ * @param cm : the component manager to remove
+ */
+ public void removeComponent(ComponentManager cm) {
+ cm.stop();
+ int idx = -1;
+
+ for (int i = 0; i < m_componentManagers.length; i++) {
+ if (m_componentManagers[i] == cm) { idx = i; }
+ }
+
+ if (idx >= 0) {
+ if ((m_componentManagers.length - 1) == 0) { m_componentManagers = new ComponentManager[0]; }
+ else {
+ ComponentManager[] newCMList = new ComponentManager[m_componentManagers.length - 1];
+ System.arraycopy(m_componentManagers, 0, newCMList, 0, idx);
+ if (idx < newCMList.length) {
+ System.arraycopy(m_componentManagers, idx + 1, newCMList, idx, newCMList.length - idx); }
+ m_componentManagers = newCMList;
+ }
+ }
+ }
+
+ /**
+ * @return the iPOJO activator reference
+ */
+ public BundleContext getBundleContext() { return m_bundleContext; }
+
+ // End field accessors
+
+ /**
+ * Constructor of a ComponentManagerFactory from a component metadata.
+ * This contructor is use when the iPOJO Activator is used.
+ * @param cm : Component Metadata for the component factory
+ */
+ protected ComponentManagerFactory(Activator activator, Element cm) {
+ m_bundleContext = activator.getBundleContext();
+ createComponentManager(cm);
+ }
+
+ /**
+ * Create a component manager factory and create a component manager with the given medatada.
+ * @param bc : bundle context
+ * @param cm : metadata of the component to create
+ */
+ public ComponentManagerFactory(BundleContext bc, Element cm) {
+ m_bundleContext = bc;
+ createComponentManager(cm);
+ }
+
+ /**
+ * Create a component manager factory, no component manager are created.
+ * @param bc
+ */
+ public ComponentManagerFactory(BundleContext bc) {
+ m_bundleContext = bc;
+ }
+
+ /**
+ * Create a component manager form the component metadata.
+ * @param cm : Component Metadata
+ * @return a component manager configured with the metadata
+ */
+ public ComponentManager createComponentManager(Element cm) {
+ ComponentManager component = new ComponentManager(this);
+ component.configure(cm);
+ addComponent(component);
+ return component;
+ }
+
+ // Factory lifecycle management
+
+ /**
+ * Stop all the component managers.
+ */
+ public void stop() {
+ Activator.getLogger().log(Level.INFO, "[Bundle " + m_bundleContext.getBundle().getBundleId() + "] Stop the component factory");
+ for (int i = 0; i < m_componentManagers.length; i++) {
+ ComponentManager cm = m_componentManagers[i];
+ cm.stop();
+ }
+ }
+
+ /**
+ * Start all the component managers.
+ */
+ public void start() {
+ Activator.getLogger().log(Level.INFO, "[Bundle " + m_bundleContext.getBundle().getBundleId() + "] Start the component factory");
+ for (int i = 0; i < m_componentManagers.length; i++) {
+ ComponentManager cm = m_componentManagers[i];
+ cm.start();
+ }
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/ComponentMetadata.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/ComponentMetadata.java
new file mode 100644
index 0000000..662b170
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/ComponentMetadata.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.logging.Level;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Component Metadata.
+ * @author Clement Escoffier
+ */
+public class ComponentMetadata {
+
+ /**
+ * Class name of the component.
+ */
+ private String m_className;
+
+ /**
+ * Is the component an immediate component ?
+ */
+ private boolean m_isImmediate = false;
+
+ /**
+ * Metadata of the component.
+ */
+ private Element m_metadata;
+
+ /**
+ * Constructor.
+ * @param metadata : metadata of the component
+ */
+ public ComponentMetadata(Element metadata) {
+ m_metadata = metadata;
+ m_className = metadata.getAttribute("className");
+ if (m_className == null) {
+ Activator.getLogger().log(Level.SEVERE, "The class name of ths component cannot be setted, it does not exist in the metadata");
+ }
+ if (metadata.containsAttribute("immediate") && metadata.getAttribute("immediate").equals("true")) { m_isImmediate = true; }
+ }
+
+ // Getter
+ /**
+ * @return the class name
+ */
+ public String getClassName() { return m_className; }
+
+ /**
+ * @return the component metadata
+ */
+ public Element getMetadata() { return m_metadata; }
+
+ /**
+ * @return true if its an immediate component
+ */
+ public boolean isImmediate() { return m_isImmediate; }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/DummyActivator.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/DummyActivator.java
new file mode 100644
index 0000000..87a3b74
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/DummyActivator.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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 org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This class is just if you start ipojo. It does nothing but avoid the launch of the Activator class on the iPOJO bundle
+ * @author escoffie
+ *
+ */
+public class DummyActivator implements BundleActivator {
+
+ /**
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext arg0) throws Exception {
+ System.out.println("iPOJO Started");
+ }
+
+ /**
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext arg0) throws Exception {
+ System.out.println("iPOJO Stopped");
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Handler.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Handler.java
new file mode 100644
index 0000000..f08c9d0
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Handler.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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 org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Handler Interface.
+ * An handler need implements tese method to be notifed of lifecycle change, getfield operation and putfield operation
+ * @author Clement Escoffier
+ */
+public interface Handler {
+
+ /**
+ * Configure the handler.
+ * @param cm : the component manager
+ * @param metadata : the metadata of the component
+ */
+ void configure(ComponentManager cm, Element metadata);
+
+ /**
+ * Stop the handler : stop the management.
+ */
+ void stop();
+
+ /**
+ * Start the handler : start the management.
+ */
+ void start();
+
+ /**
+ * This method is called when a PUTFIELD operation is detected.
+ * @param fieldName : the field name
+ * @param value : the value passed to the field
+ */
+ void setterCallback(String fieldName, Object value);
+
+ /**
+ * This method is called when a GETFIELD operation is detected.
+ * @param fieldName : the field name
+ * @param value : the value passed to the field (by the previous handler)
+ * @return : the managed value of the field
+ */
+ Object getterCallback(String fieldName, Object value);
+
+ /**
+ * Is the actual state valid for this handler ?
+ * @return true is the state seems valid for the handler
+ */
+ boolean isValid();
+
+ /**
+ * This method is called when the component state changed.
+ * @param state : the new state
+ */
+ void stateChanged(int state);
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/IPojoConfiguration.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/IPojoConfiguration.java
new file mode 100644
index 0000000..13aaff3
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/IPojoConfiguration.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.logging.Level;
+
+import org.apache.felix.ipojo.handlers.architecture.ArchitectureHandler;
+import org.apache.felix.ipojo.handlers.configuration.ConfigurationHandler;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandler;
+import org.apache.felix.ipojo.handlers.lifecycle.callback.LifecycleCallbackHandler;
+import org.apache.felix.ipojo.handlers.providedService.ProvidedServiceHandler;
+
+/**
+ * Activator Basic Configuration.
+ * - Log Level
+ * - Available handlers
+ * @author Clement Escoffier
+ */
+public class IPojoConfiguration {
+
+ /**
+ * iPOJO logger log level.
+ */
+ public static final Level LOG_LEVEL = Level.WARNING;
+
+ /**
+ * Available handlers in the iPOJO bundle.
+ */
+ public static final Class[] INTERNAL_HANDLERS = new Class[] {
+ DependencyHandler.class,
+ ProvidedServiceHandler.class,
+ LifecycleCallbackHandler.class,
+ ConfigurationHandler.class,
+ ArchitectureHandler.class
+ };
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Nullable.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Nullable.java
new file mode 100644
index 0000000..6287128
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/Nullable.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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;
+
+/**
+ * A nullable object must implement this interface.
+ * @author Clement Escoffier
+ */
+public interface Nullable {
+ // Nothing
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/Architecture.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/Architecture.java
new file mode 100644
index 0000000..22f4f15
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/Architecture.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.architecture;
+
+/**
+ * Architecture service.
+ * Allows to have information of the service delivery about GenSD component.
+ * @author Clement Escoffier
+ */
+public interface Architecture {
+
+ /**
+ * Return the full architecture.
+ * @return : the current component description
+ */
+ ComponentDescription getComponentDescription();
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/ComponentDescription.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/ComponentDescription.java
new file mode 100644
index 0000000..01eccdb
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/ComponentDescription.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.architecture;
+
+import java.util.HashMap;
+
+
+/**
+ * Component Description.
+ * @author Clement Escoffier
+ */
+public class ComponentDescription {
+
+ /**
+ * The Component class name.
+ * This String is the identifier of the component.
+ */
+ private String m_className;
+
+ /**
+ * List of provided service.
+ */
+ private ProvidedServiceDescription[] m_provideServices = new ProvidedServiceDescription[0];
+
+ /**
+ * List of dependencies.
+ */
+ private DependencyDescription[] m_dependencies = new DependencyDescription[0];
+
+ /**
+ * Hashmap [Instance reference, service reference] of the used service.
+ */
+ private HashMap m_usedServices = new HashMap();
+
+ /**
+ * Created Instances of the components.
+ */
+ private String[] m_instances = new String[0];
+
+ /**
+ * State of the component (VALID / UNRESOLVED).
+ */
+ private int m_state;
+
+ /**
+ * Constructor.
+ * @param name : the name of the component (the class name).
+ * @param state : the state of the component.
+ */
+ public ComponentDescription(String name, int state) {
+ m_className = name;
+ m_state = state;
+ m_usedServices.clear();
+ m_instances = new String[0];
+ }
+
+ /**
+ * @return the created instances
+ */
+ public String[] getInstances() { return m_instances; }
+
+ /**
+ * Set the instances array.
+ */
+ public void setInstances(String[] instances) { m_instances = instances; }
+
+ /**
+ * @return : the class name of the component
+ */
+ public String getClassName() { return m_className; }
+
+ /**
+ * @return the live dependency list
+ */
+ public DependencyDescription[] getDependencies() { return m_dependencies; }
+
+ /**
+ * @return the live provided service list
+ */
+ public ProvidedServiceDescription[] getProvideServices() { return m_provideServices; }
+
+ /**
+ * Add a dependency.
+ * @param dep : the dependency to add
+ */
+ public void addDependency(DependencyDescription dep) {
+ // Verify that the dependency description is not already in the array.
+ for (int i = 0; (i < m_dependencies.length); i++) {
+ if (m_dependencies[i] == dep) {
+ return; //NOTHING TO DO, the description is already in the array
+ }
+ }
+ // The component Description is not in the array, add it
+ DependencyDescription[] newDep = new DependencyDescription[m_dependencies.length + 1];
+ System.arraycopy(m_dependencies, 0, newDep, 0, m_dependencies.length);
+ newDep[m_dependencies.length] = dep;
+ m_dependencies = newDep;
+ }
+
+ /**
+ * Add a provided service.
+ * @param pds : the provided service to add
+ */
+ public void addProvidedService(ProvidedServiceDescription pds) {
+ //Verify that the provided service description is not already in the array.
+ for (int i = 0; (i < m_provideServices.length); i++) {
+ if (m_provideServices[i] == pds) {
+ return; //NOTHING DO DO, the description is already in the array
+ }
+ }
+
+ // The component Description is not in the array, add it
+ ProvidedServiceDescription[] newPSD = new ProvidedServiceDescription[m_provideServices.length + 1];
+ System.arraycopy(m_provideServices, 0, newPSD, 0, m_provideServices.length);
+ newPSD[m_provideServices.length] = pds;
+ m_provideServices = newPSD;
+
+ }
+
+ /**
+ * Set the state of the component.
+ * @param i : the state
+ */
+ public void setState(int i) {
+ m_state = i;
+ }
+
+ /**
+ * @return the state of the component.
+ */
+ public int getState() {
+ return m_state;
+ }
+
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/DependencyDescription.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/DependencyDescription.java
new file mode 100644
index 0000000..3559d9a
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/DependencyDescription.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.architecture;
+
+import java.util.HashMap;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Dependency Description.
+ * @author Clement Escoffier
+ */
+public class DependencyDescription {
+
+ /**
+ * Needed Service Interface.
+ */
+ private String m_interface;
+
+ /**
+ * Multiple ?
+ */
+ private boolean m_multiple;
+
+ /**
+ * Optional ?
+ */
+ private boolean m_optional;
+
+ /**
+ * State (VALID | INVALID).
+ */
+ private int m_state;
+
+ /**
+ * Filter.
+ */
+ private String m_filter;
+ /**
+ * Hashmap [Instance reference, service reference] of the used service.
+ */
+ private HashMap m_usedServices = new HashMap();
+
+
+ /**
+ * The list of service reference.
+ */
+ private ServiceReference[] m_serviceReferences;
+
+ /**
+ * Parent of the dependency either de ProvidedServiceDescription or a ComponentDescription.
+ */
+ private Object m_parent;
+
+
+ /**
+ * @return true if the dependency is a multiple dependency.
+ */
+ public boolean isMultiple() {
+ return m_multiple;
+ }
+
+ /**
+ * @return true if the dependency is an optional dependency.
+ */
+ public boolean isOptional() {
+ return m_optional;
+ }
+
+ /**
+ * @return the filter.
+ */
+ public String getFilter() {
+ return m_filter;
+ }
+
+ /**
+ * @return the needed interface.
+ */
+ public String getInterface() {
+ return m_interface;
+ }
+
+ /**
+ * @return the state of the dependency.
+ */
+ public int getState() {
+ return m_state;
+ }
+
+ /**
+ * Constructor.
+ * @param itf : the needed itf
+ * @param multiple : is the dependency a multiple dependency ?
+ * @param optional : is the depdendency optional ?
+ * @param filter : the filter
+ * @param state : the state
+ * @param parent : the description of the parent (either a ProvidedServiceDescription, either a ComponentDescription)
+ */
+ public DependencyDescription(String itf, boolean multiple, boolean optional, String filter, int state, Object parent) {
+ super();
+ m_interface = itf;
+ m_multiple = multiple;
+ m_optional = optional;
+ m_filter = filter;
+ m_state = state;
+ m_serviceReferences = new ServiceReference[0];
+ m_parent = parent;
+ }
+
+ /**
+ * @return the array of service reference (only if the cardinality could be n).
+ */
+ public ServiceReference[] getServiceReferences() {
+ return m_serviceReferences;
+ }
+
+ /**
+ * @return the ServiceReference (only if the cardinality could be 1).
+ */
+ public ServiceReference getServiceReference() {
+ return m_serviceReferences[0];
+ }
+
+ /**
+ * Set the service reference array.
+ * @param sr : the array of service reference
+ */
+ public void setServiceReferences(ServiceReference[] sr) {
+ m_serviceReferences = sr;
+ }
+
+ /**
+ * @return the parent of the dependency
+ */
+ public Object getParent() {
+ return m_parent;
+ }
+
+ /**
+ * @return the hashmap [object reference, service reference] containing the used services
+ */
+ public HashMap getUsedServices() { return m_usedServices; }
+
+ /**
+ * Set the usedServices.
+ * @param hm : the new usedService
+ */
+ public void setUsedServices(HashMap hm) {
+ m_usedServices = hm;
+ }
+
+
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/ProvidedServiceDescription.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/ProvidedServiceDescription.java
new file mode 100644
index 0000000..64311ba
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/ProvidedServiceDescription.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.architecture;
+
+import java.util.Properties;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Provided Service Description.
+ * @author Clement Escoffier
+ */
+public class ProvidedServiceDescription {
+
+ /**
+ * Provided Service Specification.
+ */
+ private String[] m_serviceSpecification;
+
+ /**
+ * Dependency of the service.
+ */
+ private DependencyDescription[] m_dependencies = new DependencyDescription[0];
+
+
+ /**
+ * State.
+ */
+ private int m_state;
+
+ /**
+ * The service reference.
+ */
+ private ServiceReference m_serviceReference;
+
+
+ /**
+ * Handler on the component description who contains this description.
+ */
+ private ComponentDescription m_parent;
+
+ /**
+ * Properties of the provided service.
+ */
+ private Properties m_properties = new Properties();
+
+
+ /**
+ * Constructor.
+ * @param serviceSpecification : the provided contract
+ * @param state : state (UNREGITRED | REGISTRED)
+ * @param sr : Service Registration (to obtain the reference), or null if state is UNREGISTRED
+ * @param parent : the component description declaring this proided service
+ */
+ public ProvidedServiceDescription(String[] serviceSpecification, int state, ServiceReference sr, ComponentDescription parent) {
+ m_serviceSpecification = serviceSpecification;
+ m_state = state;
+ m_serviceReference = sr;
+ m_parent = parent;
+ }
+
+ /**
+ * @return the provided contract name.
+ */
+ public String[] getServiceSpecification() {
+ return m_serviceSpecification;
+ }
+
+ /**
+ * Add a dependency descriptino to this provided service description.
+ * @param dep : the dependency description to add
+ */
+ public void addDependency(DependencyDescription dep) {
+ // Verify that the dependency description is not already in the array.
+ for (int i = 0; (i < m_dependencies.length); i++) {
+ if (m_dependencies[i] == dep) {
+ return; //NOTHING DO DO, the description is already in the array
+ }
+ }
+ // The component Description is not in the array, add it
+ DependencyDescription[] newDep = new DependencyDescription[m_dependencies.length + 1];
+ System.arraycopy(m_dependencies, 0, newDep, 0, m_dependencies.length);
+ newDep[m_dependencies.length] = dep;
+ m_dependencies = newDep;
+ }
+
+ /**
+ * Add a property to the current provided service description.
+ * @param key : the key of the property
+ * @param value : the value of the property
+ */
+ public void addProperty(String key, String value) {
+ m_properties.put(key, value);
+ }
+
+ /**
+ * Set the set of properties. This function create a clone of the argument.
+ * @param props : the properties
+ */
+ public void setProperty(Properties props) {
+ m_properties = (Properties)props.clone();
+ }
+
+ /**
+ * @return the dependeny description list.
+ */
+ public DependencyDescription[] getDependencies() {
+ return m_dependencies;
+ }
+
+ /**
+ * @return the properties.
+ */
+ public Properties getProperties() {
+ return m_properties;
+ }
+
+ /**
+ * @return the state of the provided service (UNREGISTRED | REGISTRED).
+ */
+ public int getState() {
+ return m_state;
+ }
+
+ /**
+ * @return the service reference (null if the service is unregistred).
+ */
+ public ServiceReference getServiceReference() {
+ return m_serviceReference;
+ }
+
+ /**
+ * @return the parent description.
+ */
+ public ComponentDescription getComponentDescription() {
+ return m_parent;
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/State.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/State.java
new file mode 100644
index 0000000..1291f03
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/architecture/State.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.architecture;
+
+/**
+ * @author Clement Escoffier
+ *
+ */
+public class State {
+
+ /**
+ * Return the String corresponding to a component state.
+ * @param state : the state in int
+ * @return : the string of the state (Stopped, Unresolved, Resolved) or "Unknow" if state is not revelant
+ */
+ public static String printComponentState(int state) {
+ switch(state) {
+ case(0) :
+ return "STOPPED";
+ case(1) :
+ return "INVALID";
+ case(2) :
+ return "VALID";
+ default :
+ return "UNKNOW";
+ }
+ }
+
+ /**
+ * Return the String corresponding to a dependency state.
+ * @param state : the state in int
+ * @return : the string of the state (Stopped, Valid, Invalid) or "Unknow" if state is not revelant
+ */
+ public static String printDependencyState(int state) {
+ switch(state) {
+ case(0) :
+ return "STOPPED";
+ case(1) :
+ return "RESOLVED";
+ case(2) :
+ return "UNRESOLVED";
+ default :
+ return "UNKNOW";
+ }
+ }
+
+ /**
+ * Return the String corresponding to a provided service state.
+ * @param state : the state in int
+ * @return : the string of the state (Unregistred, Registredu) or "Unknow" if state is not revelant
+ */
+ public static String printProvidedServiceState(int state) {
+ switch(state) {
+ case(0) :
+ return "UNREGISTRED";
+ case(1) :
+ return "REGISTRED";
+ default :
+ return "UNKNOW";
+ }
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java
new file mode 100644
index 0000000..d17cde8
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.architecture;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentManager;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.ComponentDescription;
+import org.apache.felix.ipojo.architecture.DependencyDescription;
+import org.apache.felix.ipojo.architecture.ProvidedServiceDescription;
+import org.apache.felix.ipojo.handlers.dependency.Dependency;
+import org.apache.felix.ipojo.handlers.dependency.DependencyHandler;
+import org.apache.felix.ipojo.handlers.dependency.DependencyMetadata;
+import org.apache.felix.ipojo.handlers.providedService.Property;
+import org.apache.felix.ipojo.handlers.providedService.PropertyMetadata;
+import org.apache.felix.ipojo.handlers.providedService.ProvidedService;
+import org.apache.felix.ipojo.handlers.providedService.ProvidedServiceHandler;
+import org.apache.felix.ipojo.handlers.providedService.ProvidedServiceMetadata;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Achtiecture Handler : do reflection on your component.
+ * @author Clement Escoffier
+ */
+public class ArchitectureHandler implements Handler, Architecture {
+
+ /**
+ * Component Manager.
+ */
+ private ComponentManager m_manager;
+
+ /**
+ * Service Registration of the Architecture service provided by this handler.
+ */
+ private ServiceRegistration m_sr;
+
+ /**
+ * Unique name of the component : either the name of the component, either the classname if the name if not setted.
+ */
+ private String m_name;
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.ComponentManager, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void configure(ComponentManager cm, Element metadata) {
+ if (metadata.containsAttribute("architecture")) {
+ String isArchitectureEnabled = (metadata.getAttribute("architecture")).toLowerCase();
+ if (isArchitectureEnabled.equals("true")) { cm.register(this); }
+ }
+
+ if (metadata.containsAttribute("name")) { m_name = metadata.getAttribute("name"); }
+ else { m_name = metadata.getAttribute("className"); }
+
+ m_manager = cm;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ try {
+ if (m_sr != null) { m_sr.unregister(); }
+ } 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 Implementation Class", m_manager.getComponentMetatada().getClassName());
+ properties.put(Constants.SERVICE_PID, m_name);
+
+ m_sr = bc.registerService(Architecture.class.getName(), this, properties);
+
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#setterCallback(java.lang.String, java.lang.Object)
+ */
+ public void setterCallback(String fieldName, Object value) { // Nothing to do
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#getterCallback(java.lang.String, java.lang.Object)
+ */
+ public Object getterCallback(String fieldName, Object value) { return value; }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#isValid()
+ */
+ public boolean isValid() { return true; }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ // Nothing to do
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.architecture.Architecture#getComponentDescription()
+ */
+ public ComponentDescription getComponentDescription() {
+ int componentState = m_manager.getState();
+ ComponentDescription componentDescription = new ComponentDescription(m_name, componentState);
+
+ String[] instances = new String[m_manager.getInstances().length];
+ for (int i = 0; i < m_manager.getInstances().length; i++) {
+ instances[i] = m_manager.getInstances()[i].toString();
+ }
+ componentDescription.setInstances(instances);
+
+ Handler[] handlers = m_manager.getRegistredHandlers();
+ for (int i = 0; i < handlers.length; i++) {
+ if (handlers[i] instanceof DependencyHandler) {
+ DependencyHandler dh = (DependencyHandler)handlers[i];
+ for (int j = 0; j < dh.getDependencies().length; j++) {
+ Dependency dep = dh.getDependencies()[j];
+ DependencyMetadata dm = dep.getMetadata();
+
+ // Create & add the dependency description
+ DependencyDescription dd = new DependencyDescription(dm.getServiceSpecification(), dm.isMultiple(), dm.isOptional(), dm.getFilter(), dep.getState(), componentDescription);
+ dd.setUsedServices(dep.getUsedServices());
+ componentDescription.addDependency(dd);
+ }
+ }
+ if (handlers[i] instanceof ProvidedServiceHandler) {
+ ProvidedServiceHandler psh = (ProvidedServiceHandler)handlers[i];
+ for (int j = 0; j < psh.getProvidedService().length; j++) {
+ ProvidedService ps = psh.getProvidedService()[j];
+ ProvidedServiceMetadata psm = ps.getMetadata();
+ ProvidedServiceDescription psd = new ProvidedServiceDescription(psm.getServiceSpecification(), ps.getState(), ps.getServiceReference(), componentDescription);
+
+ Properties props = new Properties();
+ for (int k = 0; k < ps.getProperties().length; k++) {
+ Property prop = ps.getProperties()[k];
+ PropertyMetadata pm = prop.getMetadata();
+ if (prop.getValue() != null) {
+ props.put(pm.getName(), prop.getValue().toString());
+ }
+ }
+ psd.setProperty(props);
+ componentDescription.addProvidedService(psd);
+ }
+ }
+
+ }
+ return componentDescription;
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurableProperty.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurableProperty.java
new file mode 100644
index 0000000..8f5a636
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurableProperty.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.configuration;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.logging.Level;
+
+import org.apache.felix.ipojo.Activator;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * @author Clement Escoffier
+ * Configurable Property
+ */
+public class ConfigurableProperty {
+
+ /**
+ * Name of the property (filed name if not set).
+ */
+ private String m_name;
+
+ /**
+ * Field of the property.
+ */
+ private String m_field;
+
+ /**
+ * Value of the property.
+ */
+ private Object m_value;
+
+ /**
+ * Configuration Handler managing this property.
+ */
+ private ConfigurationHandler m_handler;
+
+ /**
+ * Configurable Property Constructor.
+ * @param name : name of the property (optional)
+ * @param field : name of the field (mandatory)
+ * @param value : initial value of the property (optional)
+ * @param ch : configuration handler managing this configurable property
+ */
+ public ConfigurableProperty(String name, String field, String value, ConfigurationHandler ch) {
+ m_handler = ch;
+ if (name != null) { m_name = name; }
+ else { m_name = field; }
+ m_field = field;
+
+ if (value != null) { setValue(m_field, value); }
+
+ }
+
+ /**
+ * Set the value of the property.
+ * @param strValue : value of the property (String)
+ */
+ private void setValue(String field, String strValue) {
+ // Look for the type of the field
+ Element manipulation = m_handler.getComponentManager().getComponentMetatada().getMetadata().getElements("Manipulation")[0];
+ String type = null;
+ for (int i = 0; i < manipulation.getElements("Field").length; i++) {
+ if (field.equals(manipulation.getElements("Field")[i].getAttribute("name"))) {
+ type = manipulation.getElements("Field")[i].getAttribute("type");
+ break;
+ }
+ }
+
+ if (type == null) { Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] The field " + field + " does not exist in the implementation"); return; }
+
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Set the value of the configurable property " + field + " [" + type + "] " + " with the value : " + strValue);
+
+ Object value = null;
+
+ if (type.equals("string") || type.equals("String")) { value = new String(strValue); }
+ if (type.equals("boolean")) { value = new Boolean(strValue); }
+ if (type.equals("byte")) { value = new Byte(strValue); }
+ if (type.equals("short")) { value = new Short(strValue); }
+ if (type.equals("int")) { value = new Integer(strValue); }
+ if (type.equals("long")) { value = new Long(strValue); }
+ if (type.equals("float")) { value = new Float(strValue); }
+ if (type.equals("double")) { value = new Double(strValue); }
+
+ if (value == null) {
+ // Else it is a neither a primitive type neither a String -> create the object by calling a constructor with a string in argument.
+ try {
+ Class c = m_handler.getComponentManager().getContext().getBundle().loadClass(type);
+ Constructor cst = c.getConstructor(new Class[] {String.class});
+ value = cst.newInstance(new Object[] {strValue});
+ } catch (ClassNotFoundException e) {
+ System.err.println("Class not found exception in setValue on " + type);
+ e.printStackTrace();
+ return;
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ return;
+ } catch (NoSuchMethodException e) {
+ System.err.println("Constructor not found exeption in setValue on " + type);
+ e.printStackTrace();
+ return;
+ } catch (IllegalArgumentException e) {
+ System.err.println("Argument problem to call the constructor of the type " + type);
+ e.printStackTrace();
+ return;
+ } catch (InstantiationException e) {
+ System.err.println("Instantiation problem " + type);
+ e.printStackTrace();
+ return;
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ System.err.println("Invocation problem " + type);
+ e.printStackTrace();
+ return;
+ }
+ }
+
+ m_value = value;
+
+ }
+
+ /**
+ * @return the name of the property.
+ */
+ public String getName() { return m_name; }
+
+ /**
+ * @return the field of the property.
+ */
+ public String getField() { return m_field; }
+
+ /**
+ * @return the value of the property.
+ */
+ public Object getValue() { return m_value; }
+
+ /**
+ * Fix the value of the property.
+ * @param value : the new value.
+ */
+ public void setValue(Object value) { m_value = value; }
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
new file mode 100644
index 0000000..a69f02a
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.configuration;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.logging.Level;
+
+import org.apache.felix.ipojo.ComponentManager;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.Activator;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * Handler managing the Configuration Admin.
+ * @author Clement Escoffier
+ */
+public class ConfigurationHandler implements Handler, ManagedService {
+
+ /**
+ * Reference on the component manager.
+ */
+ private ComponentManager m_manager;
+
+ /**
+ * List of the configurable fields.
+ */
+ private ConfigurableProperty[] m_configurableProperties = new ConfigurableProperty[0];
+
+ /**
+ * PID of the component.
+ */
+ private String m_pid;
+
+ /**
+ * Service registration of the ManagedService provided by this handler.
+ */
+ private ServiceRegistration m_sr;
+
+ /**
+ * @return component manager of this handler.
+ */
+ protected ComponentManager getComponentManager() { return m_manager; }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.ComponentManager, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void configure(ComponentManager cm, Element metadata) {
+ // Store the component manager
+ m_manager = cm;
+ m_configurableProperties = new ConfigurableProperty[0];
+
+ // Build the hashmap
+ Element[] configurables = metadata.getElements("ConfigurableProperty");
+
+ if (configurables.length > 0) { m_manager.register(this); }
+ else { return; }
+
+ for (int i = 0; i < configurables.length; i++) {
+ String fieldName = configurables[i].getAttribute("field");
+ String name = null;
+ if (configurables[i].containsAttribute("name")) { name = configurables[i].getAttribute("name"); }
+ else { name = fieldName; }
+ String value = null;
+ if (configurables[i].containsAttribute("value")) {
+ value = configurables[i].getAttribute("value");
+ }
+ ConfigurableProperty cp = new ConfigurableProperty(name, fieldName, value, this);
+ addProperty(cp);
+ }
+
+ // Get the PID :
+ if (metadata.containsAttribute("name")) { m_pid = metadata.getAttribute("name"); }
+ else { m_pid = metadata.getAttribute("className"); }
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ // Unregister the service
+ if (m_sr != null) {
+ Activator.getLogger().log(Level.INFO, "[" + m_manager.getComponentMetatada().getClassName() + "] Unregister Managed Service");
+ m_sr.unregister();
+ m_sr = null;
+ }
+
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ // Unregister the service if already registred (it should not happen )
+ if (m_sr != null) { m_sr.unregister(); }
+
+ // Register the ManagedService
+ BundleContext bc = m_manager.getContext();
+ Dictionary properties = new Properties();
+ properties.put(Constants.SERVICE_PID, m_pid);
+
+ Activator.getLogger().log(Level.INFO, "[" + m_manager.getComponentMetatada().getClassName() + "] Register Managed Service");
+ m_sr = bc.registerService(ManagedService.class.getName(), this, properties);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#setterCallback(java.lang.String, java.lang.Object)
+ */
+ public void setterCallback(String fieldName, Object value) {
+ // Nothing to do
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#getterCallback(java.lang.String, java.lang.Object)
+ */
+ public Object getterCallback(String fieldName, Object value) {
+ // Check if the field is a configurable property
+ for (int i = 0; i < m_configurableProperties.length; i++) {
+ if (m_configurableProperties[i].getField().equals(fieldName)) {
+ return m_configurableProperties[i].getValue();
+ }
+ }
+ return value;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#isValid()
+ */
+ public boolean isValid() {
+ return true;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ if (state == ComponentManager.VALID) {
+ if (m_sr == null) { start(); }
+ return;
+ }
+ if (state == ComponentManager.INVALID) {
+ if (m_sr != null) { stop(); }
+ return;
+ }
+ }
+
+ /**
+ * @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary)
+ */
+ public void updated(Dictionary np) throws ConfigurationException {
+
+ if (np != null) {
+ Enumeration keysEnumeration = np.keys();
+ while (keysEnumeration.hasMoreElements()) {
+ String name = (String)keysEnumeration.nextElement();
+ Object value = np.get(name);
+ boolean find = false;
+ // Check if the field is a configurable property
+ for (int i = 0; !find && i < m_configurableProperties.length; i++) {
+ if (m_configurableProperties[i].getName().equals(name)) {
+ // Check if the value has change
+ if (m_configurableProperties[i].getValue() == null || !m_configurableProperties[i].getValue().equals(value)) {
+ m_configurableProperties[i].setValue(value); // Change the value
+ m_manager.setterCallback(m_configurableProperties[i].getField(), value); // says that the value has change
+ }
+ find = true;
+ // Else do nothing
+ }
+ }
+ if (!find) {
+ Activator.getLogger().log(Level.WARNING, "[" + m_manager.getComponentMetatada().getClassName() + "] The configuration is not valid, the property " + name + " is not a configurable property");
+ }
+ }
+ }
+ else { Activator.getLogger().log(Level.WARNING, "[" + m_manager.getComponentMetatada().getClassName() + "] The pushed configuration is null for " + m_pid); }
+
+ }
+
+ /**
+ * Add the given property metadata to the property metadata list.
+ * @param p : property metdata to add
+ */
+ protected void addProperty(ConfigurableProperty p) {
+ for (int i = 0; (m_configurableProperties != null) && (i < m_configurableProperties.length); i++) {
+ if (m_configurableProperties[i] == p) { return; }
+ }
+
+ if (m_configurableProperties.length > 0) {
+ ConfigurableProperty[] newProp = new ConfigurableProperty[m_configurableProperties.length + 1];
+ System.arraycopy(m_configurableProperties, 0, newProp, 0, m_configurableProperties.length);
+ newProp[m_configurableProperties.length] = p;
+ m_configurableProperties = newProp;
+ }
+ else {
+ m_configurableProperties = new ConfigurableProperty[] {p};
+ }
+ }
+
+ /**
+ * Check if the liste contains the property.
+ * @param name : name of the property
+ * @return true if the property exist in the list
+ */
+ protected boolean containsProperty(String name) {
+ for (int i = 0; (m_configurableProperties != null) && (i < m_configurableProperties.length); i++) {
+ if (m_configurableProperties[i].getName() == name) { return true; }
+ }
+ return false;
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
new file mode 100644
index 0000000..f617633
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
@@ -0,0 +1,498 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.dependency;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.logging.Level;
+
+import org.apache.felix.ipojo.Activator;
+import org.apache.felix.ipojo.ComponentManager;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represent a service dependency either for a componenet dependency either for
+ * a provided service dependency. Date : 3 déc. 2005
+ * @author clément
+ */
+public class Dependency implements ServiceListener {
+
+ /**
+ * Dependency State : RESOLVED.
+ */
+ public static final int RESOLVED = 1;
+
+ /**
+ * Dependency State : UNRESOLVED.
+ */
+ public static final int UNRESOLVED = 2;
+
+ /**
+ * Link to the Component Manager.
+ * m_handler : ComponentManager
+ */
+ private DependencyHandler m_handler;
+
+
+ /**
+ * Metadata of the dependency.
+ * m_metadata : dependency metadata
+ */
+ private DependencyMetadata m_metadata;
+
+ /**
+ * Array of Service Objects.
+ * When cardinality = 1 : just the first element is returned
+ * When cardinality = ?..n : all the array is returned
+ * m_services : Array
+ */
+ private Object[] m_services = new Object[0];
+
+ /**
+ * Array of service references.
+ * m_ref : Array
+ */
+ private ServiceReference[] m_ref = new ServiceReference[0];
+
+ /**
+ * State of the dependency.
+ * 0 : stopped, 1 : valid, 2 : invalid.
+ * m_state : int
+ */
+ private int m_state;
+
+ /**
+ * True if the reference list change after the creation of a service object array.
+ */
+ private boolean m_change;
+
+ /**
+ * Class of the dependency.
+ * Usefull to create in the case of multiple dependency
+ */
+ private Class m_clazz;
+
+
+ /**
+ * Dependency contructor. After the creation the dependency is not started.
+ * @param dh : the dependency handler managing this dependency
+ * @param dm : the depednency metadata
+ */
+ public Dependency(DependencyHandler dh, DependencyMetadata dm) {
+ m_handler = dh;
+ m_metadata = dm;
+ }
+
+ /**
+ * @return the dependency metadata.
+ */
+ public DependencyMetadata getMetadata() { return m_metadata; }
+
+ /**
+ * @return the dependency handler of this dependency.
+ */
+ public DependencyHandler getDependencyHandler() { return m_handler; }
+
+ /**
+ * @return the used service.
+ */
+ public HashMap getUsedServices() {
+ HashMap hm = new HashMap();
+ if (m_metadata.isMultiple()) {
+ for (int i = 0; i < m_ref.length; i++) {
+ if (i < m_services.length) { hm.put(((Object)m_services[i]).toString(), m_ref[i]); }
+ }
+ } else {
+ if (m_ref.length != 0 && m_services.length != 0) { hm.put(((Object)m_services[0]).toString(), m_ref[0]); }
+ }
+ return hm;
+ }
+
+ /**
+ * A dependency is satisfied if it is optional of ref.length != 0.
+ * @return true is the dependency is satified
+ */
+ protected boolean isSatisfied() {
+ return m_metadata.isOptional() || m_ref.length != 0;
+ }
+
+ /**
+ * This method is called by the replaced code in the component implementation class.
+ * Construct the service object list is necessary.
+ * @return null or a service object or a list of service object according to the dependency.
+ */
+ protected Object get() {
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Call get for a dependency on : " + m_metadata.getServiceSpecification()
+ + " Multiple : " + m_metadata.isMultiple() + " Optional : " + m_metadata.isOptional());
+ try {
+
+ // 1 : Test if there is any change in the reference list :
+ if (!m_change) {
+ if (!m_metadata.isMultiple()) {
+ if (m_services.length > 0) {
+ return m_services[0]; }
+ }
+ else {
+ return m_services;
+ }
+ }
+
+ // 2 : Else there is a change in the list -> recompute the m_services array
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Create a service array of " + m_clazz.getName());
+ m_services = (Object[])Array.newInstance(m_clazz, m_ref.length);
+
+ for (int i = 0; i < m_ref.length; i++) {
+ m_services[i] = m_handler.getComponentManager().getContext().getService(m_ref[i]);
+ }
+
+ m_change = false;
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Create an array with the size " + m_services.length);
+
+
+ // 3 : The service object list is populated, I return either the first service object, either the array.
+ // Return null or an empty array if no service are found.
+ if (!m_metadata.isMultiple()) {
+ if (m_services.length > 0) {
+ return m_services[0];
+ } else {
+ // Load the nullable class
+ String[] segment = m_metadata.getServiceSpecification().split("[.]");
+ String className = "org.apache.felix.ipojo." + segment[segment.length - 1] + "Nullable";
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Try to load the nullable class for " + getMetadata().getServiceSpecification() + " -> " + className);
+ Class nullableClazz = m_handler.getNullableClass(className);
+
+ if (nullableClazz == null) {
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Cannot load the nullable class to return a dependency object for " + m_metadata.getField() + " -> " + m_metadata.getServiceSpecification());
+ return null;
+ }
+
+ // The nullable class is loaded, create the object and return it
+ Object instance = nullableClazz.newInstance();
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Nullable object created for " + getMetadata().getServiceSpecification() + " -> " + instance);
+ return instance;
+ }
+ }
+ else { // Multiple dependency
+ return m_services;
+ }
+ } catch (Exception e) {
+ // There is a problem in the dependency resolving (like in stopping method)
+ if (!m_metadata.isMultiple()) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Return null, an exception was throwed in the get method -> " + e.getMessage());
+ return null; }
+ else {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Return an empty array, an exception was throwed in the get method" + e.getMessage());
+ return Array.newInstance(m_clazz, 0); }
+ }
+ }
+
+ /**
+ * Method calld when a service event is throwed.
+ * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+ * @param event : the received service event
+ */
+ public void serviceChanged(ServiceEvent event) {
+ synchronized (this) {
+
+ // If a service goes way.
+ if (event.getType() == ServiceEvent.UNREGISTERING) {
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] A service is gone -> " + event.getServiceReference().getBundle());
+ if (containsSR(event.getServiceReference())) {
+ // Call unbind method
+ callUnbindMethod(event.getServiceReference());
+ // Unget the service reference
+ m_handler.getComponentManager().getContext().ungetService(event.getServiceReference());
+ int index = removeReference(event.getServiceReference());
+
+ // Is the state valid or invalid
+ if (m_ref.length == 0 && !m_metadata.isOptional()) {
+ m_state = UNRESOLVED;
+ }
+ if (m_ref.length == 0 && m_metadata.isOptional()) {
+ m_state = RESOLVED;
+ }
+ // Is there any change ?
+ if (!m_metadata.isMultiple() && index == 0) { m_change = true; }
+ if (!m_metadata.isMultiple() && index != 0) { m_change = false; }
+ if (m_metadata.isMultiple()) { m_change = true; }
+ }
+ m_handler.checkContext();
+ return;
+ }
+
+ // If a service arrives
+ if (event.getType() == ServiceEvent.REGISTERED) {
+ // Add the new service inside the ref list
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Add a service for a dependency");
+ addReference(event.getServiceReference());
+ if (isSatisfied()) {
+ m_state = RESOLVED;
+ if (m_metadata.isMultiple() || m_ref.length == 1) { m_change = true; }
+ callBindMethod(event.getServiceReference());
+ }
+ m_handler.checkContext();
+ }
+
+ }
+ }
+
+ private void callUnbindMethod(ServiceReference ref) {
+ if (m_handler.getComponentManager().getState() == ComponentManager.VALID && m_metadata.isMultiple()) {
+ for (int i = 0; i < m_metadata.getCallbacks().length; i++) {
+ if (m_metadata.getCallbacks()[i].getMethodType() == DependencyCallback.UNBIND) {
+ // Try to call the bind method with a service reference inside
+ try {
+ m_metadata.getCallbacks()[i].call(new Object[] {ref});
+ } catch (NoSuchMethodException e) {
+ // The method was not found : try without service reference
+ try {
+ m_metadata.getCallbacks()[i].call();
+ } catch (NoSuchMethodException e1) {
+ // The method was not found : try with the service object
+ try {
+ m_metadata.getCallbacks()[i].call(new Object[] {m_handler.getComponentManager().getContext().getService(ref)});
+ } catch (NoSuchMethodException e2) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Unbind method not found : " + e1.getMessage());
+ return;
+ } catch (IllegalAccessException e2) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Illegal access on unbind method : " + e2.getMessage());
+ return;
+ } catch (InvocationTargetException e2) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Invocation Target Exception in the unbind method " + e2.getMessage());
+ return;
+ }
+ } catch (IllegalAccessException e1) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Illegal access on unbind method : " + e1.getMessage());
+ return;
+ } catch (InvocationTargetException e1) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Invocation Target Exception in the unbind method " + e1.getMessage());
+ return;
+ }
+
+ } catch (IllegalAccessException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Illegal access on bind method : " + e.getMessage());
+ return;
+ } catch (InvocationTargetException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Invocation Target Exception in the bind method " + e.getMessage());
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private void callBindMethod(ServiceReference ref) {
+ // call bind method :
+ if (m_handler.getComponentManager().getState() == ComponentManager.VALID && m_metadata.isMultiple()) {
+ for (int i = 0; i < m_metadata.getCallbacks().length; i++) {
+ if (m_metadata.getCallbacks()[i].getMethodType() == DependencyCallback.BIND) {
+ // Try to call the bind method with a service reference inside
+ try {
+ m_metadata.getCallbacks()[i].call(new Object[] {ref});
+ } catch (NoSuchMethodException e) {
+ // The method was not found : try without service reference
+ try {
+ m_metadata.getCallbacks()[i].call();
+ } catch (NoSuchMethodException e1) {
+ // The method was not found : try with the service object
+ try {
+ m_metadata.getCallbacks()[i].call(new Object[] {m_handler.getComponentManager().getContext().getService(ref)});
+ } catch (NoSuchMethodException e2) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Bind method not found : " + e1.getMessage());
+ return;
+ } catch (IllegalAccessException e2) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Illegal access on bind method : " + e2.getMessage());
+ return;
+ } catch (InvocationTargetException e2) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Invocation Target Exception in the bind method " + e2.getMessage());
+ return;
+ }
+ } catch (IllegalAccessException e1) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Illegal access on bind method : " + e1.getMessage());
+ return;
+ } catch (InvocationTargetException e1) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Invocation Target Exception in the bind method " + e1.getMessage());
+ return;
+ }
+
+ } catch (IllegalAccessException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Illegal access on bind method : " + e.getMessage());
+ return;
+ } catch (InvocationTargetException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Dependency Callback Error : Invocation Target Exception in the bind method " + e.getMessage());
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Start the dependency.
+ */
+ public void start() {
+ // Construct the filter with the objectclass + filter
+ String classnamefilter = "(objectClass=" + m_metadata.getServiceSpecification() + ")";
+ String filter = "";
+ if (!m_metadata.getFilter().equals("")) {
+ filter = "(&" + classnamefilter + m_metadata.getFilter() + ")";
+ }
+ else {
+ filter = classnamefilter;
+ }
+
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Start a dependency on : " + m_metadata.getServiceSpecification() + " with " + m_metadata.getFilter());
+ m_state = UNRESOLVED;
+
+ try {
+ m_clazz = m_handler.getComponentManager().getContext().getBundle().loadClass(m_metadata.getServiceSpecification());
+ } catch (ClassNotFoundException e) {
+ System.err.println("Cannot load the interface class for the dependency " + m_metadata.getField() + " [" + m_metadata.getServiceSpecification() + "]");
+ e.printStackTrace();
+ }
+
+ try {
+ // Look if the service is already present :
+ ServiceReference[] sr = m_handler.getComponentManager().getContext().getServiceReferences(
+ m_metadata.getServiceSpecification(), filter);
+ if (sr != null) {
+ for (int i = 0; i < sr.length; i++) { addReference(sr[i]); }
+ m_state = RESOLVED;
+ }
+ // Register a listener :
+ m_handler.getComponentManager().getContext().addServiceListener(this, filter);
+ m_change = true;
+ }
+ catch (InvalidSyntaxException e1) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] A filter is malformed : " + filter);
+ e1.printStackTrace();
+ }
+ }
+
+ /**
+ * Stop the dependency.
+ */
+ public void stop() {
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Stop a dependency on : " + m_metadata.getServiceSpecification() + " with " + m_metadata.getFilter());
+ m_state = UNRESOLVED;
+
+ // Unget all services references
+ for (int i = 0; i < m_ref.length; i++) {
+ m_handler.getComponentManager().getContext().ungetService(m_ref[i]);
+ }
+
+ m_ref = new ServiceReference[0];
+ m_handler.getComponentManager().getContext().removeServiceListener(this);
+ m_clazz = null;
+ m_services = null;
+ }
+
+ /**
+ * Return the state of the dependency.
+ * @return the state of the dependency (1 : valid, 2 : invalid)
+ */
+ public int getState() {
+ return m_state;
+ }
+
+ /**
+ * Return the list of service reference.
+ * @return the service reference list.
+ */
+ public ServiceReference[] getServiceReferences() {
+ return m_ref;
+ }
+
+ /**
+ * Add a service reference in the current list.
+ * @param r : the new service reference to add
+ */
+ private void addReference(ServiceReference r) {
+ for (int i = 0; (m_ref != null) && (i < m_ref.length); i++) {
+ if (m_ref[i] == r) {
+ return;
+ }
+ }
+
+ if (m_ref != null) {
+ ServiceReference[] newSR = new ServiceReference[m_ref.length + 1];
+ System.arraycopy(m_ref, 0, newSR, 0, m_ref.length);
+ newSR[m_ref.length] = r;
+ m_ref = newSR;
+ }
+ else {
+ m_ref = new ServiceReference[] {r};
+ }
+ }
+
+ /**
+ * Find if a service registration il already registred.
+ * @param sr : the service registration to find.
+ * @return true if the service registration is already in the array
+ */
+ private boolean containsSR(ServiceReference sr) {
+ for (int i = 0; i < m_ref.length; i++) {
+ if (m_ref[i] == sr) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Remove a service reference in the current list.
+ * @param r : the new service reference to remove
+ * @return the index of the founded element, or -1 if the element is not found
+ */
+ private int removeReference(ServiceReference r) {
+ if (m_ref == null) {
+ m_ref = new ServiceReference[0];
+ }
+
+ int idx = -1;
+ for (int i = 0; i < m_ref.length; i++) {
+ if (m_ref[i] == r) {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx >= 0) {
+ // If this is the module, then point to empty list.
+ if ((m_ref.length - 1) == 0) {
+ m_ref = new ServiceReference[0];
+ }
+ // Otherwise, we need to do some array copying.
+ else {
+ ServiceReference[] newSR = new ServiceReference[m_ref.length - 1];
+ System.arraycopy(m_ref, 0, newSR, 0, idx);
+ if (idx < newSR.length) {
+ System.arraycopy(
+ m_ref, idx + 1, newSR, idx, newSR.length - idx);
+ }
+ m_ref = newSR;
+ }
+ }
+ return idx;
+ }
+
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java
new file mode 100644
index 0000000..f185678
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.dependency;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.felix.ipojo.Callback;
+
+
+/**
+ * This class allwos the creation of callback when service dependency arrives or disappear.
+ * @author escoffie
+ *
+ */
+public class DependencyCallback {
+
+ /**
+ * Bind method (called when a service arrives).
+ */
+ public static final int BIND = 0;
+
+ /**
+ * Unbind method (called when a service disappears).
+ */
+ public static final int UNBIND = 1;
+
+ /**
+ * Is the method a bind method or an unbind method ?
+ */
+ private int m_methodType;
+
+ /**
+ * Callback object.
+ */
+ private Callback m_callback;
+
+
+ /**
+ * Constructor.
+ * @param dep : the dependency attached to this depednency callback
+ * @param method : the method to call
+ * @param methodType : is the method to call a bind method or an unbind method
+ * @param isStatic : is the method to call static ?
+ */
+ public DependencyCallback(Dependency dep, String method, int methodType, boolean isStatic) {
+ m_methodType = methodType;
+ m_callback = new Callback(method, isStatic, dep.getDependencyHandler().getComponentManager());
+ }
+
+ /**
+ * @return the method type.
+ */
+ public int getMethodType() { return m_methodType; }
+
+ /**
+ * Call the callback method.
+ * @throws NoSuchMethodException : Method is not found in the class
+ * @throws InvocationTargetException : The method is not static
+ * @throws IllegalAccessException : The method can not be invoked
+ */
+ protected void call() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ m_callback.call();
+ }
+
+ /**
+ * Call the callback method.
+ * @throws NoSuchMethodException : Method is not found in the class
+ * @throws InvocationTargetException : The method is not static
+ * @throws IllegalAccessException : The method can not be invoked
+ */
+ protected void call(Object[] arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ m_callback.call(arg);
+ }
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
new file mode 100644
index 0000000..7f4859c
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.dependency;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.logging.Level;
+
+import org.apache.felix.ipojo.ComponentManager;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.Activator;
+import org.apache.felix.ipojo.handlers.dependency.nullable.NullableObjectWriter;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * The dependency handler manages a list of dependencies.
+ * @author clément
+ */
+public class DependencyHandler implements Handler {
+
+ /**
+ * The component manager using this handler.
+ */
+ private ComponentManager m_componentManager;
+
+ /**
+ * List of depednencies of the component.
+ */
+ private Dependency[] m_dependencies = new Dependency[0];
+
+ /**
+ * List of nullable class for optional dependencies.
+ */
+ private Class[] m_nullableClasses = new Class[0];
+
+ /**
+ * Classloader to use to load nullable classes.
+ */
+ private NullableClassloader m_classloader;
+
+ /**
+ * State of the handler.
+ */
+ private int m_state;
+
+// ===================== Fields getters & setters =====================
+
+ private void addDependency(Dependency dep) {
+ for (int i = 0; (m_dependencies != null) && (i < m_dependencies.length); i++) {
+ if (m_dependencies[i] == dep) {
+ return;
+ }
+ }
+ if (m_dependencies.length > 0) {
+ Dependency[] newDep = new Dependency[m_dependencies.length + 1];
+ System.arraycopy(m_dependencies, 0, newDep, 0, m_dependencies.length);
+ newDep[m_dependencies.length] = dep;
+ m_dependencies = newDep;
+ }
+ else {
+ m_dependencies = new Dependency[] {dep};
+ }
+ }
+
+ private void addNullableClass(Class clazz) {
+ for (int i = 0; (m_nullableClasses != null) && (i < m_nullableClasses.length); i++) {
+ if (m_nullableClasses[i] == clazz) {
+ return;
+ }
+ }
+ if (m_nullableClasses.length > 0) {
+ Class[] newClass = new Class[m_nullableClasses.length + 1];
+ System.arraycopy(m_nullableClasses, 0, newClass, 0, m_nullableClasses.length);
+ newClass[m_nullableClasses.length] = clazz;
+ m_nullableClasses = newClass;
+ }
+ else {
+ m_nullableClasses = new Class[] {clazz};
+ }
+ }
+
+ /**
+ * @return the dependency list
+ */
+ public Dependency[] getDependencies() { return m_dependencies; }
+
+ /**
+ * @return the component manager
+ */
+ protected ComponentManager getComponentManager() { return m_componentManager; }
+
+// ===================== Handler implementation =====================
+
+ /**
+ * Check the validity of the dependencies.
+ */
+ protected void checkContext() {
+
+ synchronized (this) {
+
+ Activator.getLogger().log(Level.INFO, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] Check Context ...");
+
+ // Store the initial state
+ int initialState = m_state;
+
+ // Check the component dependencies
+ if (!validateComponentDependencies()) {
+ // The dependencies are not valid
+ if (initialState == ComponentManager.VALID) {
+ //There is a state change
+ m_state = ComponentManager.INVALID;
+ m_componentManager.check();
+ }
+ // Else do nothing, the component state stay UNRESOLVED
+ }
+ else {
+ // The dependencies are valid
+ if (initialState == ComponentManager.INVALID) {
+ //There is a state change
+ m_state = ComponentManager.VALID;
+ m_componentManager.check();
+ }
+ // Else do nothing, the component state stay VALID
+ }
+
+ }
+ }
+
+ private boolean checkDependency(Dependency dep) {
+ // Check the internal type of dependency
+ String field = dep.getMetadata().getField();
+
+ Element manipulation = m_componentManager.getComponentMetatada().getMetadata().getElements("Manipulation")[0];
+ String type = null;
+ for (int i = 0; i < manipulation.getElements("Field").length; i++) {
+ if (field.equals(manipulation.getElements("Field")[i].getAttribute("name"))) {
+ type = manipulation.getElements("Field")[i].getAttribute("type");
+ break;
+ }
+ }
+
+ if (type == null) {
+ Activator.getLogger().log(Level.SEVERE, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] A declared dependency was not found in the class : " + dep.getMetadata().getField());
+ return false;
+ }
+
+ if (type != null) {
+ if (type.endsWith("[]")) {
+ // Set the dependency to multiple
+ dep.getMetadata().setMultiple();
+ type = type.substring(0, type.length() - 2);
+ }
+
+ if (dep.getMetadata().getServiceSpecification() == null) { dep.getMetadata().setServiceSpecification(type); }
+
+ if (!dep.getMetadata().getServiceSpecification().equals(type)) {
+ Activator.getLogger().log(Level.WARNING, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] The field type [" + type + "] and the needed service interface [" + dep.getMetadata().getServiceSpecification() + "] are not the same");
+ dep.getMetadata().setServiceSpecification(type);
+ }
+ }
+ else {
+ Activator.getLogger().log(Level.WARNING, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] The declared dependency " + dep.getMetadata().getField() + " does not exist in the code");
+ }
+ return true;
+ }
+
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.ComponentManager, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void configure(ComponentManager cm, Element componentMetadata) {
+ // Fix the component manager
+ m_componentManager = cm;
+ m_dependencies = new Dependency[0];
+ m_nullableClasses = new Class[0];
+
+ // Create the dependency according to the component metadata
+ Element[] deps = componentMetadata.getElements("Dependency");
+ for (int i = 0; i < deps.length; i++) {
+ // Create the dependency metadata
+ String field = deps[i].getAttribute("field");
+ String serviceSpecification = null;
+ if (deps[i].containsAttribute("interface")) { serviceSpecification = deps[i].getAttribute("interface"); }
+ String filter = "";
+ if (deps[i].containsAttribute("filter")) { filter = deps[i].getAttribute("filter"); }
+ boolean optional = false;
+ if (deps[i].containsAttribute("optional") && deps[i].getAttribute("optional").equals("true")) { optional = true; }
+ DependencyMetadata dm = new DependencyMetadata(field, serviceSpecification, filter, optional);
+
+
+ Dependency dep = new Dependency(this, dm);
+ // Check the dependency :
+ if (checkDependency(dep)) { addDependency(dep); }
+ else { Activator.getLogger().log(Level.SEVERE, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] The dependency on " + dep.getMetadata().getField() + " is not valid"); }
+
+ // Look for dependency callback :
+ for (int j = 0; j < (deps[i].getElements("Callback", "")).length; j++) {
+ String method = deps[i].getElements("Callback", "")[j].getAttribute("method");
+ String type = deps[i].getElements("Callback", "")[j].getAttribute("type");
+ int methodType = 0;
+ if (type.equals("bind")) { methodType = DependencyCallback.BIND; }
+ else { methodType = DependencyCallback.UNBIND; }
+ boolean isStatic = false;
+ if (deps[i].getElements("Callback", "")[j].containsAttribute("isStatic") && deps[i].getElements("Callback", "")[j].getAttribute("isStatic").equals("true")) { isStatic = true; }
+ DependencyCallback dc = new DependencyCallback(dep, method, methodType, isStatic);
+ dep.getMetadata().addDependencyCallback(dc);
+ }
+ }
+
+ if (deps.length > 0) {
+ m_componentManager.register(this);
+
+ // Create the nullable classloader
+ m_classloader = new NullableClassloader(m_componentManager.getContext().getBundle());
+
+ }
+ }
+
+ private void createNullableClass(Dependency dep) {
+ Activator.getLogger().log(Level.INFO, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] Try to load the nullable class for " + dep.getMetadata().getServiceSpecification());
+ // Try to load the nullable object :
+ String[] segment = dep.getMetadata().getServiceSpecification().split("[.]");
+ String className = "org/apache/felix/ipojo/" + segment[segment.length - 1] + "Nullable";
+
+ String resource = dep.getMetadata().getServiceSpecification().replace('.', '/') + ".class";
+ URL url = m_componentManager.getContext().getBundle().getResource(resource);
+
+ try {
+ byte[] b = NullableObjectWriter.dump(url, dep.getMetadata().getServiceSpecification());
+
+// // DEBUG :
+// try {
+// File file = new File("P:\\workspace\\iPOJO\\adapted\\" + className.replace('/', '.') + ".class");
+// file.createNewFile();
+// FileOutputStream fos = new FileOutputStream(file);
+// fos.write(b);
+// fos.close();
+// } catch (Exception e3) {
+// System.err.println("Problem to write the adapted class on the file system : " + e3.getMessage());
+//
+// }
+
+ addNullableClass(m_classloader.defineClass(className.replace('/', '.'), b, null));
+ Activator.getLogger().log(Level.INFO, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] Nullable class created for " + dep.getMetadata().getServiceSpecification());
+
+ } catch (IOException e1) {
+ Activator.getLogger().log(Level.SEVERE, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] Cannot open a stream of an interface to generate the nullable class for " + dep.getMetadata().getServiceSpecification() + " -> " + e1.getMessage());
+ } catch (Exception e2) {
+ Activator.getLogger().log(Level.SEVERE, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] Cannot load the nullable class for " + dep.getMetadata().getServiceSpecification() + " -> " + e2.getMessage());
+ }
+ }
+
+ /**
+ * Return the nullable class corresponding to the given name.
+ * @param name the needed type
+ * @return the class correspondig to the name, or null if the class does not exist.
+ */
+ protected Class getNullableClass(String name) {
+ for (int i = 0; i < m_nullableClasses.length; i++) {
+ Class c = m_nullableClasses[i];
+ if (c.getName().equals(name)) {
+ return c;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#getterCallback(java.lang.String, java.lang.Object)
+ */
+ public Object getterCallback(String fieldName, Object value) {
+ for (int i = 0; i < m_dependencies.length; i++) {
+ Dependency dep = m_dependencies[i];
+ if (dep.getMetadata().getField().equals(fieldName)) {
+ // The field name is a dependency, return the get
+ return dep.get();
+ }
+ }
+ // Else return the value
+ return value;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#isValid()
+ */
+ public boolean isValid() {
+ return (m_state == ComponentManager.VALID);
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#setterCallback(java.lang.String, java.lang.Object)
+ */
+ public void setterCallback(String fieldName, Object value) {
+ // Do nothing
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ Activator.getLogger().log(Level.INFO, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] Start the dependency handler");
+
+ // Start the dependencies, for optional dependencies create Nullable class
+ for (int i = 0; i < m_dependencies.length; i++) {
+ Dependency dep = m_dependencies[i];
+ if (dep.getMetadata().isOptional() && !dep.getMetadata().isMultiple()) { createNullableClass(dep); }
+ dep.start();
+ }
+ // Check the state
+ m_state = m_componentManager.getState();
+ checkContext();
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ // Another handler or the component manager itself change the state
+ if (m_state == ComponentManager.VALID && state == ComponentManager.INVALID) {
+ // The component is stopped => Stop the dependency tracking
+ stop();
+ }
+ m_state = state;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_dependencies.length; i++) { m_dependencies[i].stop(); }
+ }
+
+ private boolean validateComponentDependencies() {
+ boolean valide = true;
+ for (int i = 0; i < m_dependencies.length; i++) {
+ Dependency dep = m_dependencies[i];
+ valide = valide & dep.isSatisfied();
+ if (!valide) {
+ Activator.getLogger().log(Level.INFO, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] Component Dependencies are not valid : " + dep.getMetadata().getServiceSpecification());
+ return false;
+ }
+ }
+ Activator.getLogger().log(Level.INFO, "[DependencyHandler on " + m_componentManager.getComponentMetatada().getClassName() + "] Component Dependencies are valid");
+ return valide;
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyMetadata.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyMetadata.java
new file mode 100644
index 0000000..38c6595
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyMetadata.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.dependency;
+
+/**
+ * Dependency Metadata.
+ * @author Clement Escoffier
+ */
+public class DependencyMetadata {
+
+ /**
+ * Service Specification <=> Service contract (or interface in OSGi).
+ */
+ private String m_serviceSpecification;
+
+ /**
+ * LDAP filter.
+ */
+ private String m_filter;
+
+ /**
+ * is the dependency optional ?
+ */
+ private boolean m_isOptional;
+
+ /**
+ * is the dependency multiple ?
+ */
+ private boolean m_isMultiple = false;
+
+ /**
+ * List of dependency callbacks attached to this dependency.
+ */
+ private DependencyCallback[] m_callbacks = new DependencyCallback[0];
+
+ /**
+ * The field linking the metadata and the component implementation.
+ */
+ private String m_field;
+
+ // Constructor
+
+ /**
+ * Constructor.
+ * @param field : the field name
+ * @param service : the interface name.
+ * @param filter : the filter of the dependency
+ * @param isOptional : is the dependency optional
+ */
+ public DependencyMetadata(String field, String service, String filter, boolean isOptional) {
+ m_field = field;
+ m_serviceSpecification = service;
+ m_isOptional = isOptional;
+ m_filter = filter;
+ }
+
+ /**
+ * Add a callback to the dependency.
+ * @param cb : callback to add
+ */
+ public void addDependencyCallback(DependencyCallback cb) {
+ for (int i = 0; (m_callbacks != null) && (i < m_callbacks.length); i++) {
+ if (m_callbacks[i] == cb) { return; }
+ }
+
+ if (m_callbacks.length > 0) {
+ DependencyCallback[] newCallbacks = new DependencyCallback[m_callbacks.length + 1];
+ System.arraycopy(m_callbacks, 0, newCallbacks, 0, m_callbacks.length);
+ newCallbacks[m_callbacks.length] = cb;
+ m_callbacks = newCallbacks;
+ }
+ else {
+ m_callbacks = new DependencyCallback[] {cb};
+ }
+ }
+
+ // Getter
+
+ /**
+ * @return Returns the m_field.
+ */
+ public String getField() {
+ return m_field;
+ }
+
+ /**
+ * @return Returns the m_filter.
+ */
+ public String getFilter() {
+ return m_filter;
+ }
+
+ /**
+ * @return Returns the m_isMultiple.
+ */
+ public boolean isMultiple() {
+ return m_isMultiple;
+ }
+
+ /**
+ * @return Returns the m_isOptional.
+ */
+ public boolean isOptional() {
+ return m_isOptional;
+ }
+
+ /**
+ * @return Returns the m_serviceSpecification.
+ */
+ public String getServiceSpecification() {
+ return m_serviceSpecification;
+ }
+
+ /**
+ * return true if the dependency is multiple.
+ */
+ public void setMultiple() {
+ m_isMultiple = true;
+ }
+
+ /**
+ * Set the service specification.
+ * @param serviceSpecification : the dependency service specification
+ */
+ public void setServiceSpecification(String serviceSpecification) {
+ m_serviceSpecification = serviceSpecification;
+ }
+
+ /**
+ * @return the list of the callbacks
+ */
+ public DependencyCallback[] getCallbacks() { return m_callbacks; }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableClassloader.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableClassloader.java
new file mode 100644
index 0000000..b490fdf
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/NullableClassloader.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.dependency;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.ProtectionDomain;
+import java.util.Enumeration;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * iPOJO Classloader.
+ * This classloadert is used to load manipulated class.
+ * @author Clement Escoffier
+ */
+public class NullableClassloader extends ClassLoader {
+
+ /**
+ * The owner bundle.
+ * m_bundle : Bundle
+ */
+ private Bundle m_bundle;
+
+ /**
+ * Constructor.
+ * @param b : the owner bundle
+ */
+ public NullableClassloader(Bundle b) {
+ m_bundle = b;
+ }
+
+ /**
+ * load the class.
+ * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
+ * @param name : the name of the class
+ * @param resolve : should be the class resolve now ?
+ * @return : the loaded class
+ * @throws ClassNotFoundException : the class to load is not found
+ */
+ protected synchronized Class loadClass(final String name,
+ final boolean resolve) throws ClassNotFoundException {
+
+ Class clazz = null;
+ //Activator.getLogger().log(Level.WARNING, "Bundle " + m_bundle.getBundleId() + " -> Try to load : " + name);
+
+ if (m_bundle != null) { clazz = m_bundle.loadClass(name); }
+
+ return clazz;
+ }
+
+
+ /**
+ * Return the URL of the asked ressource.
+ * @param arg : the name of the resource to find.
+ * @return the URL of the resource.
+ * @see java.lang.ClassLoader#getResource(java.lang.String)
+ */
+ public URL getResource(String arg) {
+ return m_bundle.getResource(arg);
+ }
+
+ /**
+ * .
+ * @param arg : resource to find
+ * @return : the enumeration found
+ * @throws IOException : if the lookup failed.
+ * @see java.lang.ClassLoader#getResources(java.lang.String)
+ */
+ public Enumeration getRessources(String arg) throws IOException {
+ return m_bundle.getResources(arg);
+ }
+
+ /**
+ * The defineClass method for GenClassLoader.
+ * @param name : name of the class
+ * @param b : the byte array of the class
+ * @param domain : the protection domain
+ * @return : the defined class.
+ * @throws Exception : if a problem is detected during the loading
+ */
+ public Class defineClass(String name, byte[] b,
+ ProtectionDomain domain) throws Exception {
+ Class clazz = super.defineClass(name, b, 0, b.length, domain);
+ return clazz;
+ }
+
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/nullable/MethodSignature.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/nullable/MethodSignature.java
new file mode 100644
index 0000000..ff49abd
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/nullable/MethodSignature.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.dependency.nullable;
+
+/**
+ * Reprensent of method description.
+ * The goal of this class, is to be able to generate a proxy class, or a nullable class from an interface.
+ * @author Clement Escoffier
+ *
+ */
+public class MethodSignature {
+
+ /**
+ * Nmae of the method.
+ */
+ private String m_name;
+
+ /**
+ * Descriptor of the method.
+ */
+ private String m_desc;
+
+ /**
+ * Signature of the method.
+ */
+ private String m_signature;
+
+ /**
+ * Exception thored by the method.
+ */
+ private String[] m_exception;
+
+ /**
+ * MethodSignature constructor.
+ * Describe a method.
+ * @param name : name of the method
+ * @param desc : descriptor of the method
+ * @param sign : signature of the method
+ * @param exc : exception throwed by the method
+ */
+ public MethodSignature(String name, String desc, String sign, String[] exc) {
+ m_name = name;
+ m_desc = desc;
+ m_signature = sign;
+ m_exception = exc;
+ }
+
+ /**
+ * @return the description of the method.
+ */
+ public String getDesc() {
+ return m_desc;
+ }
+
+ /**
+ * @return the String array of exception throwed by the method.
+ */
+ public String[] getException() {
+ return m_exception;
+ }
+
+ /**
+ * @return the name of the method.
+ */
+ public String getName() {
+ return m_name;
+ }
+
+ /**
+ * @return the signature of the method.
+ */
+ public String getSignature() {
+ return m_signature;
+ }
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/nullable/MethodSignatureVisitor.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/nullable/MethodSignatureVisitor.java
new file mode 100644
index 0000000..d1b341e
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/nullable/MethodSignatureVisitor.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.dependency.nullable;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/** This class implement a class visitor. It store all method signature of
+ * the visited interface. Then it returns these class signatures for the proxy
+ * generation or the nullable class.
+ * Date : 4/9/2005
+ * @author Clement Escoffier
+ */
+public class MethodSignatureVisitor implements ClassVisitor, Opcodes {
+
+ /**
+ * Array of method signature.
+ */
+ private MethodSignature[] m_methods;
+
+
+ /**
+ * Constructor.
+ */
+ public MethodSignatureVisitor() { }
+
+ /**
+ * Visit a method, store the information about the method.
+ * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
+ * @param access : Access modifier
+ * @param name : name of the visited method
+ * @param signature : singature of the visited element (null if not generic)
+ * @param desc : descriptor of the method
+ * @param exceptions : execption clause
+ * @return always null (not code visitor needed)
+ */
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ //Store method signature for each visited method
+ m_methods = addMethod(m_methods, new MethodSignature(name, desc, signature, exceptions));
+ return null;
+ }
+
+ /**
+ * @return the mthod signature array.
+ */
+ public MethodSignature[] getMethods() {
+ return m_methods;
+ }
+
+ /**
+ * Return the new array of Method Signature by adding the given list and the given element.
+ * @param list : the current array
+ * @param method : the element to add
+ * @return the new array
+ */
+ public static MethodSignature[] addMethod(MethodSignature[] list, MethodSignature method) {
+ if (list != null) {
+ MethodSignature[] newList = new MethodSignature[list.length + 1];
+ System.arraycopy(list, 0, newList, 0, list.length);
+ newList[list.length] = method;
+ return newList;
+ }
+ else {
+ list = new MethodSignature[] {method};
+ return list;
+ }
+
+ }
+
+ /**
+ * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
+ */
+ public void visit(int arg0, int arg1, String arg2, String arg3, String arg4, String[] arg5) { }
+
+ /**
+ * @see org.objectweb.asm.ClassVisitor#visitSource(java.lang.String, java.lang.String)
+ */
+ public void visitSource(String arg0, String arg1) { }
+
+ /**
+ * @see org.objectweb.asm.ClassVisitor#visitOuterClass(java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void visitOuterClass(String arg0, String arg1, String arg2) { }
+
+ /**
+ * @see org.objectweb.asm.ClassVisitor#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) { return null; }
+
+ /**
+ * @see org.objectweb.asm.ClassVisitor#visitAttribute(org.objectweb.asm.Attribute)
+ */
+ public void visitAttribute(Attribute arg0) { }
+
+ /**
+ * @see org.objectweb.asm.ClassVisitor#visitInnerClass(java.lang.String, java.lang.String, java.lang.String, int)
+ */
+ public void visitInnerClass(String arg0, String arg1, String arg2, int arg3) { }
+
+ /**
+ * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
+ */
+ public FieldVisitor visitField(int arg0, String arg1, String arg2, String arg3, Object arg4) { return null; }
+
+ /**
+ * @see org.objectweb.asm.ClassVisitor#visitEnd()
+ */
+ public void visitEnd() { }
+
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/nullable/NullableObjectWriter.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/nullable/NullableObjectWriter.java
new file mode 100644
index 0000000..1eb0edf
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/dependency/nullable/NullableObjectWriter.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.dependency.nullable;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/** Create the proxy class.
+ * @author clément
+ */
+public class NullableObjectWriter implements Opcodes {
+
+ /** Return the proxy classname for the contract contractname
+ * on the service object soc.
+ * @param url URL of the needed contract
+ * @param contractName String
+ * @return byte[]
+ */
+ public static byte[] dump(URL url,
+ String contractName) {
+
+ ClassReader cr = null;
+ InputStream is = null;
+ byte[] b = null;
+ try {
+ is = url.openStream();
+ cr = new ClassReader(is);
+ MethodSignatureVisitor msv = new MethodSignatureVisitor();
+ cr.accept(msv, true);
+ is.close();
+
+ ClassWriter cw = new ClassWriter(true);
+
+ String[] segment = contractName.split("[.]");
+ String className = "org/apache/felix/ipojo/" + segment[segment.length - 1] + "Nullable";
+
+
+ // Create the class
+ cw.visit(V1_2, ACC_PUBLIC + ACC_SUPER, className, null,
+ "java/lang/Object", new String[]{contractName.replace('.', '/'), "org/apache/felix/ipojo/Nullable"});
+
+ // Inject a constructor <INIT>()V
+ MethodVisitor cst = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ cst.visitVarInsn(ALOAD, 0);
+ cst.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+ cst.visitInsn(RETURN);
+ cst.visitMaxs(0, 0);
+ cst.visitEnd();
+
+ // Methods Generation :
+ MethodSignature[] methods = msv.getMethods();
+
+ for (int i = 0; i < methods.length; ++i) {
+ MethodSignature method = methods[i];
+ String desc = method.getDesc();
+ String name = method.getName();
+ String sign = method.getSignature();
+ String[] exc = method.getException();
+
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, desc, sign, exc);
+
+ Type returnType = Type.getReturnType(desc);
+ // TODO : manage the other type primitive
+ // Primitive type :
+ switch (returnType.getSort()) {
+ case Type.BOOLEAN:
+ case Type.INT:
+ // Integer or Boolean : return 0 ( false)
+ mv.visitInsn(ICONST_0);
+ mv.visitInsn(IRETURN);
+ break;
+ case Type.DOUBLE:
+ // Double : return 0.0
+ mv.visitInsn(DCONST_0);
+ mv.visitInsn(DRETURN);
+ break;
+ case Type.ARRAY :
+ case Type.OBJECT :
+ // Return always null for array and object
+ mv.visitInsn(ACONST_NULL);
+ mv.visitInsn(ARETURN);
+ break;
+ case Type.VOID :
+ mv.visitInsn(RETURN);
+ break;
+ default :
+ System.err.println("Type not yet managed : " + returnType);
+ }
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ // End process
+ cw.visitEnd();
+ b = cw.toByteArray();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return b;
+ }
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallback.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallback.java
new file mode 100644
index 0000000..1bc4899
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallback.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.lifecycle.callback;
+
+import java.lang.reflect.InvocationTargetException;
+import org.apache.felix.ipojo.Callback;
+
+/**
+ * This class is the implementation of callback on lifecycle transition.
+ * @author Clement Escoffier
+ *
+ */
+public class LifecycleCallback {
+
+
+ /**
+ * Metadata of the callback.
+ */
+ private LifecycleCallbackMetadata m_metadata;
+
+ /**
+ * Callback object.
+ */
+ private Callback m_callback;
+
+ /**
+ * LifecycleCallback constructor.
+ * @param hh : the callback handler calling the callback
+ * @param hm : the callback metadata
+ */
+ public LifecycleCallback(LifecycleCallbackHandler hh, LifecycleCallbackMetadata hm) {
+ m_metadata = hm;
+ m_callback = new Callback(hm.getMethod(), hm.isStatic(), hh.getComponentManager());
+ }
+
+ /**
+ * @return : the metadata of the hook
+ */
+ public LifecycleCallbackMetadata getMetadata() {
+ return m_metadata;
+ }
+
+ /**
+ * Call the hook method when the transition from inital to final state is detected.
+ * @throws NoSuchMethodException : Method is not found in the class
+ * @throws InvocationTargetException : The method is not static
+ * @throws IllegalAccessException : The method can not be invoked
+ */
+ protected void call() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ m_callback.call();
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java
new file mode 100644
index 0000000..f20d3f6
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.lifecycle.callback;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.logging.Level;
+
+import org.apache.felix.ipojo.ComponentManager;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.Activator;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Lifecycle callback handler.
+ * @author Clement Escoffier
+ */
+public class LifecycleCallbackHandler implements Handler {
+
+ /**
+ * The list of the callback of the component.
+ */
+ private LifecycleCallback[] m_callbacks = new LifecycleCallback[0];
+
+ /**
+ * State of the component manager (unresolved at the beginning).
+ */
+ private int m_state = ComponentManager.INVALID;
+
+ /**
+ * The component manager.
+ */
+ private ComponentManager m_componentManager;
+
+ /**
+ * Add the given Hook to the hook list.
+ * @param hk : the element to add
+ */
+ private void addCallback(LifecycleCallback hk) {
+ for (int i = 0; (m_callbacks != null) && (i < m_callbacks.length); i++) {
+ if (m_callbacks[i] == hk) { return; }
+ }
+
+ if (m_callbacks.length > 0) {
+ LifecycleCallback[] newHk = new LifecycleCallback[m_callbacks.length + 1];
+ System.arraycopy(m_callbacks, 0, newHk, 0, m_callbacks.length);
+ newHk[m_callbacks.length] = hk;
+ m_callbacks = newHk;
+ }
+ else {
+ m_callbacks = new LifecycleCallback[] {hk};
+ }
+
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.ComponentManager, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void configure(ComponentManager cm, Element metadata) {
+ m_componentManager = cm;
+ m_callbacks = new LifecycleCallback[0];
+
+ Element[] hooksMetadata = metadata.getElements("callback");
+ for (int i = 0; i < hooksMetadata.length; i++) {
+ // Create an HookMetadata object
+ String initialState = hooksMetadata[i].getAttribute("initial");
+ String finalState = hooksMetadata[i].getAttribute("final");
+ String method = hooksMetadata[i].getAttribute("method");
+ boolean isStatic = false;
+ if (hooksMetadata[i].containsAttribute("isStatic") && hooksMetadata[i].getAttribute("isStatic").equals("true")) { isStatic = true; }
+
+ LifecycleCallbackMetadata hm = new LifecycleCallbackMetadata(initialState, finalState, method, isStatic);
+
+ LifecycleCallback hk = new LifecycleCallback(this, hm);
+ addCallback(hk);
+ }
+ if (m_callbacks.length > 0) { m_componentManager.register(this); }
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ m_state = ComponentManager.INVALID;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ Activator.getLogger().log(Level.INFO, "[" + m_componentManager.getComponentMetatada().getClassName() + "] Start the life cycle callback handler");
+ }
+
+ /**
+ * Do nothing.
+ * @see org.apache.felix.ipojo.Handler#setterCallback(java.lang.String, java.lang.Object)
+ */
+ public void setterCallback(String fieldName, Object value) {
+ // Do nothing
+ }
+
+ /**
+ * Do nothing, return the initial value.
+ * @see org.apache.felix.ipojo.Handler#getterCallback(java.lang.String, java.lang.Object)
+ */
+ public Object getterCallback(String fieldName, Object value) {
+ return value;
+ }
+
+ /**
+ * Return true.
+ * @see org.apache.felix.ipojo.Handler#isValid()
+ */
+ public boolean isValid() {
+ return true;
+ }
+
+ /**
+ * @return the component manager
+ */
+ protected ComponentManager getComponentManager() { return m_componentManager; }
+
+ /**
+ * When the state change call the associated hooks.
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ Activator.getLogger().log(Level.INFO, "[" + m_componentManager.getComponentMetatada().getClassName() + "] State changed in callback handler, check " + m_callbacks.length + " callbacks. Transition : " + m_state + " -> " + state);
+ for (int i = 0; i < m_callbacks.length; i++) {
+ if (m_callbacks[i].getMetadata().getInitialState() == m_state && m_callbacks[i].getMetadata().getFinalState() == state) {
+ try {
+ Activator.getLogger().log(Level.INFO, "[" + m_componentManager.getComponentMetatada().getClassName() + "] Call the callback : " + m_callbacks[i].getMetadata().getMethod());
+ m_callbacks[i].call();
+ } catch (NoSuchMethodException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_componentManager.getComponentMetatada().getClassName() + "] The callback method " + m_callbacks[i].getMetadata().getMethod() + " is not found : " + e.getMessage());
+ } catch (IllegalAccessException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_componentManager.getComponentMetatada().getClassName() + "] The callback method " + m_callbacks[i].getMetadata().getMethod() + " is not accessible : " + e.getMessage());
+ } catch (InvocationTargetException e) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_componentManager.getComponentMetatada().getClassName() + "] The callback method " + m_callbacks[i].getMetadata().getMethod() + " has throws an exception : " + e.getMessage() + " -> " + e.getCause());
+ }
+ }
+ }
+ // Update to internal state
+ m_state = state;
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackMetadata.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackMetadata.java
new file mode 100644
index 0000000..cc032a0
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackMetadata.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.lifecycle.callback;
+
+import org.apache.felix.ipojo.ComponentManager;
+
+/**
+ * Lifecycle callback metadata.
+ * @author Clement Escoffier
+ */
+public class LifecycleCallbackMetadata {
+
+ /**
+ * Initial state of the transition.
+ */
+ private int m_initialState;
+
+ /**
+ * Final state of the transition.
+ */
+ private int m_finalState;
+
+ /**
+ * Method to call.
+ */
+ private String m_method;
+
+ /**
+ * is the method a static method ?
+ */
+ private boolean m_isStatic;
+
+ // Constructor
+
+ /**
+ * Constructor.
+ * @param initialState : initial state
+ * @param finalState : final state
+ * @param method : method name
+ * @param isStatic : is the method a static method ?
+ */
+ public LifecycleCallbackMetadata(String initialState, String finalState, String method, boolean isStatic) {
+ if (initialState.equals("VALID")) { m_initialState = ComponentManager.VALID; }
+ if (initialState.equals("INVALID")) { m_initialState = ComponentManager.INVALID; }
+ if (finalState.equals("VALID")) { m_finalState = ComponentManager.VALID; }
+ if (finalState.equals("INVALID")) { m_finalState = ComponentManager.INVALID; }
+
+ m_method = method;
+ m_isStatic = isStatic;
+ }
+
+ // Getters
+
+ /**
+ * @return Returns the m_finalState.
+ */
+ public int getFinalState() {
+ return m_finalState;
+ }
+
+ /**
+ * @return Returns the m_initialState.
+ */
+ public int getInitialState() {
+ return m_initialState;
+ }
+
+ /**
+ * @return Returns the m_isStatic.
+ */
+ public boolean isStatic() {
+ return m_isStatic;
+ }
+
+ /**
+ * @return Returns the m_method.
+ */
+ public String getMethod() {
+ return m_method;
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/Property.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/Property.java
new file mode 100644
index 0000000..c1dfe05
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/Property.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.providedService;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.logging.Level;
+
+import org.apache.felix.ipojo.Activator;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Represent a property i.e. a set : [name, type, value].
+ * A property can be attached to a field.
+ * The value of the property is thefield value.
+ * When the value change, the published value change too.
+ * Date : 5 févr. 2006
+ * @author clément
+ */
+public class Property {
+
+ /**
+ * A property is link with a service.
+ * This field represent this provided service.
+ * m_providedService : ProvidedService
+ */
+ private ProvidedService m_providedService;
+
+ /**
+ * Value of the property (before we know the type).
+ */
+ private Object m_value;
+
+ /**
+ * Metadata of the property.
+ */
+ private PropertyMetadata m_metadata;
+
+ /**
+ * Property constructor.
+ * @param ps : the provided service
+ * @param pm : metadata of the property
+ */
+ public Property(ProvidedService ps, PropertyMetadata pm) {
+ m_providedService = ps;
+ m_metadata = pm;
+
+ // Fix the type of the property if null
+ if (pm.getType() == null) {
+ // If the type is not found, it is a dynamic property
+ Element manipulation = m_providedService.getComponentManager().getComponentMetatada().getMetadata().getElements("Manipulation")[0];
+ String type = null;
+ String field = m_metadata.getField();
+ for (int i = 0; i < manipulation.getElements("Field").length; i++) {
+ if (field.equals(manipulation.getElements("Field")[i].getAttribute("name"))) {
+ type = manipulation.getElements("Field")[i].getAttribute("type");
+ break;
+ }
+ }
+
+ pm.setType(type);
+ }
+
+ if (pm.getValue() != null) { setValue(pm.getValue()); }
+ }
+
+ /**
+ * @return the Object value of the property
+ */
+ protected Object get() {
+ if (m_value == null) {
+ Activator.getLogger().log(Level.INFO, "[" + m_providedService.getComponentManager().getComponentMetatada().getClassName() + "] A property " + m_metadata.getName() + " can not be returned : no value assigned");
+ }
+ return m_value;
+ }
+
+
+ /**
+ * @return the property metadata.
+ */
+ public PropertyMetadata getMetadata() {
+ return m_metadata;
+ }
+
+ /**
+ * This method is automaticaly called when the value of the property is changed.
+ * Set the value of a property.
+ * @param s : the new value of the property (in String)
+ */
+ protected void set(String s) {
+ setValue(s);
+ m_providedService.update();
+ }
+
+ /**
+ * This method is called when the value of the property is changed.
+ * Set the value of a property.
+ * @param o : the new value of the property (object)
+ */
+ protected void set(Object o) {
+ m_value = o;
+ m_providedService.update();
+ }
+
+ /**
+ * Set the provided service of this property.
+ * @param ps : the provided service to attached.
+ */
+ void setProvidedService(ProvidedService ps) {
+ m_providedService = ps;
+ }
+
+ /**
+ * Set the value of the property.
+ * @param value : value of the property (String)
+ */
+ private void setValue(String value) {
+ String type = m_metadata.getType();
+
+ Activator.getLogger().log(Level.INFO, "[" + m_providedService.getComponentManager().getComponentMetatada().getClassName() + "] Set the value of the property " + m_metadata.getName() + " [" + m_metadata.getType() + "] " + " with the value : " + value);
+
+ if (type.equals("string") || type.equals("String")) { m_value = new String(value); return; }
+ if (type.equals("boolean")) { m_value = new Boolean(value); return; }
+ if (type.equals("byte")) { m_value = new Byte(value); return; }
+ if (type.equals("short")) { m_value = new Short(value); return; }
+ if (type.equals("int")) { m_value = new Integer(value); return; }
+ if (type.equals("long")) { m_value = new Long(value); return; }
+ if (type.equals("float")) { m_value = new Float(value); return; }
+ if (type.equals("double")) { m_value = new Double(value); return; }
+
+ // Else it is a neither a primitive type neither a String -> create the object by calling a constructor with a string in argument.
+ try {
+ Class c = m_providedService.getComponentManager().getContext().getBundle().loadClass(type);
+ //Class string = m_providedService.getComponentManager().getContext().getBundle().loadClass("java.lang.String");
+ Constructor cst = c.getConstructor(new Class[] {String.class});
+ m_value = cst.newInstance(new Object[] {value});
+ } catch (ClassNotFoundException e) {
+ System.err.println("Class not found exception in setValue on " + type);
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ System.err.println("Constructor not found exeption in setValue on " + type);
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ System.err.println("Argument problem to call the constructor of the type " + type);
+ e.printStackTrace();
+ } catch (InstantiationException e) {
+ System.err.println("Instantiation problem " + type);
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ System.err.println("Invocation problem " + type);
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * @return the value of the property.
+ */
+ public Object getValue() { return m_value; }
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/PropertyMetadata.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/PropertyMetadata.java
new file mode 100644
index 0000000..9b90e76
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/PropertyMetadata.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.providedService;
+
+/**
+ * Property metadata : either static either dynamic.
+ * @author Clement Escoffier
+ */
+public class PropertyMetadata {
+
+ /**
+ * Field of the property.
+ */
+ private String m_field;
+
+ /**
+ * Name of the property.
+ */
+ private String m_name;
+
+ /**
+ * Type of the property.
+ */
+ private String m_type;
+
+ /**
+ * String value of the property (initial value).
+ */
+ private String m_value;
+
+ //Constructor
+
+ /**
+ * Constructor.
+ * @param name : name of the property
+ * @param field : field of the property
+ * @param type : type of the property
+ * @param value : initial value of the property
+ */
+ public PropertyMetadata(String name, String field, String type, String value) {
+ m_name = name;
+ m_field = field;
+ m_type = type;
+ m_value = value;
+
+ // Dynamic property case :
+ if (m_field != null) {
+ if (m_name == null) { m_name = m_field; }
+ }
+ }
+
+ /**
+ * @return the field name.
+ */
+ public String getField() { return m_field; };
+
+ /**
+ * @return the property name.
+ */
+ public String getName() { return m_name; };
+
+ /**
+ * @return the type of the property.
+ */
+ public String getType() { return m_type; };
+
+ /**
+ * @return the initial value.
+ */
+ public String getValue() { return m_value; }
+
+ /**
+ * Set the type of the property (dynamic property only).
+ * @param type : the type of the property.
+ */
+ public void setType(String type) { m_type = type; }
+
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/ProvidedService.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/ProvidedService.java
new file mode 100644
index 0000000..041642d
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/ProvidedService.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.providedService;
+
+import java.util.Properties;
+import java.util.logging.Level;
+
+import org.apache.felix.ipojo.ComponentManager;
+import org.apache.felix.ipojo.Activator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * Provided Service represent a provided service by the component.
+ * Date : 3 déc. 2005
+ * @author clément
+ *
+ */
+public class ProvidedService implements ServiceFactory {
+
+ /**
+ * Service State : REGISTRED.
+ */
+ public static final int REGISTERED = 1;
+
+ /**
+ * Service State : UNREGISTRED.
+ */
+ public static final int UNREGISTERED = 0;
+
+ /**
+ * Factory Policy : SINGLETON_FACTORY.
+ */
+ public static final int SINGLETON_FACTORY = 0;
+
+ /**
+ * Factory policy : SERVICE_FACTORY.
+ */
+ public static final int SERVICE_FACTORY = 1;
+
+ /**
+ * Factory policy : COMPONENT_FACTORY.
+ * TODO : Component_factory behavior
+ */
+ public static final int COMPONENT_FACTORY = 2;
+
+ /**
+ * The service registration.
+ * is null when the service is not registred.
+ * m_serviceRegistration : ServiceRegistration
+ */
+ private ServiceRegistration m_serviceRegistration;
+
+ /**
+ * Link to the component manager.
+ * m_handler : ComponentManager
+ */
+ private ProvidedServiceHandler m_handler;
+
+ /**
+ * Provided service metadata.
+ */
+ private ProvidedServiceMetadata m_metadata;
+
+ /**
+ * State of the provided service.
+ */
+ private int m_state;
+
+ /**
+ * Properties Array.
+ */
+ private Property[] m_properties = new Property[0];
+
+
+ /**
+ * Construct a provided service object.
+ * @param handler : the provided service handler.
+ * @param psm : the provided service metadata.
+ */
+ public ProvidedService(ProvidedServiceHandler handler, ProvidedServiceMetadata psm) {
+ m_handler = handler;
+ m_metadata = psm;
+ for (int i = 0; i < psm.getProperties().length; i++) {
+ Property prop = new Property(this, ((PropertyMetadata)psm.getProperties()[i]));
+ addProperty(prop);
+ }
+ }
+
+ /**
+ * Add the given property to the property list.
+ * @param p : the element to add
+ */
+ private void addProperty(Property p) {
+ for (int i = 0; (m_properties != null) && (i < m_properties.length); i++) {
+ if (m_properties[i] == p) { return; }
+ }
+
+ if (m_properties.length > 0) {
+ Property[] newProp = new Property[m_properties.length + 1];
+ System.arraycopy(m_properties, 0, newProp, 0, m_properties.length);
+ newProp[m_properties.length] = p;
+ m_properties = newProp;
+ }
+ else { m_properties = new Property[] {p}; }
+ }
+
+ /**
+ * @return the service reference of the provided service (null if the service is not published).
+ */
+ public ServiceReference getServiceReference() {
+ if (m_serviceRegistration != null) { return m_serviceRegistration.getReference(); }
+ else { return null; }
+ }
+
+ /**
+ * Return a service object for the dependency.
+ * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+ * @param bundle : the bundle
+ * @param registration : the service registration of the registred service
+ * @return : a new service object or a already created service object (in the case of singleton)
+ */
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+
+ switch(m_metadata.getFactoryPolicy()) {
+
+ case SINGLETON_FACTORY :
+ return m_handler.getComponentManager().getInstance();
+
+ case SERVICE_FACTORY :
+ return m_handler.getComponentManager().createInstance();
+
+ case COMPONENT_FACTORY :
+ //TODO Component Factory Behavior
+ return null;
+
+ default :
+ Activator.getLogger().log(Level.SEVERE, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Unknown factory policy for " + m_metadata.getServiceSpecification() + " : " + m_metadata.getFactoryPolicy());
+ return null;
+ }
+
+ }
+
+ /**
+ * The unget method.
+ * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+ * @param bundle : bundle
+ * @param registration : service registration
+ * @param service : service object
+ */
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+ //Nothing to do
+ }
+
+// /**
+// * Validate the service dependencies of the current provided service.
+// * @return true if the service dependencies are valid
+// */
+// public boolean validate() {
+// boolean valide = true;
+// for (int i = 0; i < m_dependencies.length; i++) {
+// Dependency dep = m_dependencies[i];
+// valide = valide & dep.isSatisfied();
+// if (!valide) {
+// ComponentManager.getLogger().log(Level.INFO, "Service Dependency for " + m_interface + " not valid : " + dep.getInterface());
+// return false;
+// }
+// }
+// ComponentManager.getLogger().log(Level.INFO, "Service dependencies for " + m_interface + " are valid");
+// return valide;
+// }
+
+ /**
+ * Register the service.
+ * The service object must be able to serve this service.
+ * To avoid cycle in Check Context, the registred service is set to registred before the real registration.
+ */
+ protected void registerService() {
+ if (m_state != REGISTERED) {
+ String spec = "";
+ for (int i = 0; i < m_metadata.getServiceSpecification().length; i++) {
+ spec = spec + m_metadata.getServiceSpecification()[i] + ", ";
+ }
+ Activator.getLogger().log(Level.INFO, "[" + m_handler.getComponentManager().getComponentMetatada().getClassName() + "] Register the service : " + spec);
+ // Contruct the service properties list
+ Properties serviceProperties = getServiceProperties();
+
+ m_state = REGISTERED;
+ m_serviceRegistration = m_handler.getComponentManager().getContext().registerService(m_metadata.getServiceSpecification(), this, serviceProperties);
+ }
+ }
+
+ /**
+ * Unregister the service.
+ */
+ protected void unregisterService() {
+ if (m_state == REGISTERED) {
+ try {
+ m_serviceRegistration.unregister();
+ m_serviceRegistration = null;
+ } catch (Exception e) { return; }
+ m_state = UNREGISTERED;
+ }
+ }
+
+ /**
+ * @return The state of the provided service.
+ */
+ public int getState() {
+ return m_state;
+ }
+
+ /**
+ * @return the component manager.
+ */
+ protected ComponentManager getComponentManager() {
+ return m_handler.getComponentManager();
+ }
+
+ /**
+ * Return the list of properties attached to this service.
+ * This list contains only property where a value are assigned.
+ * @return the properties attached to the provided service.
+ */
+ private Properties getServiceProperties() {
+ // Contruct the service properties list
+ Properties serviceProperties = new Properties();
+ for (int i = 0; i < m_properties.length; i++) {
+ if (m_properties[i].get() != null) {
+ serviceProperties.put(m_properties[i].getMetadata().getName(), m_properties[i].get().toString());
+ }
+ }
+ return serviceProperties;
+ }
+
+ /**
+ * @return the properties attached to the provided service.
+ */
+ public Property[] getProperties() {
+ return m_properties;
+ }
+
+ /**
+ * Update refresh the service properties.
+ * The new list of properties is sended to the service registry.
+ */
+ protected void update() {
+ // Update the service properties
+
+ // Contruct the service properties list
+ Properties serviceProperties = getServiceProperties();
+
+ // Update the service registration
+ if (m_state == REGISTERED) { m_serviceRegistration.setProperties(serviceProperties); }
+ }
+
+ /**
+ * @return the propvided service metadata.
+ */
+ public ProvidedServiceMetadata getMetadata() {
+ return m_metadata;
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/ProvidedServiceHandler.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/ProvidedServiceHandler.java
new file mode 100644
index 0000000..d9b98cc
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/ProvidedServiceHandler.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.providedService;
+
+import java.util.logging.Level;
+
+import org.apache.felix.ipojo.ComponentManager;
+import org.apache.felix.ipojo.Handler;
+import org.apache.felix.ipojo.Activator;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * @author Clement Escoffier
+ *
+ */
+public class ProvidedServiceHandler implements Handler {
+
+
+ /**
+ * The list of the provided service.
+ */
+ private ProvidedService[] m_providedServices = new ProvidedService[0];
+
+ /**
+ * The component manager.
+ */
+ private ComponentManager m_componentManager;
+
+ private void addProvidedService(ProvidedService ps) {
+ // Verify that the provided service is not already in the array.
+ for (int i = 0; (m_providedServices != null) && (i < m_providedServices.length); i++) {
+ if (m_providedServices[i] == ps) { return; }
+ }
+
+ if (m_providedServices.length > 0) {
+ ProvidedService[] newPS = new ProvidedService[m_providedServices.length + 1];
+ System.arraycopy(m_providedServices, 0, newPS, 0, m_providedServices.length);
+ newPS[m_providedServices.length] = ps;
+ m_providedServices = newPS;
+ }
+ else { m_providedServices = new ProvidedService[] {ps}; }
+ }
+
+ /**
+ * @return the component manager.
+ */
+ public ComponentManager getComponentManager() { return m_componentManager; }
+
+ /**
+ * @return the list of the provided service.
+ */
+ public ProvidedService[] getProvidedService() { return m_providedServices; }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.ComponentManager, org.apache.felix.ipojo.metadata.Element)
+ */
+ public void configure(ComponentManager cm, Element componentMetadata) {
+ // Fix the component managert & clean the provided service list
+ m_componentManager = cm;
+ m_providedServices = new ProvidedService[0];
+ // Create the dependency according to the component metadata
+ Element[] providedServices = componentMetadata.getElements("Provides");
+ for (int i = 0; i < providedServices.length; i++) {
+ // Create a ProvidedServiceMetadata object
+
+ // First : create the serviceSpecification array
+ String[] serviceSpecification = new String[0];
+ if (providedServices[i].containsAttribute("interface")) {
+ String serviceSpecificationStr = providedServices[i].getAttribute("interface");
+ //Get serviceSpecification if exist in the metadata
+ String[] spec = serviceSpecificationStr.split(",");
+ serviceSpecification = new String[spec.length];
+ for (int j = 0; j < spec.length; j++) { serviceSpecification[j] = spec[j].trim(); }
+ } else {
+ Element manipulation = m_componentManager.getComponentMetatada().getMetadata().getElements("Manipulation")[0];
+ serviceSpecification = new String[manipulation.getElements("Interface").length];
+ for (int j = 0; j < manipulation.getElements("Interface").length; j++) {
+ serviceSpecification[j] = manipulation.getElements("Interface")[j].getAttribute("name");
+ }
+ }
+
+ // Get the factory policy
+ int factory = ProvidedServiceMetadata.SINGLETON_FACTORY;
+ if (providedServices[i].containsAttribute("factory") && providedServices[i].getAttribute("factory").equals("service")) { factory = ProvidedService.SERVICE_FACTORY; }
+
+ // Then create the provided service metadata
+ ProvidedServiceMetadata psm = new ProvidedServiceMetadata(serviceSpecification, factory);
+
+ // Create properties
+ Element[] dynamicProps = providedServices[i].getElements("DynamicProperty");
+ Element[] staticProps = providedServices[i].getElements("StaticProperty");
+ Element[] props = providedServices[i].getElements("Property");
+ for (int j = 0; j < dynamicProps.length; j++) {
+ Activator.getLogger().log(Level.WARNING, "[" + m_componentManager.getComponentMetatada().getClassName() + "] Please use property instead of dynamic property");
+ String name = null;
+ if (dynamicProps[j].containsAttribute("name")) { name = dynamicProps[j].getAttribute("name"); }
+ String field = dynamicProps[j].getAttribute("field");
+ String value = null;
+ if (dynamicProps[j].containsAttribute("value")) { value = dynamicProps[j].getAttribute("value"); }
+ String type = null;
+ if (dynamicProps[j].containsAttribute("type")) { type = dynamicProps[j].getAttribute("type"); }
+ PropertyMetadata pm = new PropertyMetadata(name, field, type, value);
+ psm.addProperty(pm);
+ }
+ for (int j = 0; j < staticProps.length; j++) {
+ Activator.getLogger().log(Level.WARNING, "[" + m_componentManager.getComponentMetatada().getClassName() + "] Please use property instead of static property");
+ String name = staticProps[j].getAttribute("name");
+ String value = staticProps[j].getAttribute("value");
+ String type = staticProps[j].getAttribute("type");
+ PropertyMetadata pm = new PropertyMetadata(name, null, type, value);
+ psm.addProperty(pm);
+ }
+ for (int j = 0; j < props.length; j++) {
+ String name = null;
+ if (props[j].containsAttribute("name")) { name = props[j].getAttribute("name"); }
+ String value = null;
+ if (props[j].containsAttribute("value")) { value = props[j].getAttribute("value"); }
+ String type = null;
+ if (props[j].containsAttribute("type")) { type = props[j].getAttribute("type"); }
+ String field = null;
+ if (props[j].containsAttribute("field")) { field = props[j].getAttribute("field"); }
+ PropertyMetadata pm = new PropertyMetadata(name, field, type, value);
+ psm.addProperty(pm);
+ }
+
+ // Create the provided service object
+ ProvidedService ps = new ProvidedService(this, psm);
+ if (checkProvidedService(ps)) { addProvidedService(ps); }
+ else {
+ String itfs = "";
+ for (int j = 0; j < serviceSpecification.length; j++) {
+ itfs = itfs + " " + serviceSpecification[j];
+ }
+ Activator.getLogger().log(Level.SEVERE, "[" + m_componentManager.getComponentMetatada().getClassName() + "] The provided service" + itfs + " is not valid, it will be removed");
+ ps = null;
+ }
+ }
+
+ if (providedServices.length > 0) { m_componentManager.register(this); }
+ }
+
+ private boolean containsInterface(String s) {
+ Element manipulation = m_componentManager.getComponentMetatada().getMetadata().getElements("Manipulation")[0];
+ for (int i = 0; i < manipulation.getElements("Interface").length; i++) {
+ if (manipulation.getElements("Interface")[i].getAttribute("name").equals(s)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkProvidedService(ProvidedService ps) {
+
+ for (int i = 0; i < ps.getMetadata().getServiceSpecification().length; i++) {
+ if (!containsInterface(ps.getMetadata().getServiceSpecification()[i])) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_componentManager.getComponentMetatada().getClassName() + "] The service specification " + ps.getMetadata().getServiceSpecification()[i] + " is not implemented by the component class");
+ return false;
+ }
+ }
+
+ // Fix internal property type
+ for (int i = 0; i < ps.getProperties().length; i++) {
+ Property prop = ps.getProperties()[i];
+ String field = prop.getMetadata().getField();
+
+ if (field == null) {
+ // Static dependency -> Nothing to check
+ return true;
+ } else {
+ Element manipulation = getComponentManager().getComponentMetatada().getMetadata().getElements("Manipulation")[0];
+ String type = null;
+ for (int j = 0; j < manipulation.getElements("Field").length; j++) {
+ if (field.equals(manipulation.getElements("Field")[j].getAttribute("name"))) {
+ type = manipulation.getElements("Field")[j].getAttribute("type");
+ break;
+ }
+ }
+ if (type == null) {
+ Activator.getLogger().log(Level.SEVERE, "[" + m_componentManager.getComponentMetatada().getClassName() + "] A declared property was not found in the class : " + prop.getMetadata().getField());
+ return false;
+ }
+
+ if (type != null) {
+ if (type.endsWith("[]")) {
+ // TODO array property
+ Activator.getLogger().log(Level.SEVERE, "[" + m_componentManager.getComponentMetatada().getClassName() + "] An array property was found in the class [Not implemented yet] : " + prop.getMetadata().getField());
+ return false;
+ }
+
+ if (prop.getMetadata().getType() == null) { prop.getMetadata().setType(type); }
+
+ if (!prop.getMetadata().getType().equals(type)) {
+ Activator.getLogger().log(Level.WARNING, "[" + m_componentManager.getComponentMetatada().getClassName() + "] The field type [" + type + "] and the declared type [" + prop.getMetadata().getType() + "] are not the same for " + prop.getMetadata().getField());
+ prop.getMetadata().setType(type);
+ }
+ }
+ else {
+ Activator.getLogger().log(Level.WARNING, "[" + m_componentManager.getComponentMetatada().getClassName() + "] The declared property " + prop.getMetadata().getField() + " does not exist in the code");
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Stop the provided service handler : unregister all provided services.
+ * @see org.apache.felix.ipojo.Handler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_providedServices.length; i++) {
+ m_providedServices[i].unregisterService();
+ }
+ }
+
+ /**
+ * Start the provided service handler : register the service if the component is resolved.
+ * Else do nothing and whait for a component state change event
+ * @see org.apache.felix.ipojo.Handler#start()
+ */
+ public void start() {
+ Activator.getLogger().log(Level.INFO, "[" + m_componentManager.getComponentMetatada().getClassName() + "] Start the provided service handler");
+ for (int i = 0; (m_componentManager.getState() == ComponentManager.VALID) && i < m_providedServices.length; i++) {
+ m_providedServices[i].registerService();
+ }
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#setterCallback(java.lang.String, java.lang.Object)
+ */
+ public void setterCallback(String fieldName, Object value) {
+ // Verify that the field name coreespond to a dependency
+ for (int i = 0; i < m_providedServices.length; i++) {
+ ProvidedService ps = m_providedServices[i];
+ for (int j = 0; j < ps.getProperties().length; j++) {
+ Property prop = ps.getProperties()[j];
+ if (fieldName.equals(prop.getMetadata().getField())) {
+ // it is the associated property
+ prop.set(value);
+ }
+ }
+ }
+ //Else do nothing
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#getterCallback(java.lang.String, java.lang.Object)
+ */
+ public Object getterCallback(String fieldName, Object value) {
+ for (int i = 0; i < m_providedServices.length; i++) {
+ ProvidedService ps = m_providedServices[i];
+ for (int j = 0; j < ps.getProperties().length; j++) {
+ Property prop = ps.getProperties()[j];
+ if (fieldName.equals(prop.getMetadata().getField())) {
+ // it is the associated property
+ return prop.get();
+ }
+ }
+ }
+ // Else it is not a property
+ return value;
+ }
+
+ /**
+ * @see org.apache.felix.ipojo.Handler#isValid()
+ */
+ public boolean isValid() {
+ // The provided service handler does not need to manipulate the field
+ // Return always true
+ return true;
+ }
+
+ /**
+ * Register the services if the new state is VALID.
+ * Unregister the services if the new state is UNRESOLVED.
+ * @see org.apache.felix.ipojo.Handler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ // If the new state is UNRESOLVED => unregister all the services
+ if (state == ComponentManager.INVALID) {
+ stop();
+ return;
+ }
+
+ // If the new state is VALID => regiter all the services
+ if (state == ComponentManager.VALID) {
+ start();
+ return;
+ }
+
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/ProvidedServiceMetadata.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/ProvidedServiceMetadata.java
new file mode 100644
index 0000000..a4e7fd3
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedService/ProvidedServiceMetadata.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.ipojo.handlers.providedService;
+
+
+/**
+ * Provided Service Metadata.
+ * @author Clément Escoffier
+ */
+public class ProvidedServiceMetadata {
+
+ /**
+ * Factory Policy : SINGLETON_FACTORY.
+ */
+ public static final int SINGLETON_FACTORY = 0;
+
+ /**
+ * Factory policy : SERVICE_FACTORY.
+ */
+ public static final int SERVICE_FACTORY = 1;
+
+ /**
+ * Factory policy : COMPONENT_FACTORY.
+ * TODO : Component_factory behavior
+ */
+ public static final int COMPONENT_FACTORY = 2;
+
+ /**
+ * At this time, it is only the java interface full name.
+ */
+ private String[] m_serviceSpecification = new String[0];
+
+ /**
+ * List of proeprty metadata.
+ */
+ private PropertyMetadata[] m_properties = new PropertyMetadata[0];
+
+ /**
+ * Foactory policy.
+ */
+ private int m_factoryPolicy = SINGLETON_FACTORY;
+
+ //CONSTRUCTOR :
+
+ /**
+ * Constructor.
+ * @param specification : service specification (i.e. the interface)
+ * @param factoryPolicy : the facotry policy.
+ */
+ public ProvidedServiceMetadata(String[] specification, int factoryPolicy) {
+ m_serviceSpecification = specification;
+ m_factoryPolicy = factoryPolicy;
+ }
+
+ // GETTERS :
+
+
+ /**
+ * @return the service specification (i.e. the interface)
+ */
+ public String[] getServiceSpecification() { return m_serviceSpecification; }
+
+ /**
+ * @return the property metadata list.
+ */
+ public PropertyMetadata[] getProperties() { return m_properties; }
+
+ /**
+ * @return the factory policy.
+ */
+ public int getFactoryPolicy() { return m_factoryPolicy; }
+
+ // SETTERS :
+
+ /**
+ * Add the given property metadata to the property metadata list.
+ * @param p : property metdata to add
+ */
+ protected void addProperty(PropertyMetadata p) {
+ for (int i = 0; (m_properties != null) && (i < m_properties.length); i++) {
+ if (m_properties[i] == p) { return; }
+ }
+
+ if (m_properties.length > 0) {
+ PropertyMetadata[] newProp = new PropertyMetadata[m_properties.length + 1];
+ System.arraycopy(m_properties, 0, newProp, 0, m_properties.length);
+ newProp[m_properties.length] = p;
+ m_properties = newProp;
+ }
+ else {
+ m_properties = new PropertyMetadata[] {p};
+ }
+ }
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
new file mode 100644
index 0000000..b7171e6
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.parser;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Manifest Metadata parser.
+ * Read a manifest file and construct metadata
+ * @author Clement Escoffier
+ */
+public class ManifestMetadataParser {
+
+ /**
+ * Manifest Headers.
+ */
+ private Dictionary m_headers;
+
+ /**
+ * Element list.
+ */
+ private Element[] m_elements = new Element[0];
+
+ /**
+ * @return the component metadata.
+ * @throws ParseException when a parsing error occurs
+ */
+ public Element[] getComponentsMetadata() throws ParseException {
+ return m_elements[0].getElements("Component");
+ }
+
+ private void addElement(Element elem) {
+ for (int i = 0; (m_elements != null) && (i < m_elements.length); i++) {
+ if (m_elements[i] == elem) { return; }
+ }
+
+ if (m_elements != null) {
+ Element[] newElementsList = new Element[m_elements.length + 1];
+ System.arraycopy(m_elements, 0, newElementsList, 0, m_elements.length);
+ newElementsList[m_elements.length] = elem;
+ m_elements = newElementsList;
+ }
+ else { m_elements = new Element[] {elem}; }
+ }
+
+ private Element removeLastElement() {
+ int idx = -1;
+ idx = m_elements.length - 1;
+ Element last = m_elements[idx];
+ if (idx >= 0) {
+ if ((m_elements.length - 1) == 0) {
+ // It is the last element of the list;
+ m_elements = new Element[0];
+ }
+ else {
+ // Remove the last element of the list :
+ Element[] newElementsList = new Element[m_elements.length - 1];
+ System.arraycopy(m_elements, 0, newElementsList, 0, idx);
+ m_elements = newElementsList;
+ }
+ }
+ return last;
+ }
+
+ /**
+ * Parse the given dictionnary and create the components manager.
+ * @param dict : the given headers of the manifest file
+ * @throws ParseException : if any error occurs
+ */
+ public void parse(Dictionary dict) throws ParseException {
+ m_headers = dict;
+ String componentClassesStr = (String)m_headers.get("iPOJO-Components");
+ //Add the ipojo element inside the element list
+ addElement(new Element("iPOJO", ""));
+ parseElements(componentClassesStr.trim());
+
+ }
+
+ /**
+ * Parse the metadata from the string given in argument.
+ * @param metadata : the metadata to parse
+ * @return Element : the root element resulting of the parsing
+ * @throws ParseException : if any error occurs
+ */
+ public static Element parse(String metadata) throws ParseException {
+ ManifestMetadataParser parser = new ManifestMetadataParser();
+ parser.parseElements(metadata);
+ if (parser.m_elements.length != 1) { throw new ParseException("Error in parsing, root element not found : " + metadata); }
+ return parser.m_elements[0];
+ }
+
+ private void parseElements(String s) {
+ char[] string = s.toCharArray();
+
+ for (int i = 0; i < string.length; i++) {
+ char c = string[i];
+
+ switch(c) {
+
+ case '$' :
+ String attName = "";
+ String attValue = "";
+ String attNs = "";
+ i++;
+ c = string[i];
+ while (c != '=') {
+ if (c == ':') {
+ attNs = attName;
+ attName = "";
+ } else { attName = attName + c; }
+ i = i + 1;
+ c = string[i];
+ }
+ i++; // skip =
+ c = string[i];
+ while (c != ' ') {
+ attValue = attValue + c;
+ i++;
+ c = string[i];
+ }
+ Attribute att = new Attribute(attName, attNs , attValue);
+ m_elements[m_elements.length - 1].addAttribute(att);
+ break;
+
+ case '}' :
+ Element lastElement = removeLastElement();
+ if (m_elements.length != 0) {
+ Element newQueue = m_elements[m_elements.length - 1];
+ newQueue.addElement(lastElement);
+ }
+ else {
+ addElement(lastElement);
+ }
+ break;
+ case ' ' : break; // do nothing;
+ default :
+ String name = "";
+ String ns = "";
+ c = string[i];
+ while (c != ' ') {
+ if (c == ':') {
+ ns = name;
+ name = "";
+ i++;
+ c = string[i];
+ }
+ else {
+ name = name + c;
+ i++;
+ c = string[i];
+ }
+ }
+ // Skip spaces
+ while (string[i] == ' ') { i = i + 1; }
+ i = i + 1; // skip {
+ Element elem = new Element(name, ns);
+ addElement(elem);
+ break;
+ }
+ }
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ParseException.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ParseException.java
new file mode 100644
index 0000000..4cf61b8
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ParseException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.parser;
+
+/**
+ * Exceptions thrown by parsers.
+ * @author Clement Escoffier
+ */
+public class ParseException extends Exception {
+
+ /**
+ * serialVersionUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Parsing error.
+ * @param msg : the error emssage.
+ */
+ public ParseException(String msg) {
+ super(msg);
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/Configuration.java b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/Configuration.java
new file mode 100644
index 0000000..a4d54cd
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/Configuration.java
@@ -0,0 +1,227 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/Configuration.java,v 1.16 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import java.io.IOException;
+import java.util.Dictionary;
+
+/**
+ * The configuration information for a <code>ManagedService</code> or
+ * <code>ManagedServiceFactory</code> object.
+ *
+ * The Configuration Admin service uses this interface to represent the
+ * configuration information for a <code>ManagedService</code> or for a
+ * service instance of a <code>ManagedServiceFactory</code>.
+ *
+ * <p>
+ * A <code>Configuration</code> object contains a configuration dictionary and
+ * allows the properties to be updated via this object. Bundles wishing to
+ * receive configuration dictionaries do not need to use this class - they
+ * register a <code>ManagedService</code> or
+ * <code>ManagedServiceFactory</code>. Only administrative bundles, and
+ * bundles wishing to update their own configurations need to use this class.
+ *
+ * <p>
+ * The properties handled in this configuration have case insensitive
+ * <code>String</code> objects as keys. However, case is preserved from the
+ * last set key/value.
+ * <p>
+ * A configuration can be <i>bound </i> to a bundle location (
+ * <code>Bundle.getLocation()</code>). The purpose of binding a
+ * <code>Configuration</code> object to a location is to make it impossible
+ * for another bundle to forge a PID that would match this configuration. When a
+ * configuration is bound to a specific location, and a bundle with a different
+ * location registers a corresponding <code>ManagedService</code> object or
+ * <code>ManagedServiceFactory</code> object, then the configuration is not
+ * passed to the updated method of that object.
+ *
+ * <p>
+ * If a configuration's location is <code>null</code>, it is not yet bound to
+ * a location. It will become bound to the location of the first bundle that
+ * registers a <code>ManagedService</code> or
+ * <code>ManagedServiceFactory</code> object with the corresponding PID.
+ * <p>
+ * The same <code>Configuration</code> object is used for configuring both a
+ * Managed Service Factory and a Managed Service. When it is important to
+ * differentiate between these two the term "factory configuration" is used.
+ *
+ * @version $Revision: 1.16 $
+ */
+public interface Configuration {
+ /**
+ * Get the PID for this <code>Configuration</code> object.
+ *
+ * @return the PID for this <code>Configuration</code> object.
+ * @throws IllegalStateException if this configuration has been deleted
+ */
+ public String getPid();
+
+ /**
+ * Return the properties of this <code>Configuration</code> object.
+ *
+ * The <code>Dictionary</code> object returned is a private copy for the
+ * caller and may be changed without influencing the stored configuration.
+ * The keys in the returned dictionary are case insensitive and are always
+ * of type <code>String</code>.
+ *
+ * <p>
+ * If called just after the configuration is created and before update has
+ * been called, this method returns <code>null</code>.
+ *
+ * @return A private copy of the properties for the caller or
+ * <code>null</code>. These properties must not contain the
+ * "service.bundleLocation" property. The value of this property may
+ * be obtained from the <code>getBundleLocation</code> method.
+ * @throws IllegalStateException if this configuration has been deleted
+ */
+ public Dictionary getProperties();
+
+ /**
+ * Update the properties of this <code>Configuration</code> object.
+ *
+ * Stores the properties in persistent storage after adding or overwriting
+ * the following properties:
+ * <ul>
+ * <li>"service.pid" : is set to be the PID of this configuration.</li>
+ * <li>"service.factoryPid" : if this is a factory configuration it is set
+ * to the factory PID else it is not set.</li>
+ * </ul>
+ * These system properties are all of type <code>String</code>.
+ *
+ * <p>
+ * If the corresponding Managed Service/Managed Service Factory is
+ * registered, its updated method must be called asynchronously. Else, this
+ * callback is delayed until aforementioned registration occurs.
+ *
+ * <p>
+ * Also intiates an asynchronous call to all
+ * <code>ConfigurationListener</code>s with a
+ * <code>ConfigurationEvent.CM_UPDATED</code> event.
+ *
+ * @param properties the new set of properties for this configuration
+ * @throws IOException if update cannot be made persistent
+ * @throws IllegalArgumentException if the <code>Dictionary</code> object
+ * contains invalid configuration types or contains case variants of
+ * the same key name.
+ * @throws IllegalStateException if this configuration has been deleted
+ */
+ public void update(Dictionary properties) throws IOException;
+
+ /**
+ * Delete this <code>Configuration</code> object.
+ *
+ * Removes this configuration object from the persistent store. Notify
+ * asynchronously the corresponding Managed Service or Managed Service
+ * Factory. A <code>ManagedService</code> object is notified by a call to
+ * its <code>updated</code> method with a <code>null</code> properties
+ * argument. A <code>ManagedServiceFactory</code> object is notified by a
+ * call to its <code>deleted</code> method.
+ *
+ * <p>
+ * Also intiates an asynchronous call to all
+ * <code>ConfigurationListener</code>s with a
+ * <code>ConfigurationEvent.CM_DELETED</code> event.
+ *
+ * @throws IOException If delete fails
+ * @throws IllegalStateException if this configuration has been deleted
+ */
+ public void delete() throws IOException;
+
+ /**
+ * For a factory configuration return the PID of the corresponding Managed
+ * Service Factory, else return <code>null</code>.
+ *
+ * @return factory PID or <code>null</code>
+ * @throws IllegalStateException if this configuration has been deleted
+ */
+ public String getFactoryPid();
+
+ /**
+ * Update the <code>Configuration</code> object with the current
+ * properties.
+ *
+ * Initiate the <code>updated</code> callback to the Managed Service or
+ * Managed Service Factory with the current properties asynchronously.
+ *
+ * <p>
+ * This is the only way for a bundle that uses a Configuration Plugin
+ * service to initate a callback. For example, when that bundle detects a
+ * change that requires an update of the Managed Service or Managed Service
+ * Factory via its <code>ConfigurationPlugin</code> object.
+ *
+ * @see ConfigurationPlugin
+ * @throws IOException if update cannot access the properties in persistent
+ * storage
+ * @throws IllegalStateException if this configuration has been deleted
+ */
+ public void update() throws IOException;
+
+ /**
+ * Bind this <code>Configuration</code> object to the specified bundle
+ * location.
+ *
+ * If the bundleLocation parameter is <code>null</code> then the
+ * <code>Configuration</code> object will not be bound to a location. It
+ * will be set to the bundle's location before the first time a Managed
+ * Service/Managed Service Factory receives this <code>Configuration</code>
+ * object via the updated method and before any plugins are called. The
+ * bundle location will be set persistently.
+ *
+ * @param bundleLocation a bundle location or <code>null</code>
+ * @throws IllegalStateException If this configuration has been deleted.
+ * @throws SecurityException If the caller does not have
+ * <code>ConfigurationPermission[*,CONFIGURE]</code>.
+ */
+ public void setBundleLocation(String bundleLocation);
+
+ /**
+ * Get the bundle location.
+ *
+ * Returns the bundle location to which this configuration is bound, or
+ * <code>null</code> if it is not yet bound to a bundle location.
+ *
+ * @return location to which this configuration is bound, or
+ * <code>null</code>.
+ * @throws IllegalStateException If this <code>Configuration</code> object
+ * has been deleted.
+ * @throws SecurityException If the caller does not have
+ * <code>ConfigurationPermission[*,CONFIGURE]</code>.
+ */
+ public String getBundleLocation();
+
+ /**
+ * Equality is defined to have equal PIDs
+ *
+ * Two Configuration objects are equal when their PIDs are equal.
+ *
+ * @param other <code>Configuration</code> object to compare against
+ * @return <code>true</code> if equal, <code>false</code> if not a
+ * <code>Configuration</code> object or one with a different PID.
+ */
+ public boolean equals(Object other);
+
+ /**
+ * Hash code is based on PID.
+ *
+ * The hashcode for two Configuration objects must be the same when the
+ * Configuration PID's are the same.
+ *
+ * @return hash code for this Configuration object
+ */
+ public int hashCode();
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java
new file mode 100644
index 0000000..f0f7836
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java
@@ -0,0 +1,256 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationAdmin.java,v 1.14 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import java.io.IOException;
+import java.util.Dictionary;
+
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * Service for administering configuration data.
+ *
+ * <p>
+ * The main purpose of this interface is to store bundle configuration data
+ * persistently. This information is represented in <code>Configuration</code>
+ * objects. The actual configuration data is a <code>Dictionary</code> of
+ * properties inside a <code>Configuration</code> object.
+ *
+ * <p>
+ * There are two principally different ways to manage configurations. First
+ * there is the concept of a Managed Service, where configuration data is
+ * uniquely associated with an object registered with the service registry.
+ *
+ * <p>
+ * Next, there is the concept of a factory where the Configuration Admin service
+ * will maintain 0 or more <code>Configuration</code> objects for a Managed
+ * Service Factory that is registered with the Framework.
+ *
+ * <p>
+ * The first concept is intended for configuration data about "things/services"
+ * whose existence is defined externally, e.g. a specific printer. Factories are
+ * intended for "things/services" that can be created any number of times, e.g.
+ * a configuration for a DHCP server for different networks.
+ *
+ * <p>
+ * Bundles that require configuration should register a Managed Service or a
+ * Managed Service Factory in the service registry. A registration property
+ * named <code>service.pid</code> (persistent identifier or PID) must be used
+ * to identify this Managed Service or Managed Service Factory to the
+ * Configuration Admin service.
+ *
+ * <p>
+ * When the ConfigurationAdmin detects the registration of a Managed Service, it
+ * checks its persistent storage for a configuration object whose PID matches
+ * the PID registration property (<code>service.pid</code>) of the Managed
+ * Service. If found, it calls {@link ManagedService#updated}method with the
+ * new properties. The implementation of a Configuration Admin service must run
+ * these call-backs asynchronously to allow proper synchronization.
+ *
+ * <p>
+ * When the Configuration Admin service detects a Managed Service Factory
+ * registration, it checks its storage for configuration objects whose
+ * <code>factoryPid</code> matches the PID of the Managed Service Factory. For
+ * each such <code>Configuration</code> objects, it calls the
+ * <code>ManagedServiceFactory.updated</code> method asynchronously with the
+ * new properties. The calls to the <code>updated</code> method of a
+ * <code>ManagedServiceFactory</code> must be executed sequentially and not
+ * overlap in time.
+ *
+ * <p>
+ * In general, bundles having permission to use the Configuration Admin service
+ * can only access and modify their own configuration information. Accessing or
+ * modifying the configuration of another bundle requires
+ * <code>ConfigurationPermission[*,CONFIGURE]</code>.
+ *
+ * <p>
+ * <code>Configuration</code> objects can be <i>bound </i> to a specified
+ * bundle location. In this case, if a matching Managed Service or Managed
+ * Service Factory is registered by a bundle with a different location, then the
+ * Configuration Admin service must not do the normal callback, and it should
+ * log an error. In the case where a <code>Configuration</code> object is not
+ * bound, its location field is <code>null</code>, the Configuration Admin
+ * service will bind it to the location of the bundle that registers the first
+ * Managed Service or Managed Service Factory that has a corresponding PID
+ * property. When a <code>Configuration</code> object is bound to a bundle
+ * location in this manner, the Confguration Admin service must detect if the
+ * bundle corresponding to the location is uninstalled. If this occurs, the
+ * <code>Configuration</code> object is unbound, that is its location field is
+ * set back to <code>null</code>.
+ *
+ * <p>
+ * The method descriptions of this class refer to a concept of "the calling
+ * bundle". This is a loose way of referring to the bundle which obtained the
+ * Configuration Admin service from the service registry. Implementations of
+ * <code>ConfigurationAdmin</code> must use a
+ * {@link org.osgi.framework.ServiceFactory}to support this concept.
+ *
+ * @version $Revision: 1.14 $
+ */
+public interface ConfigurationAdmin {
+ /**
+ * Service property naming the Factory PID in the configuration dictionary.
+ * The property's value is of type <code>String</code>.
+ *
+ * @since 1.1
+ */
+ public final static String SERVICE_FACTORYPID = "service.factoryPid";
+ /**
+ * Service property naming the location of the bundle that is associated
+ * with a a <code>Configuration</code> object. This property can be
+ * searched for but must not appear in the configuration dictionary for
+ * security reason. The property's value is of type <code>String</code>.
+ *
+ * @since 1.1
+ */
+ public final static String SERVICE_BUNDLELOCATION = "service.bundleLocation";
+
+ /**
+ * Create a new factory <code>Configuration</code> object with a new PID.
+ *
+ * The properties of the new <code>Configuration</code> object are
+ * <code>null</code> until the first time that its
+ * {@link Configuration#update(Dictionary)}method is called.
+ *
+ * <p>
+ * It is not required that the <code>factoryPid</code> maps to a
+ * registered Managed Service Factory.
+ * <p>
+ * The <code>Configuration</code> object is bound to the location of the
+ * calling bundle.
+ *
+ * @param factoryPid PID of factory (not <code>null</code>).
+ * @return A new <code>Configuration</code> object.
+ * @throws IOException if access to persistent storage fails.
+ * @throws SecurityException if caller does not have <code>ConfigurationPermission[*,CONFIGURE]</code> and <code>factoryPid</code> is bound to another bundle.
+ */
+ public Configuration createFactoryConfiguration(String factoryPid)
+ throws IOException;
+
+ /**
+ * Create a new factory <code>Configuration</code> object with a new PID.
+ *
+ * The properties of the new <code>Configuration</code> object are
+ * <code>null</code> until the first time that its
+ * {@link Configuration#update(Dictionary)}method is called.
+ *
+ * <p>
+ * It is not required that the <code>factoryPid</code> maps to a
+ * registered Managed Service Factory.
+ *
+ * <p>
+ * The <code>Configuration</code> is bound to the location specified. If
+ * this location is <code>null</code> it will be bound to the location of
+ * the first bundle that registers a Managed Service Factory with a
+ * corresponding PID.
+ *
+ * @param factoryPid PID of factory (not <code>null</code>).
+ * @param location A bundle location string, or <code>null</code>.
+ * @return a new <code>Configuration</code> object.
+ * @throws IOException if access to persistent storage fails.
+ * @throws SecurityException if caller does not have <code>ConfigurationPermission[*,CONFIGURE]</code>.
+ */
+ public Configuration createFactoryConfiguration(String factoryPid, String location)
+ throws IOException;
+
+ /**
+ * Get an existing <code>Configuration</code> object from the persistent
+ * store, or create a new <code>Configuration</code> object.
+ *
+ * <p>
+ * If a <code>Configuration</code> with this PID already exists in
+ * Configuration Admin service return it. The location parameter is ignored
+ * in this case.
+ *
+ * <p>
+ * Else, return a new <code>Configuration</code> object. This new object
+ * is bound to the location and the properties are set to <code>null</code>.
+ * If the location parameter is <code>null</code>, it will be set when a
+ * Managed Service with the corresponding PID is registered for the first
+ * time.
+ *
+ * @param pid Persistent identifier.
+ * @param location The bundle location string, or <code>null</code>.
+ * @return An existing or new <code>Configuration</code> object.
+ * @throws IOException if access to persistent storage fails.
+ * @throws SecurityException if the caller does not have <code>ConfigurationPermission[*,CONFIGURE]</code>.
+ */
+ public Configuration getConfiguration(String pid, String location)
+ throws IOException;
+
+ /**
+ * Get an existing or new <code>Configuration</code> object from the
+ * persistent store.
+ *
+ * If the <code>Configuration</code> object for this PID does not exist,
+ * create a new <code>Configuration</code> object for that PID, where
+ * properties are <code>null</code>. Bind its location to the calling
+ * bundle's location.
+ *
+ * <p>
+ * Otherwise, if the location of the existing <code>Configuration</code> object
+ * is <code>null</code>, set it to the calling bundle's location.
+ *
+ * @param pid persistent identifier.
+ * @return an existing or new <code>Configuration</code> matching the PID.
+ * @throws IOException if access to persistent storage fails.
+ * @throws SecurityException if the <code>Configuration</code> object is bound to a location different from that of the calling bundle and it has no <code>ConfigurationPermission[*,CONFIGURE]</code>.
+ */
+ public Configuration getConfiguration(String pid) throws IOException;
+
+ /**
+ * List the current <code>Configuration</code> objects which match the
+ * filter.
+ *
+ * <p>
+ * Only <code>Configuration</code> objects with non- <code>null</code>
+ * properties are considered current. That is,
+ * <code>Configuration.getProperties()</code> is guaranteed not to return
+ * <code>null</code> for each of the returned <code>Configuration</code>
+ * objects.
+ *
+ * <p>
+ * Normally only <code>Configuration</code> objects that are bound to the
+ * location of the calling bundle are returned, or all if the caller has
+ * <code>ConfigurationPermission[*,CONFIGURE]</code>.
+ *
+ * <p>
+ * The syntax of the filter string is as defined in the <code>Filter</code>
+ * class. The filter can test any configuration parameters including the
+ * following system properties:
+ * <ul>
+ * <li><code>service.pid</code>-<code>String</code>- the PID under
+ * which this is registered</li>
+ * <li><code>service.factoryPid</code>-<code>String</code>- the
+ * factory if applicable</li>
+ * <li><code>service.bundleLocation</code>-<code>String</code>- the
+ * bundle location</li>
+ * </ul>
+ * The filter can also be <code>null</code>, meaning that all
+ * <code>Configuration</code> objects should be returned.
+ *
+ * @param filter a <code>Filter</code> object, or <code>null</code> to
+ * retrieve all <code>Configuration</code> objects.
+ * @return all matching <code>Configuration</code> objects, or
+ * <code>null</code> if there aren't any
+ * @throws IOException if access to persistent storage fails
+ * @throws InvalidSyntaxException if the filter string is invalid
+ */
+ public Configuration[] listConfigurations(String filter) throws IOException,
+ InvalidSyntaxException;
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationEvent.java b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationEvent.java
new file mode 100644
index 0000000..28ef9e4
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationEvent.java
@@ -0,0 +1,167 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationEvent.java,v 1.8 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2005). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A Configuration Event.
+ *
+ * <p>
+ * <code>ConfigurationEvent</code> objects are delivered to all registered
+ * <code>ConfigurationListener</code> service objects. ConfigurationEvents
+ * must be asynchronously delivered in chronological order with respect to each
+ * listener.
+ *
+ * <p>
+ * A type code is used to identify the type of event. The following event types
+ * are defined:
+ * <ul>
+ * <li>{@link #CM_UPDATED}
+ * <li>{@link #CM_DELETED}
+ * </ul>
+ * Additional event types may be defined in the future.
+ *
+ * <p>
+ * Security Considerations. <code>ConfigurationEvent</code> objects do not
+ * provide <code>Configuration</code> objects, so no sensitive configuration
+ * information is available from the event. If the listener wants to locate the
+ * <code>Configuration</code> object for the specified pid, it must use
+ * <code>ConfigurationAdmin</code>.
+ *
+ * @see ConfigurationListener
+ *
+ * @version $Revision: 1.8 $
+ * @since 1.2
+ */
+public class ConfigurationEvent {
+ /**
+ * A <code>Configuration</code> has been updated.
+ *
+ * <p>
+ * This <code>ConfigurationEvent</code> type that indicates that a
+ * <code>Configuration</code> object has been updated with new properties.
+ *
+ * An event is fired when a call to <code>Configuration.update</code>
+ * successfully changes a configuration.
+ *
+ * <p>
+ * The value of <code>CM_UPDATED</code> is 1.
+ */
+ public static final int CM_UPDATED = 1;
+ /**
+ * A <code>Configuration</code> has been deleted.
+ *
+ * <p>
+ * This <code>ConfigurationEvent</code> type that indicates that a
+ * <code>Configuration</code> object has been deleted.
+ *
+ * An event is fired when a call to <code>Configuration.delete</code>
+ * successfully deletes a configuration.
+ *
+ * <p>
+ * The value of <code>CM_DELETED</code> is 2.
+ */
+ public static final int CM_DELETED = 2;
+ /**
+ * Type of this event.
+ *
+ * @see #getType
+ */
+ private final int type;
+ /**
+ * The factory pid associated with this event.
+ */
+ private final String factoryPid;
+ /**
+ * The pid associated with this event.
+ */
+ private final String pid;
+ /**
+ * The ConfigurationAdmin service which created this event.
+ */
+ private final ServiceReference reference;
+
+ /**
+ * Constructs a <code>ConfigurationEvent</code> object from the given
+ * <code>ServiceReference</code> object, event type, and pids.
+ *
+ * @param reference The <code>ServiceReference</code> object of the
+ * Configuration Admin service that created this event.
+ * @param type The event type. See {@link #getType}.
+ * @param factoryPid The factory pid of the associated configuration if the
+ * target of the configuration is a ManagedServiceFactory. Otherwise
+ * <code>null</code> if the target of the configuration is a
+ * ManagedService.
+ * @param pid The pid of the associated configuration.
+ */
+ public ConfigurationEvent(ServiceReference reference, int type,
+ String factoryPid, String pid) {
+ this.reference = reference;
+ this.type = type;
+ this.factoryPid = factoryPid;
+ this.pid = pid;
+ }
+
+ /**
+ * Returns the factory pid of the associated configuration.
+ *
+ * @return Returns the factory pid of the associated configuration if the
+ * target of the configuration is a ManagedServiceFactory. Otherwise
+ * <code>null</code> if the target of the configuration is a
+ * ManagedService.
+ */
+ public String getFactoryPid() {
+ return factoryPid;
+ }
+
+ /**
+ * Returns the pid of the associated configuration.
+ *
+ * @return Returns the pid of the associated configuration.
+ */
+ public String getPid() {
+ return pid;
+ }
+
+ /**
+ * Return the type of this event.
+ * <p>
+ * The type values are:
+ * <ul>
+ * <li>{@link #CM_UPDATED}
+ * <li>{@link #CM_DELETED}
+ * </ul>
+ *
+ * @return The type of this event.
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Return the <code>ServiceReference</code> object of the Configuration
+ * Admin service that created this event.
+ *
+ * @return The <code>ServiceReference</code> object for the Configuration
+ * Admin service that created this event.
+ */
+ public ServiceReference getReference() {
+ return reference;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationException.java b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationException.java
new file mode 100644
index 0000000..6d41dce
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationException.java
@@ -0,0 +1,112 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationException.java,v 1.11 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+/**
+ * An <code>Exception</code> class to inform the Configuration Admin service
+ * of problems with configuration data.
+ *
+ * @version $Revision: 1.11 $
+ */
+public class ConfigurationException extends Exception {
+ static final long serialVersionUID = -1690090413441769377L;
+
+ private String property;
+ private String reason;
+
+ /**
+ * Nested exception.
+ */
+ private Throwable cause;
+
+ /**
+ * Create a <code>ConfigurationException</code> object.
+ *
+ * @param property name of the property that caused the problem,
+ * <code>null</code> if no specific property was the cause
+ * @param reason reason for failure
+ */
+ public ConfigurationException(String property, String reason) {
+ super(property + " : " + reason);
+ this.property = property;
+ this.reason = reason;
+ this.cause = null;
+ }
+
+ /**
+ * Create a <code>ConfigurationException</code> object.
+ *
+ * @param property name of the property that caused the problem,
+ * <code>null</code> if no specific property was the cause
+ * @param reason reason for failure
+ * @param cause The cause of this exception.
+ * @since 1.2
+ */
+ public ConfigurationException(String property, String reason,
+ Throwable cause) {
+ super(property + " : " + reason);
+ this.property = property;
+ this.reason = reason;
+ this.cause = cause;
+ }
+
+ /**
+ * Return the property name that caused the failure or null.
+ *
+ * @return name of property or null if no specific property caused the
+ * problem
+ */
+ public String getProperty() {
+ return property;
+ }
+
+ /**
+ * Return the reason for this exception.
+ *
+ * @return reason of the failure
+ */
+ public String getReason() {
+ return reason;
+ }
+
+ /**
+ * Returns the cause of this exception or <code>null</code> if no cause
+ * was specified when this exception was created.
+ *
+ * @return The cause of this exception or <code>null</code> if no cause
+ * was specified.
+ * @since 1.2
+ */
+ public Throwable getCause() {
+ return cause;
+ }
+
+ /**
+ * The cause of this exception can only be set when constructed.
+ *
+ * @param cause Cause of the exception.
+ * @return This object.
+ * @throws java.lang.IllegalStateException This method will always throw an
+ * <code>IllegalStateException</code> since the cause of this
+ * exception can only be set when constructed.
+ * @since 1.2
+ */
+ public Throwable initCause(Throwable cause) {
+ throw new IllegalStateException();
+ }
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationListener.java b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationListener.java
new file mode 100644
index 0000000..f7fb6a6
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationListener.java
@@ -0,0 +1,50 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationListener.java,v 1.9 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2005). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+/**
+ * Listener for Configuration Events. When a <code>ConfigurationEvent</code>
+ * is fired, it is asynchronously delivered to a
+ * <code>ConfigurationListener</code>.
+ *
+ * <p>
+ * <code>ConfigurationListener</code> objects are registered with the
+ * Framework service registry and are notified with a
+ * <code>ConfigurationEvent</code> object when an event is fired.
+ * <p>
+ * <code>ConfigurationListener</code> objects can inspect the received
+ * <code>ConfigurationEvent</code> object to determine its type, the pid of
+ * the <code>Configuration</code> object with which it is associated, and the
+ * Configuration Admin service that fired the event.
+ *
+ * <p>
+ * Security Considerations. Bundles wishing to monitor configuration events will
+ * require <code>ServicePermission[ConfigurationListener,REGISTER]</code> to
+ * register a <code>ConfigurationListener</code> service.
+ *
+ * @version $Revision: 1.9 $
+ * @since 1.2
+ */
+public interface ConfigurationListener {
+ /**
+ * Receives notification of a Configuration that has changed.
+ *
+ * @param event The <code>ConfigurationEvent</code>.
+ */
+ public void configurationEvent(ConfigurationEvent event);
+}
\ No newline at end of file
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationPermission.java b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationPermission.java
new file mode 100644
index 0000000..dc0c6ec
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationPermission.java
@@ -0,0 +1,217 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationPermission.java,v 1.20 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2004, 2005). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import java.security.*;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * Indicates a bundle's authority to configure bundles.
+ *
+ * This permission has only a single action: CONFIGURE.
+ *
+ * @version $Revision: 1.20 $
+ * @since 1.2
+ */
+
+public final class ConfigurationPermission extends BasicPermission {
+ static final long serialVersionUID = 5716868734811965383L;
+ /**
+ * The action string <code>configure</code>.
+ */
+ public final static String CONFIGURE = "configure";
+
+ /**
+ * Create a new ConfigurationPermission.
+ *
+ * @param name Name must be "*".
+ * @param actions <code>configure</code> (canonical order).
+ */
+
+ public ConfigurationPermission(String name, String actions) {
+ super(name);
+ if (!name.equals("*")) {
+ throw new IllegalArgumentException("name must be *");
+ }
+ actions = actions.trim();
+ if (actions.equalsIgnoreCase(CONFIGURE)||actions.equals("*"))
+ return;
+
+ throw new IllegalArgumentException("actions must be " + CONFIGURE);
+ }
+
+ /**
+ * Determines if a <code>ConfigurationPermission</code> object "implies"
+ * the specified permission.
+ *
+ * @param p The target permission to check.
+ * @return <code>true</code> if the specified permission is implied by
+ * this object; <code>false</code> otherwise.
+ */
+
+ public boolean implies(Permission p) {
+ return p instanceof ConfigurationPermission;
+ }
+
+ /**
+ * Determines the equality of two <code>ConfigurationPermission</code>
+ * objects.
+ * <p>
+ * Two <code>ConfigurationPermission</code> objects are equal.
+ *
+ * @param obj The object being compared for equality with this object.
+ * @return <code>true</code> if <code>obj</code> is equivalent to this
+ * <code>ConfigurationPermission</code>; <code>false</code>
+ * otherwise.
+ */
+ public boolean equals(Object obj) {
+ return obj instanceof ConfigurationPermission;
+ }
+
+ /**
+ * Returns the hash code value for this object.
+ *
+ * @return Hash code value for this object.
+ */
+
+ public int hashCode() {
+ return getName().hashCode() ^ getActions().hashCode();
+ }
+
+ /**
+ * Returns the canonical string representation of the
+ * <code>ConfigurationPermission</code> actions.
+ *
+ * <p>
+ * Always returns present <code>ConfigurationPermission</code> actions in
+ * the following order: <code>CONFIGURE</code>
+ *
+ * @return Canonical string representation of the
+ * <code>ConfigurationPermission</code> actions.
+ */
+ public String getActions() {
+ return CONFIGURE;
+ }
+
+ /**
+ * Returns a new <code>PermissionCollection</code> object suitable for
+ * storing <code>ConfigurationPermission</code>s.
+ *
+ * @return A new <code>PermissionCollection</code> object.
+ */
+ public PermissionCollection newPermissionCollection() {
+ return new ConfigurationPermissionCollection();
+ }
+}
+
+/**
+ * Stores a set of <code>ConfigurationPermission</code> permissions.
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ */
+final class ConfigurationPermissionCollection extends PermissionCollection {
+ static final long serialVersionUID = -6917638867081695839L;
+ /**
+ * True if collection is non-empty.
+ *
+ * @serial
+ */
+ private boolean hasElement;
+
+ /**
+ * Creates an empty <tt>ConfigurationPermissionCollection</tt> object.
+ *
+ */
+ public ConfigurationPermissionCollection() {
+ hasElement = false;
+ }
+
+ /**
+ * Adds the specified permission to the
+ * <tt>ConfigurationPermissionCollection</tt>. The key for the hash is
+ * the interface name of the service.
+ *
+ * @param permission The <tt>Permission</tt> object to add.
+ *
+ * @exception IllegalArgumentException If the permission is not an
+ * <tt>ConfigurationPermission</tt>.
+ *
+ * @exception SecurityException If this ConfigurationPermissionCollection
+ * object has been marked read-only.
+ */
+
+ public void add(Permission permission) {
+ if (!(permission instanceof ConfigurationPermission)) {
+ throw new IllegalArgumentException("invalid permission: "
+ + permission);
+ }
+
+ if (isReadOnly())
+ throw new SecurityException("attempt to add a Permission to a "
+ + "readonly PermissionCollection");
+
+ hasElement = true;
+ }
+
+ /**
+ * Determines if the specified set of permissions implies the permissions
+ * expressed in the parameter <tt>permission</tt>.
+ *
+ * @param p The Permission object to compare.
+ *
+ * @return true if permission is a proper subset of a permission in the set;
+ * false otherwise.
+ */
+
+ public boolean implies(Permission p) {
+ return hasElement && (p instanceof ConfigurationPermission);
+ }
+
+ /**
+ * Returns an enumeration of an <tt>ConfigurationPermission</tt> object.
+ *
+ * @return Enumeration of an <tt>ConfigurationPermission</tt> object.
+ */
+
+ public Enumeration elements() {
+ return new Enumeration() {
+ private boolean more = hasElement;
+
+ public boolean hasMoreElements() {
+ return more;
+ }
+
+ public Object nextElement() {
+ if (more) {
+ more = false;
+
+ return new ConfigurationPermission("*",
+ ConfigurationPermission.CONFIGURE);
+ }
+ else {
+ throw new NoSuchElementException();
+ }
+ }
+ };
+ }
+
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationPlugin.java b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationPlugin.java
new file mode 100644
index 0000000..089e626
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ConfigurationPlugin.java
@@ -0,0 +1,131 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ConfigurationPlugin.java,v 1.10 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A service interface for processing configuration dictionary before the
+ * update.
+ *
+ * <p>
+ * A bundle registers a <code>ConfigurationPlugin</code> object in order to
+ * process configuration updates before they reach the Managed Service or
+ * Managed Service Factory. The Configuration Admin service will detect
+ * registrations of Configuration Plugin services and must call these services
+ * every time before it calls the <code>ManagedService</code> or
+ * <code>ManagedServiceFactory</code>
+ * <code>updated</code> method. The
+ * Configuration Plugin service thus has the opportunity to view and modify the
+ * properties before they are passed to the ManagedS ervice or Managed Service
+ * Factory.
+ *
+ * <p>
+ * Configuration Plugin (plugin) services have full read/write access to all
+ * configuration information. Therefore, bundles using this facility should be
+ * trusted. Access to this facility should be limited with
+ * <code>ServicePermission[ConfigurationPlugin,REGISTER]</code>.
+ * Implementations of a Configuration Plugin service should assure that they
+ * only act on appropriate configurations.
+ *
+ * <p>
+ * The <code>Integer</code> <code>service.cmRanking</code> registration
+ * property may be specified. Not specifying this registration property, or
+ * setting it to something other than an <code>Integer</code>, is the same as
+ * setting it to the <code>Integer</code> zero. The
+ * <code>service.cmRanking</code> property determines the order in which
+ * plugins are invoked. Lower ranked plugins are called before higher ranked
+ * ones. In the event of more than one plugin having the same value of
+ * <code>service.cmRanking</code>, then the Configuration Admin service
+ * arbitrarily chooses the order in which they are called.
+ *
+ * <p>
+ * By convention, plugins with <code>service.cmRanking< 0</code> or
+ * <code>service.cmRanking > 1000</code> should not make modifications to
+ * the properties.
+ *
+ * <p>
+ * The Configuration Admin service has the right to hide properties from
+ * plugins, or to ignore some or all the changes that they make. This might be
+ * done for security reasons. Any such behavior is entirely implementation
+ * defined.
+ *
+ * <p>
+ * A plugin may optionally specify a <code>cm.target</code> registration
+ * property whose value is the PID of the Managed Service or Managed Service
+ * Factory whose configuration updates the plugin is intended to intercept. The
+ * plugin will then only be called with configuration updates that are targetted
+ * at the Managed Service or Managed Service Factory with the specified PID.
+ * Omitting the <code>cm.target</code> registration property means that the
+ * plugin is called for all configuration updates.
+ *
+ * @version $Revision: 1.10 $
+ */
+public interface ConfigurationPlugin {
+ /**
+ * A service property to limit the Managed Service or Managed Service
+ * Factory configuration dictionaries a Configuration Plugin service
+ * receives.
+ *
+ * This property contains a <code>String[]</code> of PIDs. A Configuration
+ * Admin service must call a Configuration Plugin service only when this
+ * property is not set, or the target service's PID is listed in this
+ * property.
+ */
+ public static final String CM_TARGET = "cm.target";
+ /**
+ * A service property to specify the order in which plugins are invoked.
+ *
+ * This property contains an <code>Integer</code> ranking of the plugin.
+ * Not specifying this registration property, or setting it to something
+ * other than an <code>Integer</code>, is the same as setting it to the
+ * <code>Integer</code> zero. This property determines the order in which
+ * plugins are invoked. Lower ranked plugins are called before higher ranked
+ * ones.
+ *
+ * @since 1.2
+ */
+ public static final String CM_RANKING = "service.cmRanking";
+
+ /**
+ * View and possibly modify the a set of configuration properties before
+ * they are sent to the Managed Service or the Managed Service Factory. The
+ * Configuration Plugin services are called in increasing order of their
+ * <code>service.cmRanking</code> property. If this property is undefined
+ * or is a non- <code>Integer</code> type, 0 is used.
+ *
+ * <p>
+ * This method should not modify the properties unless the
+ * <code>service.cmRanking</code> of this plugin is in the range
+ * <code>0 <= service.cmRanking <= 1000</code>.
+ * <p>
+ * If this method throws any <code>Exception</code>, the Configuration
+ * Admin service must catch it and should log it.
+ *
+ * @param reference reference to the Managed Service or Managed Service
+ * Factory
+ * @param properties The configuration properties. This argument must not
+ * contain the "service.bundleLocation" property. The value of this
+ * property may be obtained from the
+ * <code>Configuration.getBundleLocation</code> method.
+ */
+ public void modifyConfiguration(ServiceReference reference,
+ Dictionary properties);
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ManagedService.java b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ManagedService.java
new file mode 100644
index 0000000..b5ccce4
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ManagedService.java
@@ -0,0 +1,140 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ManagedService.java,v 1.11 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import java.util.Dictionary;
+
+/**
+ * A service that can receive configuration data from a Configuration Admin
+ * service.
+ *
+ * <p>
+ * A Managed Service is a service that needs configuration data. Such an object
+ * should be registered with the Framework registry with the
+ * <code>service.pid</code> property set to some unique identitifier called a
+ * PID.
+ *
+ * <p>
+ * If the Configuration Admin service has a <code>Configuration</code> object
+ * corresponding to this PID, it will callback the <code>updated()</code>
+ * method of the <code>ManagedService</code> object, passing the properties of
+ * that <code>Configuration</code> object.
+ *
+ * <p>
+ * If it has no such <code>Configuration</code> object, then it calls back
+ * with a <code>null</code> properties argument. Registering a Managed Service
+ * will always result in a callback to the <code>updated()</code> method
+ * provided the Configuration Admin service is, or becomes active. This callback
+ * must always be done asynchronously.
+ *
+ * <p>
+ * Else, every time that either of the <code>updated()</code> methods is
+ * called on that <code>Configuration</code> object, the
+ * <code>ManagedService.updated()</code> method with the new properties is
+ * called. If the <code>delete()</code> method is called on that
+ * <code>Configuration</code> object, <code>ManagedService.updated()</code>
+ * is called with a <code>null</code> for the properties parameter. All these
+ * callbacks must be done asynchronously.
+ *
+ * <p>
+ * The following example shows the code of a serial port that will create a port
+ * depending on configuration information.
+ *
+ * <pre>
+ *
+ * class SerialPort implements ManagedService {
+ *
+ * ServiceRegistration registration;
+ * Hashtable configuration;
+ * CommPortIdentifier id;
+ *
+ * synchronized void open(CommPortIdentifier id,
+ * BundleContext context) {
+ * this.id = id;
+ * registration = context.registerService(
+ * ManagedService.class.getName(),
+ * this,
+ * getDefaults()
+ * );
+ * }
+ *
+ * Hashtable getDefaults() {
+ * Hashtable defaults = new Hashtable();
+ * defaults.put( "port", id.getName() );
+ * defaults.put( "product", "unknown" );
+ * defaults.put( "baud", "9600" );
+ * defaults.put( Constants.SERVICE_PID,
+ * "com.acme.serialport." + id.getName() );
+ * return defaults;
+ * }
+ *
+ * public synchronized void updated(
+ * Dictionary configuration ) {
+ * if ( configuration ==
+ * <code>
+ * null
+ * </code>
+ * )
+ * registration.setProperties( getDefaults() );
+ * else {
+ * setSpeed( configuration.get("baud") );
+ * registration.setProperties( configuration );
+ * }
+ * }
+ * ...
+ * }
+ *
+ * </pre>
+ *
+ * <p>
+ * As a convention, it is recommended that when a Managed Service is updated, it
+ * should copy all the properties it does not recognize into the service
+ * registration properties. This will allow the Configuration Admin service to
+ * set properties on services which can then be used by other applications.
+ *
+ * @version $Revision: 1.11 $
+ */
+public interface ManagedService {
+ /**
+ * Update the configuration for a Managed Service.
+ *
+ * <p>
+ * When the implementation of <code>updated(Dictionary)</code> detects any
+ * kind of error in the configuration properties, it should create a new
+ * <code>ConfigurationException</code> which describes the problem. This
+ * can allow a management system to provide useful information to a human
+ * administrator.
+ *
+ * <p>
+ * If this method throws any other <code>Exception</code>, the
+ * Configuration Admin service must catch it and should log it.
+ * <p>
+ * The Configuration Admin service must call this method asynchronously
+ * which initiated the callback. This implies that implementors of Managed
+ * Service can be assured that the callback will not take place during
+ * registration when they execute the registration in a synchronized method.
+ *
+ * @param properties A copy of the Configuration properties, or
+ * <code>null</code>. This argument must not contain the
+ * "service.bundleLocation" property. The value of this property may
+ * be obtained from the <code>Configuration.getBundleLocation</code>
+ * method.
+ * @throws ConfigurationException when the update fails
+ */
+ public void updated(Dictionary properties) throws ConfigurationException;
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ManagedServiceFactory.java b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ManagedServiceFactory.java
new file mode 100644
index 0000000..001ddd8
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/ManagedServiceFactory.java
@@ -0,0 +1,162 @@
+/*
+ * $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/ManagedServiceFactory.java,v 1.10 2006/03/14 01:21:09 hargrave Exp $
+ *
+ * Copyright (c) OSGi Alliance (2001, 2005). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import java.util.Dictionary;
+
+/**
+ * Manage multiple service instances.
+ *
+ * Bundles registering this interface are giving the Configuration Admin service
+ * the ability to create and configure a number of instances of a service that
+ * the implementing bundle can provide. For example, a bundle implementing a
+ * DHCP server could be instantiated multiple times for different interfaces
+ * using a factory.
+ *
+ * <p>
+ * Each of these <i>service instances </i> is represented, in the persistent
+ * storage of the Configuration Admin service, by a factory
+ * <code>Configuration</code> object that has a PID. When such a
+ * <code>Configuration</code> is updated, the Configuration Admin service
+ * calls the <code>ManagedServiceFactory</code> updated method with the new
+ * properties. When <code>updated</code> is called with a new PID, the Managed
+ * Service Factory should create a new factory instance based on these
+ * configuration properties. When called with a PID that it has seen before, it
+ * should update that existing service instance with the new configuration
+ * information.
+ *
+ * <p>
+ * In general it is expected that the implementation of this interface will
+ * maintain a data structure that maps PIDs to the factory instances that it has
+ * created. The semantics of a factory instance are defined by the Managed
+ * Service Factory. However, if the factory instance is registered as a service
+ * object with the service registry, its PID should match the PID of the
+ * corresponding <code>Configuration</code> object (but it should <b>not </b>
+ * be registered as a Managed Service!).
+ *
+ * <p>
+ * An example that demonstrates the use of a factory. It will create serial
+ * ports under command of the Configuration Admin service.
+ *
+ * <pre>
+ *
+ * class SerialPortFactory
+ * implements ManagedServiceFactory {
+ * ServiceRegistration registration;
+ * Hashtable ports;
+ * void start(BundleContext context) {
+ * Hashtable properties = new Hashtable();
+ * properties.put( Constants.SERVICE_PID,
+ * "com.acme.serialportfactory" );
+ * registration = context.registerService(
+ * ManagedServiceFactory.class.getName(),
+ * this,
+ * properties
+ * );
+ * }
+ * public void updated( String pid,
+ * Dictionary properties ) {
+ * String portName = (String) properties.get("port");
+ * SerialPortService port =
+ * (SerialPort) ports.get( pid );
+ * if ( port == null ) {
+ * port = new SerialPortService();
+ * ports.put( pid, port );
+ * port.open();
+ * }
+ * if ( port.getPortName().equals(portName) )
+ * return;
+ * port.setPortName( portName );
+ * }
+ * public void deleted( String pid ) {
+ * SerialPortService port =
+ * (SerialPort) ports.get( pid );
+ * port.close();
+ * ports.remove( pid );
+ * }
+ * ...
+ * }
+ *
+ * </pre>
+ *
+ * @version $Revision: 1.10 $
+ */
+public interface ManagedServiceFactory {
+ /**
+ * Return a descriptive name of this factory.
+ *
+ * @return the name for the factory, which might be localized
+ */
+ public String getName();
+
+ /**
+ * Create a new instance, or update the configuration of an existing
+ * instance.
+ *
+ * If the PID of the <code>Configuration</code> object is new for the
+ * Managed Service Factory, then create a new factory instance, using the
+ * configuration <code>properties</code> provided. Else, update the
+ * service instance with the provided <code>properties</code>.
+ *
+ * <p>
+ * If the factory instance is registered with the Framework, then the
+ * configuration <code>properties</code> should be copied to its registry
+ * properties. This is not mandatory and security sensitive properties
+ * should obviously not be copied.
+ *
+ * <p>
+ * If this method throws any <code>Exception</code>, the Configuration
+ * Admin service must catch it and should log it.
+ *
+ * <p>
+ * When the implementation of updated detects any kind of error in the
+ * configuration properties, it should create a new
+ * {@link ConfigurationException}which describes the problem.
+ *
+ * <p>
+ * The Configuration Admin service must call this method asynchronously.
+ * This implies that implementors of the <code>ManagedServiceFactory</code>
+ * class can be assured that the callback will not take place during
+ * registration when they execute the registration in a synchronized method.
+ *
+ * @param pid The PID for this configuration.
+ * @param properties A copy of the configuration properties. This argument
+ * must not contain the service.bundleLocation" property. The value
+ * of this property may be obtained from the
+ * <code>Configuration.getBundleLocation</code> method.
+ * @throws ConfigurationException when the configuration properties are
+ * invalid.
+ */
+ public void updated(String pid, Dictionary properties)
+ throws ConfigurationException;
+
+ /**
+ * Remove a factory instance.
+ *
+ * Remove the factory instance associated with the PID. If the instance was
+ * registered with the service registry, it should be unregistered.
+ * <p>
+ * If this method throws any <code>Exception</code>, the Configuration
+ * Admin service must catch it and should log it.
+ * <p>
+ * The Configuration Admin service must call this method asynchronously.
+ *
+ * @param pid the PID of the service to be removed
+ */
+ public void deleted(String pid);
+}
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/package.html b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/package.html
new file mode 100644
index 0000000..3f65348
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/package.html
@@ -0,0 +1,11 @@
+<!-- $Header: /cvshome/build/org.osgi.service.cm/src/org/osgi/service/cm/package.html,v 1.2 2004/12/01 19:01:11 hargrave Exp $ -->
+<BODY>
+<P>The OSGi Configuration Admin service Package. Specification Version 1.2
+<p>Bundles wishing to use this package must list the package
+in the Import-Package header of the bundle's manifest.
+For example:
+<pre>
+Import-Package: org.osgi.service.cm; version=1.2
+</pre>
+</BODY>
+
diff --git a/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/packageinfo b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/packageinfo
new file mode 100644
index 0000000..ef7df68
--- /dev/null
+++ b/org.apache.felix.ipojo/src/main/java/org/osgi/service/cm/packageinfo
@@ -0,0 +1 @@
+version 1.2