blob: ccf9fff5b0a8941538e0163d81f072f368a577e9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.felix.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:dev@felix.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;
}
}
}