Ported servicebinder code:
o package updates to org.apache.felix.servicebinder
o non-invasive IDE warning fixes
o author tag to felix dev list
o M2 POM to provide initial install support
o license update to ASL 2.0
o kxml update to 1.21
o svn ignores
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@388786 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.servicebinder/pom.xml b/org.apache.felix.servicebinder/pom.xml
new file mode 100644
index 0000000..a21263f
--- /dev/null
+++ b/org.apache.felix.servicebinder/pom.xml
@@ -0,0 +1,60 @@
+<project>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix</artifactId>
+ <version>0.8.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>osgi-bundle</packaging>
+ <name>Apache Felix Service Binder</name>
+ <artifactId>org.apache.felix.servicebinder</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>${pom.groupId}</groupId>
+ <artifactId>org.osgi</artifactId>
+ <version>${pom.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>kxml</groupId>
+ <artifactId>kxml</artifactId>
+ <version>1.21</version>
+ <scope>required</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix.plugins</groupId>
+ <artifactId>maven-osgi-plugin</artifactId>
+ <version>${pom.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <osgiManifest>
+ <entries>
+ <property>
+ <name>Metadata-Location</name>
+ <value>metadata.xml</value>
+ </property>
+ </entries>
+ <bundleName>Service Binder</bundleName>
+ <bundleVendor>Apache Software Foundation</bundleVendor>
+ <!--<bundleVersion>1.1.2</bundleVersion>-->
+ <bundleDescription>
+ This bundle provides a mechanism to automate service dependency management.
+ </bundleDescription>
+ <bundleActivator>
+ org.apache.felix.servicebinder.impl.Activator
+ </bundleActivator>
+ <exportPackage>
+ org.apache.felix.servicebinder; specification-version="1.1.0",org.apache.felix.servicebinder.architecture; specification-version="1.1.0"
+ </exportPackage>
+ <metadataLocation>
+ metadata.xml
+ </metadataLocation>
+ </osgiManifest>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/DependencyMetadata.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/DependencyMetadata.java
new file mode 100644
index 0000000..8ce80d1
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/DependencyMetadata.java
@@ -0,0 +1,167 @@
+/*
+ * 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.servicebinder;
+
+/**
+ * Metadata of a dependency
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class DependencyMetadata
+{
+ private String m_serviceName = "";
+ private String m_filter = "";
+ private String m_bindMethod = "";
+ private String m_unbindMethod = "";
+ private String m_cardinality = "";
+ private String m_policy = "";
+
+ private boolean m_isStatic = true;
+ private boolean m_isOptional = false;
+ private boolean m_isMultiple = false;
+
+ /**
+ * Constructor
+ *
+ **/
+ DependencyMetadata(String servicename,String cardinality,String policy,String filter,String bindmethod,String unbindmethod)
+ {
+ m_serviceName = servicename;
+
+ String classnamefilter = "(objectClass="+servicename+")";
+
+ if(filter.equals("") == false)
+ {
+ m_filter = "(&"+classnamefilter+filter+")";
+ }
+ else
+ {
+ m_filter = classnamefilter;
+ }
+
+ m_bindMethod = bindmethod;
+ m_unbindMethod = unbindmethod;
+ m_cardinality = cardinality;
+ m_policy = policy;
+
+ if(policy.equals("static") == false)
+ {
+ m_isStatic = false;
+ }
+
+ if(cardinality.equals("0..1") || cardinality.equals("0..n"))
+ {
+ m_isOptional = true;
+ }
+
+ if(cardinality.equals("0..n") || cardinality.equals("1..n"))
+ {
+ m_isMultiple = true;
+ }
+ }
+
+ /**
+ * Returns the name of the required service
+ *
+ * @return the name of the required service
+ **/
+ public String getServiceName()
+ {
+ return m_serviceName;
+ }
+
+ /**
+ * Returns the filter
+ *
+ * @return A string with the filter
+ **/
+ public String getFilter()
+ {
+ return m_filter;
+ }
+
+ /**
+ * Get the name of the Bind method
+ *
+ * @return a String with the name of the BindMethod
+ **/
+ public String getBindMethodName()
+ {
+ return m_bindMethod;
+ }
+
+ /**
+ * Get the name of the Unbind method
+ *
+ * @return a String with the name of the Unbind method
+ **/
+ public String getUnbindMethodName()
+ {
+ return m_unbindMethod;
+ }
+
+
+ /**
+ * Test if dependency's binding policy is static
+ *
+ * @return true if static
+ **/
+ public boolean isStatic()
+ {
+ return m_isStatic;
+ }
+
+ /**
+ * Test if dependency is optional (0..1 or 0..n)
+ *
+ * @return true if the dependency is optional
+ **/
+ public boolean isOptional()
+ {
+ return m_isOptional;
+ }
+
+ /**
+ * Test if dependency is multiple (0..n or 1..n)
+ *
+ * @return true if the dependency is multiple
+ **/
+ public boolean isMultiple()
+ {
+ return m_isMultiple;
+ }
+
+ /**
+ * Get the cardinality as a string
+ *
+ * @return the cardinality
+ **/
+ public String getCardinality()
+ {
+ return m_cardinality;
+ }
+
+ /**
+ * Get the policy as a string
+ *
+ * @return the policy
+ **/
+ public String getPolicy()
+ {
+ return m_policy;
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/GenericActivator.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/GenericActivator.java
new file mode 100644
index 0000000..32c17a7
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/GenericActivator.java
@@ -0,0 +1,328 @@
+/*
+ * 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.servicebinder;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import java.io.InputStream;
+
+import org.apache.felix.servicebinder.architecture.DependencyChangeEvent;
+import org.apache.felix.servicebinder.architecture.InstanceChangeEvent;
+import org.apache.felix.servicebinder.impl.ArchitectureServiceImpl;
+import org.apache.felix.servicebinder.parser.KxmlParser;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+/**
+ * The GenericActivator, it will read information from the metadata.xml file
+ * and will create the corresponding instance managers
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+abstract public class GenericActivator implements BundleActivator
+{
+ private BundleContext m_context = null;
+ private List m_instanceManagers = new ArrayList();
+
+ private static boolean m_trace = false;
+ private static boolean m_error = true;
+
+ private static String m_version = "1.1.1 (17062004)";
+
+ // Static initializations based on system properties
+ static {
+ // Get system properties to see if traces or errors need to be displayed
+ String result = System.getProperty("servicebinder.showtrace");
+ if(result != null && result.equals("true"))
+ {
+ m_trace = true;
+ }
+ result = System.getProperty("servicebinder.showerrors");
+ if(result != null && result.equals("false"))
+ {
+ m_error = false;
+ }
+ result = System.getProperty("servicebinder.showversion");
+ if(result != null && result.equals("true"))
+ {
+ System.out.println("[ ServiceBinder version = "+m_version+" ]\n");
+ }
+ }
+
+ public GenericActivator()
+ {
+ }
+
+ /**
+ * Called upon starting of the bundle. This method invokes initialize() which
+ * parses the meta data and creates the instance managers
+ *
+ * @param context The bundle context passed by the framework
+ * @exception Exception any exception thrown from initialize
+ */
+ public void start(BundleContext context) throws Exception
+ {
+ m_context = context;
+ try
+ {
+ initialize();
+ }
+ catch (Exception e)
+ {
+ GenericActivator.error("GenericActivator : in bundle ["
+ + context.getBundle().getBundleId() + "] : " + e);
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ /**
+ * Gets the MetaData location, parses the meta data and requests the processing
+ * of binder instances
+ *
+ * @throws java.io.FileNotFoundException if the metadata file is not found
+ * @throws javax.xml.parsers.ParserConfigurationException
+ * @throws org.xml.sax.SAXException
+ * @throws java.io.IOException
+ * @throws java.lang.ClassNotFoundException it the instance class is not found
+ * @throws java.lang.NoSuchMethodException if binder methods are not found
+ * @throws org.osgi.framework.InvalidSyntaxException if the filter has an incorrect syntax
+ * @throws Exception if any exception is thrown during the validation of the InstanceManagers
+ */
+ private void initialize() throws Exception
+ {
+ // Get the Metadata-Location value from the manifest
+
+ String metadataLocation = "";
+ //Dictionary dict = m_context.getBundle().getHeaders();
+
+ metadataLocation = (String) m_context.getBundle().getHeaders().get("Metadata-Location");
+
+ if (metadataLocation == null)
+ {
+ throw new java.io.FileNotFoundException("Metadata-Location entry not found in the manifest");
+ }
+
+ if (metadataLocation.startsWith("/") == false)
+ {
+ metadataLocation="/"+metadataLocation;
+ }
+
+ InputStream stream = getClass().getResourceAsStream(metadataLocation);
+
+ if (stream == null)
+ {
+ throw new java.io.FileNotFoundException("MetaData file not found at:"+metadataLocation);
+ }
+
+ // Create the parser
+
+ XmlHandler handler = new XmlHandler();
+ BufferedReader in = new BufferedReader(new InputStreamReader(stream));
+ KxmlParser parser = new KxmlParser(in);
+
+ parser.parseXML(handler);
+
+ // Create An instance manager for every entry
+
+ Iterator i = handler.getInstanceMetadatas().iterator();
+
+ while (i.hasNext())
+ {
+ InstanceMetadata descriptor = (InstanceMetadata) i.next();
+
+ if(descriptor.isFactory())
+ {
+ // NOT YET SUPPORTED IN THIS VERSION
+ }
+ else // deployment instance
+ {
+ // create the instance manager
+ InstanceManager currentinstance = new InstanceManager(this,descriptor);
+ // start managing lifecycle
+ currentinstance.validate();
+ }
+ }
+ }
+
+ /**
+ * Stop method that destroys all the instance managers
+ *
+ * @param context The Bundle Context passed by the framework
+ * @exception Exception any exception thrown during destruction of the instance managers
+ */
+ public void stop(BundleContext context) throws java.lang.Exception
+ {
+ GenericActivator.trace("GenericActivator : Bundle ["+context.getBundle().getBundleId()+"] will destroy "+m_instanceManagers.size()+" instances");
+
+ while (m_instanceManagers.size() !=0 )
+ {
+ InstanceManager current = (InstanceManager)m_instanceManagers.get(0);
+ try
+ {
+ current.destroy();
+ }
+ catch(Exception e)
+ {
+ GenericActivator.error("GenericActivator : Exception during invalidate : "+e);
+ e.printStackTrace();
+ }
+ }
+
+ m_context = null;
+
+ GenericActivator.trace("GenericActivator : Bundle ["+context.getBundle().getBundleId()+"] STOPPED");
+ }
+
+ /**
+ * Returns the list of instance references currently associated to this activator
+ *
+ * @return the list of instance references
+ */
+ protected List getInstanceReferences()
+ {
+ return m_instanceManagers;
+ }
+
+ /**
+ * Returns the BundleContext
+ *
+ * @return the BundleContext
+ */
+ protected BundleContext getBundleContext()
+ {
+ return m_context;
+ }
+
+ /**
+ * Add an instance manager to the list
+ *
+ * @param instance an instance manager
+ */
+ synchronized void addInstanceManager(InstanceManager instance)
+ {
+ ArchitectureServiceImpl.addInstanceReference(instance);
+
+ m_instanceManagers.add(instance);
+ }
+
+ /**
+ * Removes a binder instance from the list
+ *
+ * @param instance an instance manager
+ */
+ synchronized void removeInstanceManager(InstanceManager instance)
+ {
+ ArchitectureServiceImpl.removeInstanceReference(instance);
+
+ m_instanceManagers.remove(instance);
+ }
+
+ /**
+ * Method to display traces
+ *
+ * @param s a string to be displayed
+ **/
+ static void trace(String s)
+ {
+ if(m_trace)
+ {
+ System.out.println("--- "+s);
+ }
+ }
+
+ /**
+ * Method to display errors
+ *
+ * @param s a string to be displayed
+ **/
+ static void error(String s)
+ {
+ if(m_error)
+ {
+ System.err.println("### "+s);
+ }
+ }
+
+ /**
+ * Method called before an object implementing services is registered
+ * in the OSGi framework. This method is provided so that subclasses of
+ * the generic activator may proxy the object. The default implementation
+ * returns the passed in object.
+ *
+ * @param obj the instance object
+ * @param descriptor the instance descriptor that provides information relevant to
+ * the instance object
+ **/
+ protected Object proxyProvidedServiceObject(Object obj, InstanceMetadata descriptor)
+ {
+ return obj;
+ }
+
+ /**
+ * Method called before the binding of the service object occurs.
+ * This method is provided so that subclasses of the generic activator
+ * may proxy the object. The default implementation returns the passed in object.
+ *
+ * @param obj the instance object
+ * @param descriptor the dependency descriptor that provides information relevant to
+ * the service object
+ **/
+ protected Object proxyRequiredServiceObject(Object obj, DependencyMetadata descriptor)
+ {
+ return obj;
+ }
+
+ /**
+ * Fires an event when an instance has changed
+ * The generic activator always requests a reference of EvtGeneratorImpl
+ * since this class can be instantiated at anytime since it is
+ * the service implementation.
+ *
+ * @evt The InstanceChangeEvent
+ **/
+ void fireInstanceChangeEvent(InstanceChangeEvent evt)
+ {
+ ArchitectureServiceImpl evtGenerator = ArchitectureServiceImpl.getReference();
+
+ if(evtGenerator != null)
+ {
+ evtGenerator.fireInstanceChangeEvent(evt);
+ }
+ }
+
+ /**
+ * Fires an event when a dependency has changed
+ *
+ * @evt The InstanceChangeEvent
+ **/
+ void fireDependencyChangeEvent(DependencyChangeEvent evt)
+ {
+ ArchitectureServiceImpl evtGenerator = ArchitectureServiceImpl.getReference();
+
+ if(evtGenerator != null)
+ {
+ evtGenerator.fireDependencyChangeEvent(evt);
+ }
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceManager.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceManager.java
new file mode 100644
index 0000000..8bd7eba
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceManager.java
@@ -0,0 +1,1278 @@
+/*
+ * 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.servicebinder;
+
+import java.util.Properties;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+import org.apache.felix.servicebinder.architecture.Dependency;
+import org.apache.felix.servicebinder.architecture.DependencyChangeEvent;
+import org.apache.felix.servicebinder.architecture.Instance;
+import org.apache.felix.servicebinder.architecture.InstanceChangeEvent;
+import org.apache.felix.servicebinder.impl.ArchitectureServiceImpl;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Bundle;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * A InstanceManager is created for every component instance.
*
* When the InstanceManager is instantiated, a collection of DependencyManagers is
* created. Each dependency manager corresponds to a required service
*
* A InstanceManager follows a sequence of clearly defined steps.
*
* 1.- Creation : the binder instance is created, its state becomes CREATED. This step is further divided
* in the following substeps:
* - The binder instance checks if all of the dependencies are valid, if this
* is false, it returns.
* - If the dependendencies are valid, its state becomes executing. The object from
* the instance class is created (if this object receives a ServiceBinderContext as
* a parameter in its constructor, the context is passed to it.
* - The validate() method is called on the dependency managers, this will cause
* calls on the binding methods to occur
* - The binder instance adds itself to the list of binder instances in the activator
* - The binder instance registers the services implemented by the instance object.
*
* 2.- Disposal :
*
* @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+
+public class InstanceManager implements InstanceReference, Instance
+{
+ // The values ranging from 0 to 3 are public and are defined in InstanceReference
+ static final int INSTANCE_CREATING = 4;
+ static final int INSTANCE_VALIDATING = 5;
+ static final int INSTANCE_INVALIDATING = 6;
+ static final int INSTANCE_DESTROYING = 7;
+
+ static final String m_states[]={"CREATED","VALID","INVALID",
+ "DESTROYED","CREATING","VALIDATING",
+ "INVALIDATING","DESTROYING"};
+
+ // The state of this instance manager
+ private int m_state = INSTANCE_CREATING;
+
+ /**
+ *
+ * @uml.property name="m_instanceMetadata"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ // The metadata
+ private InstanceMetadata m_instanceMetadata;
+
+
+ // The object that implements the service and that is bound to other services
+ private Object m_implementorObject;
+
+ // The dependency managers that manage every dependency
+ private List m_dependencyManagers;
+
+ // The ServiceRegistration
+ private ServiceRegistration m_serviceRegistration;
+
+ /**
+ *
+ * @uml.property name="m_activator"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ // A reference to the GenericActivator
+ private GenericActivator m_activator;
+
+ /**
+ *
+ * @uml.property name="m_sbcontext"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ // The context that will be passed to the objects
+ private ServiceBinderContextImpl m_sbcontext;
+
+ /**
+ *
+ * @uml.property name="m_instanceListener"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ // Listeners to validation events
+ private InstanceReferenceListener m_instanceListener = null;
+
+ // Properties that can be attached to te InstanceManager
+ private Properties m_localProperties = new Properties();
+
+ // Flag that indicates that activate was called
+ private boolean m_activateCalled = false;
+
+ /**
+ * Constructor that creates a collection of dependency managers that will be in
+ * charge of the different dependencies for a particular instance.
+ *
+ * @param activator A reference to the generic activator
+ * @param descriptor an InstanceMetadata that contains information found in the descriptor file
+ * @throws java.lang.ClassNotFoundException if the instance class (declared in the descriptor file) is not found
+ * @throws java.lang.NoSuchMethodException if the bind or unbind methods are not found on the instance class
+ * @throws org.osgi.framework.InvalidSyntaxException if the filter declared in the requires entry has an invalid syntax
+ **/
+ InstanceManager(GenericActivator activator,InstanceMetadata descriptor)
+ throws ClassNotFoundException, NoSuchMethodException, InvalidSyntaxException
+ {
+ m_activator = activator;
+
+ m_instanceMetadata = descriptor;
+
+ m_dependencyManagers = new ArrayList();
+
+ if (m_instanceMetadata.getDependencies().size() != 0)
+ {
+ Iterator dependencyit = m_instanceMetadata.getDependencies().iterator();
+
+ while(dependencyit.hasNext())
+ {
+ DependencyMetadata currentdependency = (DependencyMetadata)dependencyit.next();
+
+ DependencyManager depmanager = new DependencyManager(currentdependency);
+
+ m_dependencyManagers.add(depmanager);
+
+ // Register the dependency managers as listeners to service events so that they begin
+ // to manage the dependency autonomously
+
+ m_activator.getBundleContext().addServiceListener(depmanager,depmanager.getDependencyMetadata().getFilter());
+ }
+ }
+
+ m_sbcontext = new ServiceBinderContextImpl(this);
+
+ // Add this instance manager to the Generic activator list
+ m_activator.addInstanceManager(this);
+
+ setState(INSTANCE_CREATED);
+ }
+
+ /**
+ * Validate this Instance manager.
+ *
+ * CONCURRENCY NOTE: This method can be called either after an instance manager is created
+ * or after the instance is validated again after by the instance manager itself
+ */
+ synchronized void validate()
+ {
+ if (m_state == INSTANCE_VALID)
+ {
+ return;
+ }
+ else if (m_state != INSTANCE_INVALID && m_state !=INSTANCE_CREATED)
+ {
+ GenericActivator.error("InstanceManager : create() called for a non INVALID or CREATED InstanceManager ("+m_states[m_state]+")");
+ return;
+ }
+
+ setState(INSTANCE_VALIDATING);
+
+ // Test if all dependency managers are valid
+
+ Iterator it = m_dependencyManagers.iterator();
+
+ while (it.hasNext())
+ {
+ // It is not possible to call the isValid method yet in the DependencyManager
+ // since they have not been initialized yet, but we can't call initialize
+ // since the object where bindings will be done has not been created.
+ // This test is necessary, because we don't want to instantiate
+ // the object if the dependency managers won't be valid.
+ DependencyManager dm = (DependencyManager)it.next();
+ if (dm.getRequiredServiceRefs() == null && dm.getDependencyMetadata().isOptional() == false)
+ {
+ setState(INSTANCE_INVALID);
+ return;
+ }
+ }
+
+ // everything ok to go...
+
+ try
+ {
+ Class c = m_activator.getClass().getClassLoader().loadClass(m_instanceMetadata.getImplementorName());
+ try
+ {
+ Constructor cons = c.getConstructor(new Class[] {ServiceBinderContext.class});
+ m_implementorObject = cons.newInstance(new Object[] {m_sbcontext});
+ }
+ catch(NoSuchMethodException ex)
+ {
+ // Aparently he doesn't want a ServiceBinderContext...
+ }
+
+ // Create from no-param constructor
+ if (m_implementorObject == null)
+ {
+ m_implementorObject = c.newInstance();
+ }
+
+ /* is it a factory?
+ if (m_implementorObject instanceof GenericFactory)
+ {
+ ((GenericFactory) m_implementorObject).setActivator(m_activator, this);
+ }
+ */
+
+ // Allow somebody to proxy the object through the proxyProvidedServiceObject method
+ // in the activator
+ Object proxy = m_activator.proxyProvidedServiceObject(m_implementorObject, this.getInstanceMetadata());
+ if (proxy != null)
+ {
+ m_implementorObject = proxy;
+ }
+ else
+ {
+ GenericActivator.error("InstanceManager : Proxy method returned a null value");
+ }
+ }
+ catch (Throwable t)
+ {
+ // failure at creation
+ GenericActivator.error("InstanceManager : Error during instantiation : "+t);
+ t.printStackTrace();
+ _invalidate();
+ return;
+ }
+
+ // initial bindings
+
+ it = m_dependencyManagers.iterator();
+
+ while (it.hasNext())
+ {
+ DependencyManager dm = (DependencyManager)it.next();
+ if (dm.initialize() == false)
+ {
+ _invalidate();
+ return;
+ }
+ }
+
+ // We need to check if we are still validating because it is possible that when we
+ // registered the service above our thread causes an instance to become valid which
+ // then registered a service that then generated an event that we needed that
+ // caused validate() to be called again, thus if we are not still VALIDATING, it
+ // means we are already VALID.
+ if (m_state == INSTANCE_VALIDATING)
+ {
+ // activate
+
+ if (m_implementorObject instanceof Lifecycle)
+ {
+ try
+ {
+ ((Lifecycle)m_implementorObject).activate();
+ this.m_activateCalled=true;
+ }
+ catch(Exception e)
+ {
+ GenericActivator.error("InstanceManager : exception during activate:"+e);
+ e.printStackTrace();
+ _invalidate();
+ return;
+ }
+ }
+
+ // validated!
+
+ fireInstanceReferenceValidated();
+ setState(INSTANCE_VALID);
+ }
+
+
+ // register services
+
+ boolean reg = requestRegistration();
+
+ if (!reg)
+ {
+ GenericActivator.error("InstanceManager : registration of the services failed...");
+ _invalidate();
+ return;
+ }
+
+ // Configuration ended successfuly.
+
+ }
+
+ /**
+ * This method invalidates the InstanceManager
+ *
+ * CONCURRENCY NOTE: This method may be called either from application code or event thread.
+ **/
+ synchronized void invalidate()
+ {
+ if (m_state == INSTANCE_INVALID)
+ {
+ return;
+ }
+ else if (m_state != INSTANCE_VALID && m_state != INSTANCE_DESTROYING)
+ {
+ GenericActivator.error("InstanceManager : invalidate() called for a non VALID InstanceManager ("+m_states[m_state]+")");
+ return;
+ }
+
+ if (m_state != INSTANCE_DESTROYING)
+ {
+ setState(INSTANCE_INVALIDATING);
+ }
+
+ // Fire invalidating events
+ fireInstanceReferenceInvalidating();
+
+ _invalidate();
+
+
+ }
+
+ /**
+ * this method invalidates the InstanceManager without performing any of the callbacks
+ * associated with the Lifecycle interface or the InstanceReference event listeners.
+ **/
+ private void _invalidate()
+ {
+ // Unregister services
+
+ requestUnregistration();
+
+ if(m_activateCalled==true)
+ {
+ // Call deactivate on the Lifecycle
+
+ if (m_implementorObject instanceof Lifecycle)
+ {
+ try
+ {
+ ((Lifecycle)m_implementorObject).deactivate();
+ }
+ catch(Exception e)
+ {
+ GenericActivator.error("InstanceManager : exception during call to deactivate():"+e);
+ }
+ }
+
+ }
+
+ // Unbind all services
+
+ Iterator it = m_dependencyManagers.iterator();
+
+ while (it.hasNext())
+ {
+ DependencyManager dm = (DependencyManager)it.next();
+ dm.unbindAll();
+ }
+
+ //m_activator.removeInstanceManager(this);
+
+ // remove all instances from a factory
+
+ /*
+ if (m_implementorObject instanceof GenericFactory)
+ {
+ ((GenericFactory)m_implementorObject).invalidateInstances();
+ }
+ */
+
+ // Release the object reference
+
+ m_implementorObject = null;
+
+ GenericActivator.trace("InstanceManager from bundle ["
+ + m_activator.getBundleContext().getBundle().getBundleId() + "] was invalidated.");
+
+ if (m_state != INSTANCE_DESTROYING)
+ {
+ setState(INSTANCE_INVALID);
+ }
+ }
+
+ /**
+ * This method should be called to completely remove the InstanceManager from the system.
+ * This means that the dependency managers will stop listening to events.
+ *
+ * CONCURRENCY NOTE: This method is only called from the GenericActivator, which is
+ * essentially application code and not via events.
+ **/
+ synchronized void destroy()
+ {
+ if (m_state == INSTANCE_DESTROYED)
+ {
+ return;
+ }
+
+ // Theoretically this should never be in any state other than VALID or INVALID,
+ // because validate is called right after creation.
+ boolean invalidatefirst = (m_state == INSTANCE_VALID);
+
+ setState(INSTANCE_DESTROYING);
+
+ // Stop the dependency managers to listen to events...
+ Iterator it = m_dependencyManagers.iterator();
+
+ while (it.hasNext())
+ {
+ DependencyManager dm = (DependencyManager)it.next();
+ m_activator.getBundleContext().removeServiceListener(dm);
+ }
+
+ if (invalidatefirst)
+ {
+ invalidate();
+ }
+
+ m_dependencyManagers.clear();
+
+ m_instanceListener = null;
+
+ GenericActivator.trace("InstanceManager from bundle ["
+ + m_activator.getBundleContext().getBundle().getBundleId() + "] was destroyed.");
+
+ m_activator.removeInstanceManager(this);
+ setState(INSTANCE_DESTROYED);
+
+ m_activator = null;
+ }
+
+ /**
+ * Returns the InstanceMetadata
+ */
+ public InstanceMetadata getInstanceMetadata()
+ {
+ return m_instanceMetadata;
+ }
+
+ /**
+ * Get the object that is implementing this descriptor
+ *
+ * @return the object that implements
+ */
+ public Object getObject()
+ {
+ return m_implementorObject;
+ }
+
+ /**
+ * Request the registration of the service provided by this binder instance
+ *
+ * @return returns false if registration was not successful,
+ * returns true if registration was successful
+ **/
+ boolean requestRegistration()
+ {
+ if (!m_instanceMetadata.instanceRegistersServices())
+ {
+ return true;
+ }
+ else if (m_implementorObject == null)
+ {
+ GenericActivator.error("GenericActivator : Cannot register, implementor object not created!");
+ return false;
+ }
+ else if (m_serviceRegistration != null)
+ {
+ GenericActivator.error("GenericActivator : Cannot register, binder instance already registered :"
+ + m_instanceMetadata.getImplementorName());
+ return true;
+ }
+
+ // Check validity of dependencies before registering !
+ Iterator it = m_dependencyManagers.iterator();
+ while (it.hasNext())
+ {
+ DependencyManager dm = (DependencyManager)it.next();
+ if (dm.isValid() == false)
+ return false;
+ }
+
+ // When registering a factory, add an instanceClass property which is an array
+ // of service interfaces implemented by the objects created by the factory.
+
+ if (m_instanceMetadata.isFactory())
+ {
+ if(m_instanceMetadata.getProperties().get("instanceClass") == null)
+ {
+ m_instanceMetadata.getProperties().put("instanceClass",m_instanceMetadata.getInstantiates().getInterfaces());
+ }
+ }
+
+ m_serviceRegistration = m_activator.getBundleContext().registerService(
+ m_instanceMetadata.getInterfaces(), m_implementorObject, m_instanceMetadata.getProperties());
+
+ GenericActivator.trace("Generic Activator : InstanceManager inside bundle ["
+ + m_activator.getBundleContext().getBundle().getBundleId()
+ + "] successfully registered its services !");
+
+ return true;
+ }
+
+
+ /**
+ *
+ * Request the unfegistration of the service provided by this binder instance
+ *
+ **/
+ void requestUnregistration()
+ {
+ if (m_serviceRegistration != null)
+ {
+ m_serviceRegistration.unregister();
+ m_serviceRegistration = null;
+
+ GenericActivator.trace("Generic Activator : InstanceManager inside bundle ["
+ + m_activator.getBundleContext().getBundle().getBundleId()
+ + "] unregistered its services !");
+
+ }
+ }
+
+ /**
+ * Get the state
+ */
+ public int getState()
+ {
+ return m_state;
+ }
+
+ /**
+ * Get the state
+ */
+ public long getBundleId()
+ {
+ return m_activator.getBundleContext().getBundle().getBundleId();
+ }
+
+ /**
+ * Get a property associated with this instance. For classes
+ * implementing this method, special care must be taken for
+ * values implementing <tt>InstanceReference.ValueHolder</tt>.
+ * In such cases, the value itself should not be returned, but
+ * the value of <tt>InstanceReference.ValueHolder.get()</tt>
+ * should be returned instead. This may be used to defer
+ * creating value objects in cases where creating the value
+ * object is expensive.
+ * @param name the name of the property to retrieve.
+ * @return the value of the associated property or <tt>null</tt>.
+ **/
+ public Object get(String name)
+ {
+ GenericActivator.trace("InstanceManager.get("+name+")");
+
+ if(name.equals(InstanceReference.INSTANCE_STATE))
+ {
+ return new Integer(m_state);
+ }
+ else if(name.equals(InstanceReference.INSTANCE_METADATA))
+ {
+ return getInstanceMetadata();
+ }
+ else if(name.equals(InstanceReference.INSTANCE_BUNDLE))
+ {
+ return new Integer((int) getBundleId());
+ }
+ else if(name.equals(InstanceReference.INSTANCE_DEPENDENCIES))
+ {
+ return getDependencies();
+ }
+ else
+ {
+ Object ret = m_localProperties.get(name);
+
+ if (ret != null)
+ {
+ if (ret instanceof ValueHolder)
+ {
+ return ((ValueHolder)ret).get(this);
+ }
+ return ret;
+ }
+
+ return m_instanceMetadata.getProperties().get(name);
+ }
+
+ }
+
+ /**
+ * Associate a property with this instance. For classes
+ * implementing this method, special care must be taken for
+ * values implementing <tt>InstanceReference.ValueHolder</tt>.
+ * In such cases, the value itself should not be returned, but
+ * the value of <tt>InstanceReference.ValueHolder.get()</tt>
+ * should be returned instead. This may be used to defer
+ * creating value objects in cases where creating the value
+ * object is expensive.
+ * @param name the name of the property to add.
+ * @param obj the value of the property.
+ **/
+ public void put(String name, Object obj)
+ {
+ m_localProperties.put(name,obj);
+ }
+
+ /**
+ * Adds an instance reference listener to listen for changes to
+ * the availability of the underlying object associated with this
+ * instance reference.
+ * @param l the listener to add.
+ **/
+ public void addInstanceReferenceListener(InstanceReferenceListener l)
+ {
+ m_instanceListener = StateChangeMulticaster.add(m_instanceListener, l);
+ }
+
+ /**
+ * Removes an instance reference listener.
+ * @param l the listener to remove.
+ **/
+ public void removeInstanceReferenceListener(InstanceReferenceListener l)
+ {
+ m_instanceListener = StateChangeMulticaster.remove(m_instanceListener, l);
+ }
+
+ /**
+ * Fires an event when the instance reference has been validated
+ **/
+ protected void fireInstanceReferenceValidated()
+ {
+ try
+ {
+ if (m_instanceListener != null)
+ {
+ m_instanceListener.validated(new InstanceReferenceEvent(this));
+ }
+ }
+ catch(Exception ex)
+ {
+ // Ignore any exception
+ }
+ }
+
+ /**
+ * Fires an event when the instance reference is invalidating
+ **/
+ protected void fireInstanceReferenceInvalidating()
+ {
+ try
+ {
+ if (m_instanceListener != null)
+ {
+ m_instanceListener.invalidating(new InstanceReferenceEvent(this));
+ }
+ }
+ catch(Exception ex)
+ {
+ // Ignore any exception
+ }
+ }
+
+ /**
+ * sets the state of the instanceManager
+ **/
+ synchronized void setState(int newState)
+ {
+ m_state = newState;
+
+ if(m_state == INSTANCE_CREATED || m_state == INSTANCE_VALID || m_state == INSTANCE_INVALID || m_state == INSTANCE_DESTROYED)
+ {
+ m_activator.fireInstanceChangeEvent(new InstanceChangeEvent(this,m_instanceMetadata,m_state));
+ }
+ }
+
+ /**
+ * Get an array of dependencies for this instance. This method is declared
+ * in the Instance interface
+ *
+ * @return an array of Dependencies
+ **/
+ public Dependency [] getDependencies()
+ {
+ Dependency deps [] = new Dependency[m_dependencyManagers.size()];
+ return (Dependency[]) m_dependencyManagers.toArray(deps);
+ }
+
+ /**
+ * Get a list of child instances in case this is a factory
+ *
+ * @return an array of Instances
+ **/
+ public Instance[] getChildInstances()
+ {
+ /*
+ if(m_implementorObject != null && m_implementorObject instanceof GenericFactory)
+ {
+ List instanceRefs = ((GenericFactory)m_implementorObject).getInstanceReferences();
+ Instance [] instances = new Instance[instanceRefs.size()];
+ instances = (Instance [])instanceRefs.toArray(instances);
+ return instances;
+ }
+ */
+ return null;
+ }
+
+/**
+ * This class implements the ServiceBinderContext, which cannot be directly
* implemented by the activator because of the getInstanceReference() method
+ */
+
+ class ServiceBinderContextImpl implements ServiceBinderContext
+ {
+
+ /**
+ *
+ * @uml.property name="m_parent"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private InstanceReference m_parent;
+
+ ServiceBinderContextImpl(InstanceReference parent)
+ {
+ m_parent = parent;
+ }
+
+ /**
+ * Get the bundle context
+ **/
+ public BundleContext getBundleContext()
+ {
+ return m_activator.getBundleContext();
+ }
+
+ /**
+ * Return all of the InstanceReferences created in the same bundle
+ **/
+ public List getInstanceReferences()
+ {
+ return m_activator.getInstanceReferences();
+ }
+
+ /**
+ * Get the parent InstanceReference
+ **/
+ public InstanceReference getInstanceReference()
+ {
+ return m_parent;
+ }
+ }
+
+/**
+ * The DependencyManager task is to listen to service events and to call the
* bind/unbind methods on a given object. It is also responsible for requesting
* the unregistration of a service in case a dependency is broken.
+ */
+
+ class DependencyManager implements ServiceListener, Dependency
+ {
+
+ /**
+ *
+ * @uml.property name="m_dependencyMetadata"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private DependencyMetadata m_dependencyMetadata;
+
+ private Map m_boundServices = new HashMap();
+ private Method m_bindMethod;
+ private Method m_unbindMethod;
+ private boolean m_isValid;
+ private int m_depState;
+ private boolean m_receivesRef = false;
+
+ /**
+ * Constructor that receives several parameters.
+ *
+ * @param dependency An object that contains data about the dependency
+ **/
+ DependencyManager(DependencyMetadata dependency) throws ClassNotFoundException, NoSuchMethodException
+ {
+ m_dependencyMetadata = dependency;
+ m_isValid = false;
+
+ m_bindMethod = getTargetMethod(m_dependencyMetadata.getBindMethodName(),InstanceManager.this.getInstanceMetadata().getImplementorName(),m_dependencyMetadata.getServiceName());
+ m_unbindMethod = getTargetMethod(m_dependencyMetadata.getUnbindMethodName(),InstanceManager.this.getInstanceMetadata().getImplementorName(),m_dependencyMetadata.getServiceName());
+
+ setStateDependency(DependencyChangeEvent.DEPENDENCY_CREATED);
+ }
+
+ /**
+ * initializes a dependency. This method binds all of the service occurrences to the instance object
+ *
+ * @return true if the operation was successful, false otherwise
+ **/
+ boolean initialize()
+ {
+ if(getObject() == null)
+ {
+ return false;
+ }
+
+ ServiceReference refs[] = getRequiredServiceRefs();
+
+ if (refs == null && m_dependencyMetadata.isOptional() == false)
+ {
+ m_isValid = false;
+ setStateDependency(DependencyChangeEvent.DEPENDENCY_INVALID);
+ return m_isValid;
+ }
+
+ m_isValid = true;
+ setStateDependency(DependencyChangeEvent.DEPENDENCY_VALID);
+
+ if (refs != null)
+ {
+ int max = 1;
+ boolean retval = true;
+
+ if (m_dependencyMetadata.isMultiple() == true)
+ {
+ max = refs.length;
+ }
+
+ for (int index = 0; index < max; index++)
+ {
+ retval = callBindMethod(refs[index]);
+ if(retval == false && (max == 1))
+ {
+ // There was an exception when calling the bind method
+ GenericActivator.error("Dependency Manager: Possible exception in the bind method during initialize()");
+ m_isValid = false;
+ setStateDependency(DependencyChangeEvent.DEPENDENCY_INVALID);
+ return m_isValid;
+ }
+ }
+ }
+
+ return m_isValid;
+ }
+
+ /**
+ * Called upon a service event. This method is responsible for calling the
+ * binding and unbinding methods and also to request the eventual unregistering
+ * of a service when a dependency breaks
+ *
+ * @param evt The ServiceEvent
+ **/
+ public void serviceChanged(ServiceEvent evt)
+ {
+ synchronized (InstanceManager.this)
+ {
+ // If the object is being created or destroyed, we can safely ignore events.
+ if (m_state == INSTANCE_DESTROYING || m_state == INSTANCE_DESTROYED || m_state == INSTANCE_CREATING || m_state == INSTANCE_CREATED)
+ {
+ return;
+ }
+
+ // If we are in the process of invalidating, it is not necessary to pass
+ // unregistration events, since we are unbinding everything anyway.
+ else if (m_state == INSTANCE_INVALIDATING && evt.getType() == ServiceEvent.UNREGISTERING)
+ {
+ return;
+ }
+
+ // We do not have an entry for VALIDATING because it is reentrant.
+
+ // A service is unregistering
+ if (evt.getType() == ServiceEvent.UNREGISTERING)
+ {
+ if (m_boundServices.keySet().contains(evt.getServiceReference()) == true)
+ {
+ // A static dependency is broken the instance manager will be invalidated
+ if (m_dependencyMetadata.isStatic())
+ {
+ m_isValid = false;
+ setStateDependency(DependencyChangeEvent.DEPENDENCY_INVALID);
+ try
+ {
+ GenericActivator.trace("Dependency Manager: Static dependency is broken");
+ invalidate();
+ GenericActivator.trace("Dependency Manager: RECREATING");
+ validate();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ // dynamic dependency
+ else
+ {
+ // Release references to the service, call unbinder method
+ // and eventually request service unregistration
+
+ callUnbindMethod(evt.getServiceReference());
+
+ // The only thing we need to do here is check if we can reinitialize
+ // once the bound services becomes zero. This tries to repair dynamic
+ // 1..1 or rebind 0..1, since replacement services may be available.
+ // In the case of aggregates, this will only invalidate them since they
+ // can't be repaired.
+ if (m_boundServices.size() == 0)
+ {
+ // try to reinitialize
+ if (!initialize())
+ {
+ if (!m_dependencyMetadata.isOptional())
+ {
+ GenericActivator.trace("Dependency Manager: Mandatory dependency not fullfilled and no replacements available... unregistering service...");
+ invalidate();
+ GenericActivator.trace("Dependency Manager: RECREATING");
+ validate();
+ }
+ }
+ }
+ }
+ }
+ }
+ // A service is registering.
+ else if (evt.getType() == ServiceEvent.REGISTERED)
+ {
+ if (m_boundServices.keySet().contains(evt.getServiceReference()) == true)
+ {
+ // This is a duplicate
+ GenericActivator.trace("DependencyManager : ignoring REGISTERED ServiceEvent (already bound)");
+ }
+ else
+ {
+ m_isValid = true;
+ setStateDependency(DependencyChangeEvent.DEPENDENCY_VALID);
+
+ // If the InstanceManager is invalid, a call to validate is made
+ // which will fix everything.
+ if (InstanceManager.this.getState() != INSTANCE_VALID)
+ {
+ validate();
+ }
+ // Otherwise, this checks for dynamic 0..1, 0..N, and 1..N it never
+ // checks for 1..1 dynamic which is done above by the validate()
+ else if (!m_dependencyMetadata.isStatic())
+ {
+ // For dependency that are aggregates, always bind the service
+ // Otherwise only bind if bind services is zero, which captures the 0..1 case
+ if (m_dependencyMetadata.isMultiple() || m_boundServices.size() == 0)
+ {
+ callBindMethod(evt.getServiceReference());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Revoke all bindings. This method cannot throw an exception since it must try
+ * to complete all that it can
+ *
+ **/
+ void unbindAll()
+ {
+ Object []allrefs = m_boundServices.keySet().toArray();
+
+ if (allrefs == null)
+ return;
+
+ for (int i = 0; i < allrefs.length; i++)
+ {
+ callUnbindMethod((ServiceReference)allrefs[i]);
+ }
+ }
+
+ /**
+ * Test if this dependency managed by this object is valid
+ **/
+ boolean isValid()
+ {
+ return m_isValid;
+ }
+
+ /**
+ *
+ * Returns an array containing the service references that are pertinent to the
+ * dependency managed by this object. This method filters out services that
+ * belong to bundles that are being (or are actually) shutdown. This is an issue
+ * since is not clearly specified in the OSGi specification if a getServiceReference
+ * call should return the services that belong to bundles that are stopping.
+ *
+ * @return an array of ServiceReferences valid in the context of this dependency
+ **/
+ ServiceReference [] getRequiredServiceRefs()
+ {
+ try
+ {
+ ArrayList list=new ArrayList();
+ ServiceReference temprefs[] =
+ m_activator.getBundleContext().getServiceReferences(m_dependencyMetadata.getServiceName(), m_dependencyMetadata.getFilter());
+
+ if (temprefs == null)
+ {
+ return null;
+ }
+
+ for (int i = 0; i < temprefs.length; i++)
+ {
+ if (temprefs[i].getBundle().getState() == Bundle.ACTIVE
+ || temprefs[i].getBundle().getState() == Bundle.STARTING)
+ {
+ list.add(temprefs[i]);
+ }
+ }
+
+ return (ServiceReference []) list.toArray(new ServiceReference [temprefs.length]);
+
+ }
+ catch (Exception e)
+ {
+ GenericActivator.error("DependencyManager: exception while getting references :"+e);
+ return null;
+ }
+ }
+
+ /**
+ * Gets a target method based on a set of parameters
+ *
+ * @param methodname The name of the method
+ * @param targetClass the class to which the method belongs to
+ * @param paramClass the class of the parameter that is passed to the method
+ * @throws java.lang.ClassNotFoundException if the class was not found
+ * @throws java.lang.NoSuchMethodException if the method was not found
+ **/
+ private Method getTargetMethod(String methodname, String targetClass, String paramClass)
+ throws ClassNotFoundException, NoSuchMethodException
+ {
+ Class targetclass = m_activator.getClass().getClassLoader().loadClass(targetClass);
+
+ Method method = null;
+
+ try
+ {
+ method = targetclass.getMethod(methodname,
+ new Class[]{m_activator.getClass().getClassLoader().loadClass(paramClass)});
+
+ }
+ catch(NoSuchMethodException ex)
+ {
+ // Test if the bind method receives a ServiceReference as the first parameter
+
+ method = targetclass.getMethod(methodname,
+ new Class[]{ServiceReference.class, m_activator.getClass().getClassLoader().loadClass(paramClass)});
+
+ m_receivesRef = true;
+ }
+
+ return method;
+ }
+
+ /**
+ * Call the bind method. In case there is an exception while calling the bind method, the service
+ * is not considered to be bound to the instance object
+ *
+ * @param ref A ServiceReference with the service that will be bound to the instance object
+ * @return true if the call was successful, false otherwise
+ **/
+ boolean callBindMethod(ServiceReference ref)
+ {
+ try
+ {
+ Object requiredService = m_activator.getBundleContext().getService(ref);
+ Object proxy = m_activator.proxyRequiredServiceObject(requiredService,m_dependencyMetadata);
+
+ if(proxy == null)
+ {
+ // ignore a null return value from the proxy method
+ proxy = requiredService;
+ }
+ if(m_receivesRef == false)
+ {
+ m_bindMethod.invoke(getObject(),new Object[] {proxy});
+ }
+ else
+ {
+ m_bindMethod.invoke(getObject(),new Object[] {ref,proxy});
+ }
+ m_boundServices.put(ref,proxy);
+
+ return true;
+ }
+ catch(Exception e)
+ {
+ if(e instanceof InvocationTargetException)
+ {
+ InvocationTargetException ite = (InvocationTargetException) e;
+ GenericActivator.error("DependencyManager : exception while invoking "+m_dependencyMetadata.getBindMethodName()+" :"+ite.getTargetException());
+ }
+ else
+ {
+ GenericActivator.error("DependencyManager : exception while invoking "+m_dependencyMetadata.getBindMethodName()+" :"+e);
+ }
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * Call the unbind method
+ *
+ * @param ref A service reference corresponding to the service that will be unbound
+ **/
+ void callUnbindMethod(ServiceReference ref)
+ {
+ Object requiredService = m_boundServices.get(ref);
+ if (requiredService == null)
+ {
+ GenericActivator.error("DependencyManager : callUnbindMethod UNBINDING UNKNOWN SERVICE !!!!");
+ return;
+ }
+
+ try
+ {
+ if(m_receivesRef == false)
+ {
+ m_unbindMethod.invoke(getObject(),new Object [] {requiredService});
+ }
+ else
+ {
+ m_unbindMethod.invoke(getObject(),new Object [] {ref, requiredService});
+ }
+
+ m_boundServices.remove(ref);
+ m_activator.getBundleContext().ungetService(ref);
+ }
+ catch(Exception e)
+ {
+ if(e instanceof InvocationTargetException)
+ {
+ InvocationTargetException ite = (InvocationTargetException) e;
+ GenericActivator.error("DependencyManager : exception while invoking "+m_dependencyMetadata.getUnbindMethodName()+" :"+ite.getTargetException());
+ }
+ else
+ {
+ GenericActivator.error("DependencyManager : exception while invoking "+m_dependencyMetadata.getUnbindMethodName()+" :"+e);
+ }
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Return the dependency descriptor
+ *
+ * @return the corresponding dependency descriptor
+ **/
+ public DependencyMetadata getDependencyMetadata()
+ {
+ return m_dependencyMetadata;
+ }
+
+ /**
+ * Fire a state change event.
+ *
+ * @param state the state of the dependency manager
+ **/
+ void setStateDependency(int state)
+ {
+ m_depState = state;
+ m_activator.fireDependencyChangeEvent(new DependencyChangeEvent(this,m_dependencyMetadata,state));
+ }
+
+ /**
+ * Get the state of the dependency.
+ *
+ * @return the state of the dependency manager
+ **/
+ public int getDependencyState()
+ {
+ return m_depState;
+ }
+
+ /**
+ * Get the bound service objects. This method is declared in the Dependency interface
+ * and is used for to get a model.
+ *
+ * @return an array containing the bound service objects
+ **/
+ public Instance[] getBoundInstances()
+ {
+ Object bound[] = m_boundServices.values().toArray();
+
+ ArrayList tempArray = new ArrayList();
+
+ for(int i=0; i<bound.length; i++)
+ {
+ InstanceReference ref = ArchitectureServiceImpl.findInstanceReference(bound[i]);
+ if(ref != null)
+ {
+ tempArray.add(ref);
+ }
+ }
+
+ Instance instances[]= new Instance[tempArray.size()];
+ instances = (Instance [])tempArray.toArray(instances);
+
+ return instances;
+
+
+ }
+ }
+
+/**
+ * @version X.XX Feb 3, 2004
* @author Humberto Cervantes
+ */
+
+ static public class StateChangeMulticaster implements InstanceReferenceListener
+ {
+
+ /**
+ *
+ * @uml.property name="a"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ protected InstanceReferenceListener a;
+
+ /**
+ *
+ * @uml.property name="b"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ protected InstanceReferenceListener b;
+
+ protected StateChangeMulticaster(InstanceReferenceListener a, InstanceReferenceListener b)
+ {
+ this.a = a;
+ this.b = b;
+ }
+
+
+ public void validated(InstanceReferenceEvent e)
+ {
+ a.validated(e);
+ b.validated(e);
+ }
+
+ public void invalidating(InstanceReferenceEvent e)
+ {
+ a.invalidating(e);
+ b.invalidating(e);
+ }
+
+ public static InstanceReferenceListener add(InstanceReferenceListener a, InstanceReferenceListener b)
+ {
+ if (a == null)
+ return b;
+ else if (b == null)
+ return a;
+ else
+ return new StateChangeMulticaster(a, b);
+ }
+
+ public static InstanceReferenceListener remove(InstanceReferenceListener a, InstanceReferenceListener b)
+ {
+ if ((a == null) || (a == b))
+ return null;
+ else if (a instanceof StateChangeMulticaster)
+ return add (remove (((StateChangeMulticaster) a).a, b),remove (((StateChangeMulticaster) a).b, b));
+ else
+ return a;
+ }
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceMetadata.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceMetadata.java
new file mode 100644
index 0000000..6585796
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceMetadata.java
@@ -0,0 +1,204 @@
+/*
+ * 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.servicebinder;
+
+import java.util.Properties;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Description of an instance entry in the descriptor file
*
* @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class InstanceMetadata
+{
+ // These properties will be filled by the parser
+ private String m_implementorName;
+ private Collection m_interfaces = null;
+ private Properties m_properties = new Properties();
+ private Collection m_dependencies = null;
+
+ /**
+ *
+ * @uml.property name="m_instantiates"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private InstanceMetadata m_instantiates = null;
+
+ /**
+ *
+ * @uml.property name="m_parent"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private InstanceMetadata m_parent = null;
+
+ private boolean m_isFactory = false;
+ private boolean m_registersService = false;
+ private boolean m_isInstance = false;
+
+ /**
+ * Constructor
+ *
+ * @param implementorName name of the class of the implementation object
+ * @param parent the parent to this service descriptor
+ */
+ InstanceMetadata(String implementorName,InstanceMetadata parent)
+ {
+ m_interfaces = new ArrayList();
+ m_dependencies = new ArrayList();
+
+ m_implementorName = implementorName;
+
+ // The parent will be != null if this descriptor corresponds to an
+ // instantiate entry
+
+ if(parent != null)
+ {
+ m_parent = parent;
+ m_parent.m_instantiates = this;
+ m_parent.m_isFactory = true;
+ m_isInstance = true;
+ }
+ }
+
+ /**
+ * Returns the name of the implementor
+ *
+ * @return the name of the implementor
+ */
+ public String getImplementorName()
+ {
+ return m_implementorName;
+ }
+
+
+ /**
+ * Used to add an interface to the service descriptor
+ *
+ * @param newInterface name of the interface implemented by the implementation object
+ */
+ void addInterface(String newInterface)
+ {
+ // As soon as there is one interface provided, it cannot be a bundle-to-service.
+ m_registersService = true;
+ m_interfaces.add(newInterface);
+ }
+
+ /**
+ * Returns the implemented interfaces
+ *
+ * @return the implemented interfaces as a string array
+ */
+ public String [] getInterfaces()
+ {
+ String interfaces[] = new String[m_interfaces.size()];
+ Iterator it = m_interfaces.iterator();
+ int count = 0;
+ while (it.hasNext())
+ {
+ interfaces[count++] = it.next().toString();
+ }
+ return interfaces;
+ }
+
+ /**
+ * Used to add a property to the instance
+ *
+ * @param newProperty a property descriptor
+ */
+ void addProperty(PropertyMetadata newProperty)
+ {
+ String key = newProperty.getName();
+ Object value = newProperty.getValue();
+ if(key != null && value != null)
+ {
+ m_properties.put(key,value);
+ }
+ }
+
+ /**
+ * Returns the property descriptors
+ *
+ * @return the property descriptors as a Collection
+ */
+ public Properties getProperties()
+ {
+ return m_properties;
+ }
+
+ /**
+ * Used to add a dependency descriptor to the service descriptor
+ *
+ * @param newDependency a new dependency to be added
+ */
+ void addDependency(DependencyMetadata newDependency)
+ {
+ m_dependencies.add(newDependency);
+ }
+
+
+ /**
+ * Returns the dependency descriptors
+ *
+ * @return a Collection of dependency descriptors
+ */
+ public Collection getDependencies()
+ {
+ return m_dependencies;
+ }
+
+ /**
+ * Test to see if this service is a factory
+ *
+ * @return true if it is a factory, false otherwise
+ */
+ public boolean isFactory()
+ {
+ return m_isFactory;
+ }
+
+ /**
+ * Get the meta data of the instances
+ *
+ * @return the instance metadata
+ */
+ public InstanceMetadata getInstantiates()
+ {
+ return m_instantiates;
+ }
+
+ /**
+ * Test to see if this descriptor describes a bundle-to-service dependency
+ * that means that the instance does not register any services.
+ *
+ * @return true if the dependency is bundle-to-service
+ */
+ public boolean instanceRegistersServices()
+ {
+ return m_registersService;
+ }
+
+ /**
+ * Test to see if this descriptor is registered from an instance from a factory.
+ *
+ * @return true if this descriptor is registered from an instance from a factory.
+ */
+ public boolean isInstance()
+ {
+ return m_isInstance;
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceReference.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceReference.java
new file mode 100644
index 0000000..c4366b2
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceReference.java
@@ -0,0 +1,99 @@
+/*
+ * 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.servicebinder;
+
+/**
+ * This interface creates a level of indirection for the objects
+ * created by a factory. This is necessary because it might not
+ * be possible for a factory to create the actual object instance
+ * at the time of the call to <tt>Factory.createInstance()</tt>
+ * due to unfulfilled dependencies. In such a scenario, this
+ * interface can be used to listen for the object instance to
+ * become available.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public interface InstanceReference
+{
+ public static final String INSTANCE_STATE = "INSTANCE_STATE";
+ public static final String INSTANCE_METADATA = "INSTANCE_METADATA";
+ public static final String INSTANCE_BUNDLE = "INSTANCE_BUNDLE";
+ public static final String INSTANCE_DEPENDENCIES ="INSTANCE_DEPENDENCIES";
+
+ /**
+ * Get a property associated with this instance. For classes
+ * implementing this method, special care must be taken for
+ * values implementing <tt>InstanceReference.ValueHolder</tt>.
+ * In such cases, the value itself should not be returned, but
+ * the value of <tt>InstanceReference.ValueHolder.get()</tt>
+ * should be returned instead. This may be used to defer
+ * creating value objects in cases where creating the value
+ * object is expensive.
+ * @param name the name of the property to retrieve.
+ * @return the value of the associated property or <tt>null</tt>.
+ **/
+ public Object get(String name);
+
+ /**
+ * Associate a property with this instance. For classes
+ * implementing this method, special care must be taken for
+ * values implementing <tt>InstanceReference.ValueHolder</tt>.
+ * In such cases, the value itself should not be returned, but
+ * the value of <tt>InstanceReference.ValueHolder.get()</tt>
+ * should be returned instead. This may be used to defer
+ * creating value objects in cases where creating the value
+ * object is expensive.
+ * @param name the name of the property to add.
+ * @param value the value of the property.
+ **/
+ public void put(String name, Object value);
+
+ /**
+ * Gets the actual object associated with this instance refernce.
+ * @return the object associated with this reference or <tt>null</tt>
+ * if the reference is not currently valid.
+ **/
+ public Object getObject();
+
+ /**
+ * Adds an instance reference listener to listen for changes to
+ * the availability of the underlying object associated with this
+ * instance reference.
+ * @param l the listener to add.
+ **/
+ public void addInstanceReferenceListener(InstanceReferenceListener l);
+
+ /**
+ * Removes an instance reference listener.
+ * @param l the listener to remove.
+ **/
+ public void removeInstanceReferenceListener(InstanceReferenceListener l);
+
+ /**
+ * A simple interface that enabled deferred value creation for
+ * the <tt>InstanceReference.get()</tt> and <tt>InstanceReference.put()</tt>
+ * methods.
+ **/
+ public static interface ValueHolder
+ {
+ /**
+ * Returns the associated value.
+ * @return the associated value or <tt>null</tt>.
+ **/
+ public Object get(InstanceReference ir);
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceReferenceEvent.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceReferenceEvent.java
new file mode 100644
index 0000000..2df4c47
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceReferenceEvent.java
@@ -0,0 +1,40 @@
+/*
+ * 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.servicebinder;
+
+/**
+ * This class is the event generated when the availability of the
+ * underlying object associated with an <tt>InstanceReference</tt>
+ * changes. Use the <tt>InstanceReferenceListener</tt> interface
+ * to listen for this event. The <tt>getSource()</tt> method
+ * returns the <tt>InstanceReference</tt> that generated the event.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+**/
+public class InstanceReferenceEvent extends java.util.EventObject
+{
+ private static final long serialVersionUID = 189791898139565080L;
+
+ /**
+ * Construct an event with the specified source instance reference.
+ * @param ir the instance reference that generated the event.
+ **/
+ public InstanceReferenceEvent(InstanceReference ir)
+ {
+ super(ir);
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceReferenceListener.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceReferenceListener.java
new file mode 100644
index 0000000..d616ff7
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/InstanceReferenceListener.java
@@ -0,0 +1,71 @@
+/*
+ * 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.servicebinder;
+
+/**
+ * This is an event listener for listening to changes in
+ * the availability of the underlying object associated
+ * with an <tt>InstanceReference</tt>. For the precise
+ * details of when this event is fired, refer to the
+ * methods below.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+**/
+public interface InstanceReferenceListener extends java.util.EventListener
+{
+ /**
+ * This method is called when an <tt>InstanceReference</tt>'s
+ * underlying object becomes valid, i.e., the instance is
+ * available for use. This event is fired during the following
+ * sequence of steps:
+ * <p>
+ * <ol>
+ * <li>Instance created.</li>
+ * <li>Dependencies bound, if any.</li>
+ * <li>Services registered, if any.</li>
+ * <li><tt>Lifecycle.activate()</tt> is called, if the instance
+ * implements the <tt>Lifecycle</tt> interface.</li>
+ * <li>Fire <tt>InstanceReferenceListener.validated()</tt>.
+ * </ol>
+ * @param event the associated instance reference event.
+ **/
+ public void validated(InstanceReferenceEvent event);
+
+ /**
+ * This method is called when an <tt>InstanceReference</tt>'s
+ * underlying object is going to be invalidated. This event
+ * is fired during the following sequence of steps:
+ * <p>
+ * <ol>
+ * <li>Fire <tt>InstanceReferenceListener.invalidating()</tt>.
+ * <li>Call <tt>Lifecycle.deactivate()</tt>, if the instance
+ * implements the <tt>Lifecycle</tt> interface.</li>
+ * <li>Unregister services, if any.</li>
+ * <li>Unbind dependencies, if any.</li>
+ * <li>Dispose instance.</li>
+ * </ol>
+ * <p>
+ * Note: Care must be taken during this callback, because the
+ * underlying object associated with the instance reference may
+ * not be fully functioning. For example, this event might be
+ * fired in direct response to a dependent service shutting down,
+ * which then instigates the invalidation of the underlying object
+ * instance.
+ * @param event the associated instance reference event.
+ **/
+ public void invalidating(InstanceReferenceEvent event);
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/Lifecycle.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/Lifecycle.java
new file mode 100644
index 0000000..7d5b40f
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/Lifecycle.java
@@ -0,0 +1,44 @@
+/*
+ * 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.servicebinder;
+
+/**
+ * Instances created by the service binder, either via the
+ * <tt>GenericActivator</tt> or the <tt>GenericFactory</tt>,
+ * may implement this interface to receive notification of
+ * object life cycle events. See each interface method for
+ * a precise description of when the method is invoked.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+**/
+public interface Lifecycle
+{
+ /**
+ * This method is called after the instance is created, all of its
+ * dependencies are valid, and all implemented services are registered.
+ **/
+ public void activate();
+
+ /**
+ * This method is called prior to instance disposal. At the time
+ * of invocation, all dependencies are still valid and all services
+ * are still registered. Be aware that at this point some dependent
+ * services may have been shutdown and using them may result in
+ * error conditions.
+ **/
+ public void deactivate();
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/PropertyMetadata.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/PropertyMetadata.java
new file mode 100644
index 0000000..e89892f
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/PropertyMetadata.java
@@ -0,0 +1,115 @@
+/*
+ * 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.servicebinder;
+
+/**
+ * A property descriptor that contains the information for properties
+ * defined in the meta-data file.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class PropertyMetadata
+{
+ String name;
+ String type;
+ Object value;
+
+ /**
+ * Create a PropertyMetadata object
+ *
+ * @param name the name of the property
+ * @param type the type of the property (string, boolean, byte, char, short, int, long, float or double)
+ * @param val the value of the property
+ */
+ public PropertyMetadata(String name, String type, String val)
+ {
+ this.name = name;
+ type.toLowerCase();
+ this.type = type;
+ value = null;
+
+ if(type.equals("string") || type.equals("String"))
+ {
+ value = new String(val);
+ }
+ else if(type.equals("boolean"))
+ {
+ value = new Boolean(val);
+ }
+ else if(type.equals("byte"))
+ {
+ value = new Byte(val);
+ }
+ else if(type.equals("char"))
+ {
+ value = new Byte(val);
+ }
+ else if(type.equals("short"))
+ {
+ value = new Short(val);
+ }
+ else if(type.equals("int"))
+ {
+ value = new Integer(val);
+ }
+ else if(type.equals("long"))
+ {
+ value = new Long(val);
+ }
+ else if(type.equals("float"))
+ {
+ value = new Float(val);
+ }
+ else if(type.equals("double"))
+ {
+ value = new Double(val);
+ }
+ }
+
+ /**
+ * Get the name of the property
+ *
+ * @return the name of the property
+ *
+ * @uml.property name="name"
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the type of the property
+ *
+ * @return the type of the property
+ *
+ * @uml.property name="type"
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Get the value of the property
+ *
+ * @return the value of the property as an Object
+ *
+ * @uml.property name="value"
+ */
+ public Object getValue() {
+ return value;
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/ServiceBinderContext.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/ServiceBinderContext.java
new file mode 100644
index 0000000..bcadab5
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/ServiceBinderContext.java
@@ -0,0 +1,50 @@
+/*
+ * 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.servicebinder;
+
+import org.osgi.framework.BundleContext;
+
+import java.util.List;
+
+/**
+ * The ServiceBinderContext is passed to the objects that implement the services
+ * if they implement a constructor that receives a reference of this type. Through
+ * this interface, they can access the BundleContext along with the list ob
+ * binder instances located on the same bundle.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public interface ServiceBinderContext
+{
+ /**
+ *
+ *@return the Bundle Context of the bundle where the receiver of the context is located
+ **/
+ BundleContext getBundleContext();
+
+ /**
+ *
+ *
+ **/
+ List getInstanceReferences();
+
+ /**
+ *
+ *
+ **/
+ InstanceReference getInstanceReference();
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/ServiceBinderException.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/ServiceBinderException.java
new file mode 100644
index 0000000..9713430
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/ServiceBinderException.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.servicebinder;
+
+/**
+ * Exceptions thrown by the ServiceBinder.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ServiceBinderException extends Exception
+{
+ private static final long serialVersionUID = 2819108687170297942L;
+
+ public ServiceBinderException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/XmlHandler.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/XmlHandler.java
new file mode 100644
index 0000000..c3e5f6b
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/XmlHandler.java
@@ -0,0 +1,143 @@
+/*
+ * 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.servicebinder;
+
+import java.util.Properties;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.servicebinder.parser.ParseException;
+
+/**
+ * Simple content handler that builds a list of service descriptors
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class XmlHandler
+{
+ /**
+ *
+ * @uml.property name="parentDescriptor"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private InstanceMetadata parentDescriptor = null;
+
+ /**
+ *
+ * @uml.property name="currentDescriptor"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private InstanceMetadata currentDescriptor = null;
+
+ private List descriptors = new ArrayList();
+
+ XmlHandler()
+ {
+ }
+
+ /**
+ * Method called when a tag opens
+ *
+ * @param uri
+ * @param localName
+ * @param qName
+ * @param attrib
+ * @exception ParseException
+ **/
+ public void startElement(String uri,String localName,String qName,Properties attrib) throws ParseException
+ {
+ if (qName.equals("instance") || qName.equals("component"))
+ {
+ currentDescriptor = new InstanceMetadata(attrib.getProperty("class"),parentDescriptor);
+ descriptors.add(currentDescriptor);
+ }
+ if (qName.equals("service")) // will be deprecated
+ {
+ if(currentDescriptor == null)
+ {
+ return;
+ }
+ currentDescriptor.addInterface(attrib.getProperty("interface"));
+ }
+ if (qName.equals("provides"))
+ {
+ if(currentDescriptor == null)
+ {
+ return;
+ }
+ currentDescriptor.addInterface(attrib.getProperty("service"));
+ }
+ if (qName.equals("property"))
+ {
+
+ if(currentDescriptor == null)
+ {
+ return;
+ }
+ PropertyMetadata prop = new PropertyMetadata(attrib.getProperty("name"),
+ attrib.getProperty("type"),
+ attrib.getProperty("value"));
+ currentDescriptor.addProperty(prop);
+ }
+ if (qName.equals("requires"))
+ {
+ if(currentDescriptor == null)
+ {
+ return;
+ }
+
+ DependencyMetadata dd=new DependencyMetadata(attrib.getProperty("service"),
+ attrib.getProperty("cardinality"),attrib.getProperty("policy"),attrib.getProperty("filter"),
+ attrib.getProperty("bind-method"),attrib.getProperty("unbind-method"));
+
+ currentDescriptor.addDependency(dd);
+ }
+
+ if (qName.equals("instantiates"))
+ {
+ GenericActivator.error("ERROR: Version 1.1 does not support factories");
+ }
+
+ }
+
+ /**
+ * Method called when a tag closes
+ *
+ * @param uri
+ * @param localName
+ * @param qName
+ * @exception ParseException
+ */
+ public void endElement(java.lang.String uri,java.lang.String localName,java.lang.String qName) throws ParseException
+ {
+ if (qName.equals("instantiates") || qName.equals("component"))
+ {
+ currentDescriptor = parentDescriptor;
+ parentDescriptor = null;
+ }
+ }
+
+ /**
+ * Called to retrieve the service descriptors
+ *
+ * @return A list of service descriptors
+ */
+ List getInstanceMetadatas()
+ {
+ return descriptors;
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/ArchitectureService.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/ArchitectureService.java
new file mode 100644
index 0000000..d72789d
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/ArchitectureService.java
@@ -0,0 +1,48 @@
+/*
+ * 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.servicebinder.architecture;
+
+/**
+ *
+ * A service to provide an architectural vision of the instances created by the
+ * service binder
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public interface ArchitectureService
+{
+ /**
+ * Get a list of all the available instance references
+ *
+ * @return a List containing all of the instance references
+ **/
+ public Instance [] getInstances();
+
+ /**
+ * Add a service binder listener
+ *
+ * @param listener a ServiceBinderListener to add to the Architecture service
+ **/
+ public void addServiceBinderListener(ServiceBinderListener listener);
+
+ /**
+ * Remove a service binder listener
+ *
+ * @param listener the listener to be removed
+ **/
+ public void removeServiceBinderListener(ServiceBinderListener listener);
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/Dependency.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/Dependency.java
new file mode 100644
index 0000000..3ef0a27
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/Dependency.java
@@ -0,0 +1,48 @@
+/*
+ * 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.servicebinder.architecture;
+
+import org.apache.felix.servicebinder.DependencyMetadata;
+
+/**
+ * Interface for a dependency
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public interface Dependency
+{
+ /**
+ * get the dependency state
+ *
+ * @return the state of the dependency
+ **/
+ public int getDependencyState();
+
+ /**
+ * get the dependency metadata
+ *
+ * @return the metadata of the dependency
+ **/
+ public DependencyMetadata getDependencyMetadata();
+
+ /**
+ * get the bound service objects
+ *
+ * @return the bound Instances
+ **/
+ public Instance []getBoundInstances();
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/DependencyChangeEvent.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/DependencyChangeEvent.java
new file mode 100644
index 0000000..603d97d
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/DependencyChangeEvent.java
@@ -0,0 +1,70 @@
+/*
+ * 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.servicebinder.architecture;
+
+import org.apache.felix.servicebinder.DependencyMetadata;
+
+/**
+ * An event thrown when a dependency changes
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class DependencyChangeEvent
+{
+ public static final int DEPENDENCY_CREATED = 0;
+ public static final int DEPENDENCY_VALID = 1;
+ public static final int DEPENDENCY_INVALID = 2;
+ public static final int DEPENDENCY_DESTROYED = 3;
+
+ /**
+ *
+ * @uml.property name="m_dep"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private Dependency m_dep;
+
+ /**
+ *
+ * @uml.property name="m_meta"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private DependencyMetadata m_meta;
+
+ private int m_state;
+
+ public DependencyChangeEvent(Dependency dep, DependencyMetadata meta,int newState)
+ {
+ m_dep = dep;
+ m_meta = meta;
+ m_state = newState;
+ }
+
+ public Dependency getDependency()
+ {
+ return m_dep;
+ }
+
+ public DependencyMetadata getDependencyMetadata()
+ {
+ return m_meta;
+ }
+
+ public int getState()
+ {
+ return m_state;
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/Instance.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/Instance.java
new file mode 100644
index 0000000..21aa209
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/Instance.java
@@ -0,0 +1,66 @@
+/*
+ * 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.servicebinder.architecture;
+
+import org.apache.felix.servicebinder.InstanceMetadata;
+
+/**
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public interface Instance
+{
+ public static final int INSTANCE_CREATED = 0;
+ public static final int INSTANCE_VALID = 1;
+ public static final int INSTANCE_INVALID = 2;
+ public static final int INSTANCE_DESTROYED = 3;
+
+ /**
+ * Get the state of the instance
+ *
+ * @return an integer representing the state of the instance
+ **/
+ public int getState();
+
+ /**
+ * Get the bundle
+ *
+ * @return an integer with the bundle id
+ **/
+ public long getBundleId();
+
+ /**
+ * Get a list of depenencies
+ *
+ * @return a List containing all of the dependencies
+ **/
+ public Dependency[] getDependencies();
+
+ /**
+ * Get a list of child instances in case this instance is a factory
+ *
+ * @return a List containing all of the child instances
+ **/
+ public Instance[] getChildInstances();
+
+ /**
+ * Get the instance metadata
+ *
+ * @return the isntance metadata
+ **/
+ public InstanceMetadata getInstanceMetadata();
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/InstanceChangeEvent.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/InstanceChangeEvent.java
new file mode 100644
index 0000000..deba479
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/InstanceChangeEvent.java
@@ -0,0 +1,64 @@
+/*
+ * 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.servicebinder.architecture;
+
+import org.apache.felix.servicebinder.InstanceMetadata;
+
+/**
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class InstanceChangeEvent
+{
+ /**
+ *
+ * @uml.property name="m_ref"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private Instance m_ref;
+
+ /**
+ *
+ * @uml.property name="m_meta"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private InstanceMetadata m_meta;
+
+ private int m_state;
+
+ public InstanceChangeEvent(Instance ref,InstanceMetadata meta,int state)
+ {
+ m_ref = ref;
+ m_meta = meta;
+ m_state = state;
+ }
+
+ public Instance getInstance()
+ {
+ return m_ref;
+ }
+
+ public InstanceMetadata getInstanceMetadata()
+ {
+ return m_meta;
+ }
+
+ public int getState()
+ {
+ return m_state;
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/ServiceBinderListener.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/ServiceBinderListener.java
new file mode 100644
index 0000000..dec4b4e
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/architecture/ServiceBinderListener.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.servicebinder.architecture;
+
+/**
+ * The ServiceBinderListener interface must be implemented by any subclass
+ * of the GenericActivator if it wishes to receive notifications about
+ * changes in the architecture
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public interface ServiceBinderListener extends java.util.EventListener
+{
+ /*
+ * Method called when an instance changes its state
+ */
+ void instanceReferenceChanged(InstanceChangeEvent evt);
+
+ /*
+ * Method called when a dependency changes its state
+ */
+ void dependencyChanged(DependencyChangeEvent evt);
+
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/impl/Activator.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/impl/Activator.java
new file mode 100644
index 0000000..578a064
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/impl/Activator.java
@@ -0,0 +1,27 @@
+/*
+ * 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.servicebinder.impl;
+
+import org.apache.felix.servicebinder.GenericActivator;
+
+/**
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class Activator extends GenericActivator
+{
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/impl/ArchitectureEventMulticaster.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/impl/ArchitectureEventMulticaster.java
new file mode 100644
index 0000000..ecbeba0
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/impl/ArchitectureEventMulticaster.java
@@ -0,0 +1,80 @@
+/*
+ * 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.servicebinder.impl;
+
+import org.apache.felix.servicebinder.architecture.DependencyChangeEvent;
+import org.apache.felix.servicebinder.architecture.InstanceChangeEvent;
+import org.apache.felix.servicebinder.architecture.ServiceBinderListener;
+
+/**
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ArchitectureEventMulticaster implements ServiceBinderListener
+{
+ /**
+ *
+ * @uml.property name="a"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ protected ServiceBinderListener a;
+
+ /**
+ *
+ * @uml.property name="b"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ protected ServiceBinderListener b;
+
+ protected ArchitectureEventMulticaster(ServiceBinderListener a, ServiceBinderListener b)
+ {
+ this.a = a;
+ this.b = b;
+ }
+
+ public void dependencyChanged(DependencyChangeEvent e)
+ {
+ a.dependencyChanged(e);
+ b.dependencyChanged(e);
+ }
+
+ public void instanceReferenceChanged(InstanceChangeEvent e)
+ {
+ a.instanceReferenceChanged(e);
+ b.instanceReferenceChanged(e);
+ }
+
+ public static ServiceBinderListener add(ServiceBinderListener a, ServiceBinderListener b)
+ {
+ if (a == null)
+ return b;
+ else if (b == null)
+ return a;
+ else
+ return new ArchitectureEventMulticaster(a, b);
+ }
+
+ public static ServiceBinderListener remove(ServiceBinderListener a, ServiceBinderListener b)
+ {
+ if ((a == null) || (a == b))
+ return null;
+ else if (a instanceof ArchitectureEventMulticaster)
+ return add (remove (((ArchitectureEventMulticaster) a).a, b),remove (((ArchitectureEventMulticaster) a).b, b));
+ else
+ return a;
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/impl/ArchitectureServiceImpl.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/impl/ArchitectureServiceImpl.java
new file mode 100644
index 0000000..c7518a1
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/impl/ArchitectureServiceImpl.java
@@ -0,0 +1,171 @@
+/*
+ * 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.servicebinder.impl;
+
+import org.apache.felix.servicebinder.InstanceReference;
+import org.apache.felix.servicebinder.Lifecycle;
+import org.apache.felix.servicebinder.architecture.ArchitectureService;
+import org.apache.felix.servicebinder.architecture.DependencyChangeEvent;
+import org.apache.felix.servicebinder.architecture.Instance;
+import org.apache.felix.servicebinder.architecture.InstanceChangeEvent;
+import org.apache.felix.servicebinder.architecture.ServiceBinderListener;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Class that implements the architecture service
+ * an object of this class is created when the
+ * service binder bundle is activated
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ArchitectureServiceImpl implements ArchitectureService, Lifecycle
+{
+ /**
+ *
+ * @uml.property name="m_listeners"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private ServiceBinderListener m_listeners = null;
+
+ /**
+ *
+ * @uml.property name="m_ref"
+ * @uml.associationEnd multiplicity="(0 1)"
+ */
+ private static ArchitectureServiceImpl m_ref = null;
+
+ private static List m_instanceReferences = new ArrayList();
+
+ public ArchitectureServiceImpl() throws Exception
+ {
+ if(m_ref == null)
+ {
+ m_ref = this;
+ }
+ }
+
+ public static InstanceReference findInstanceReference(Object obj)
+ {
+ Object[] refs=m_instanceReferences.toArray();
+
+ for(int i=0; i<refs.length ;i++)
+ {
+ InstanceReference current = (InstanceReference) refs [i];
+ if(current.getObject( )== obj)
+ {
+ return current;
+ }
+ }
+
+ return null;
+ }
+
+ public static void addInstanceReference(InstanceReference ref)
+ {
+ m_instanceReferences.add(ref);
+ }
+
+ public static void removeInstanceReference(InstanceReference ref)
+ {
+ m_instanceReferences.remove(ref);
+ }
+
+ public Instance[] getInstances()
+ {
+ Instance instances[]=new Instance[m_instanceReferences.size()];
+ instances = (Instance [])m_instanceReferences.toArray(instances);
+
+ return instances;
+ }
+
+ public static ArchitectureServiceImpl getReference()
+ {
+ return m_ref;
+ }
+
+ public void activate()
+ {
+ }
+
+ synchronized public void deactivate()
+ {
+ m_ref = null;
+ m_listeners = null; //new EventListenerList();
+ }
+
+ /**
+ * Add a service binder listener
+ **/
+ public void addServiceBinderListener(ServiceBinderListener listener)
+ {
+ //m_listeners.add(ServiceBinderListener.class, listener);
+ m_listeners = ArchitectureEventMulticaster.add(m_listeners, listener);
+ }
+
+ /**
+ * Remove a service binder listener
+ **/
+ public void removeServiceBinderListener(ServiceBinderListener listener)
+ {
+ //m_listeners.remove(ServiceBinderListener.class, listener);
+ m_listeners = ArchitectureEventMulticaster.remove(m_listeners, listener);
+ }
+
+ /**
+ * Fires an event when an instance has changed
+ **/
+ public void fireInstanceChangeEvent(InstanceChangeEvent evt)
+ {
+ try
+ {
+ if (m_listeners != null)
+ {
+ m_listeners.instanceReferenceChanged(evt);
+ }
+ }
+ catch(Exception ex)
+ {
+ // Ignore any exception
+ }
+ }
+
+ /**
+ * Fires an event when a dependency has changed
+ **/
+ public void fireDependencyChangeEvent(DependencyChangeEvent evt)
+ {
+ try
+ {
+ if (m_listeners != null)
+ {
+ m_listeners.dependencyChanged(evt);
+ }
+ }
+ catch(Exception ex)
+ {
+ // Ignore any exception
+ }
+ }
+
+
+
+}
+
+
+
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/parser/KxmlParser.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/parser/KxmlParser.java
new file mode 100644
index 0000000..4a553ff
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/parser/KxmlParser.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.servicebinder.parser;
+
+import org.apache.felix.servicebinder.XmlHandler;
+import org.kxml.parser.XmlParser;
+import org.kxml.parser.ParseEvent;
+import org.kxml.Xml;
+import org.kxml.Attribute;
+
+import java.io.Reader;
+
+import java.util.Properties;
+
+/**
+ * The KxmlParser extends the XmlParser from kxml. This is a very
+ * simple parser that does not take into account the DTD
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class KxmlParser extends XmlParser
+{
+ /**
+ * The constructor for a parser, it receives a java.io.Reader.
+ *
+ * @param r The reader
+ * @exception java.io.IOException thrown by the superclass
+ */
+ public KxmlParser(Reader r) throws java.io.IOException
+ {
+ super(r);
+ }
+
+ /**
+ * Parser from the reader provided in the constructor, and call
+ * the startElement and endElement in a KxmlHandler
+ *
+ * @param handler The handler
+ * @exception java.io.IOException thrown by the superclass
+ */
+ public void parseXML(XmlHandler handler) throws java.io.IOException, ParseException
+ {
+ ParseEvent evt=null;
+ do
+ {
+ evt = read();
+ if (evt.getType() == Xml.START_TAG)
+ {
+ Properties props = new Properties();
+ for (int i=0; i<evt.getAttributeCount();i++)
+ {
+ Attribute attr = evt.getAttribute(i);
+ props.put(attr.getName(),attr.getValue());
+ }
+ handler.startElement("uri",evt.getName(),evt.getName(),props);
+ }
+ if (evt.getType() == Xml.END_TAG)
+ {
+ handler.endElement("uri",evt.getName(),evt.getName());
+ }
+ }while(evt.getType()!=Xml.END_DOCUMENT);
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/parser/ParseException.java b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/parser/ParseException.java
new file mode 100644
index 0000000..071ecbf
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/java/org/apache/felix/servicebinder/parser/ParseException.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.servicebinder.parser;
+
+/**
+ * Exceptions thrown by the ServiceBinder.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ParseException extends Exception
+{
+ private static final long serialVersionUID = -2658823754557277056L;
+
+ public ParseException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/org.apache.felix.servicebinder/src/main/resources/metadata.dtd b/org.apache.felix.servicebinder/src/main/resources/metadata.dtd
new file mode 100644
index 0000000..6917216
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/resources/metadata.dtd
@@ -0,0 +1,29 @@
+<!--
+ DTD for org.apache.felix.servicebinder descriptor DTD
+ Version: 1.1
+-->
+
+<!ELEMENT bundle (component*)>
+<!ELEMENT component (property*,provides*,requires*)>
+ <!ATTLIST component
+ class CDATA #REQUIRED
+ >
+<!ELEMENT provides EMPTY>
+ <!ATTLIST provides
+ service CDATA #REQUIRED
+ >
+<!ELEMENT property EMPTY>
+ <!ATTLIST property
+ name CDATA #REQUIRED
+ type CDATA #REQUIRED
+ value CDATA #REQUIRED
+ >
+<!ELEMENT requires EMPTY>
+ <!ATTLIST requires
+ service CDATA #REQUIRED
+ filter CDATA #REQUIRED
+ cardinality (0..1|0..n|1..1|1..n) #REQUIRED
+ policy (static|dynamic) #REQUIRED
+ bind-method CDATA #REQUIRED
+ unbind-method CDATA #REQUIRED
+>
diff --git a/org.apache.felix.servicebinder/src/main/resources/metadata.xml b/org.apache.felix.servicebinder/src/main/resources/metadata.xml
new file mode 100644
index 0000000..18f0797
--- /dev/null
+++ b/org.apache.felix.servicebinder/src/main/resources/metadata.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--<!DOCTYPE bundle SYSTEM "metadata.dtd">-->
+<bundle>
+ <component class="org.apache.felix.servicebinder.impl.ArchitectureServiceImpl">
+ <provides service="org.apache.felix.servicebinder.architecture.ArchitectureService"/>
+ </component>
+</bundle>