/* * 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.scr.impl; import java.util.ArrayList; import java.util.Dictionary; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import org.apache.felix.scr.Component; import org.apache.felix.scr.Reference; import org.osgi.framework.Bundle; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.ComponentInstance; import org.osgi.service.log.LogService; /** * The default ComponentManager. Objects of this class are responsible for managing * implementation object's lifecycle. * */ abstract class AbstractComponentManager implements Component, ComponentInstance { // the ID of this component private long m_componentId; // The state of this instance manager // methods accessing this field should be synchronized unless there is a // good reason to not be synchronized private volatile State m_state; // The metadata private ComponentMetadata m_componentMetadata; // The dependency managers that manage every dependency private List m_dependencyManagers; // A reference to the BundleComponentActivator private BundleComponentActivator m_activator; // The ServiceRegistration private volatile ServiceRegistration m_serviceRegistration; /** * There are 9 states in all. They are: Disabled, Enabled, Unsatisfied, * Registered, Factory, Active, Destroyed, Activating and Deactivating. * State Enabled is right State Unsatisfied. State Registered, Factory * and Active are the "Satisfied" state in concept. State Activating and * Deactivating are transition states. They will be changed to other state * automatically when work is done. *
* The transition cases are listed below. *
* This method ignores the enabled flag of the component metadata * and just enables as requested. *
* This method schedules the enablement for asynchronous execution. */ public final void enable() { enableInternal(); getActivator().schedule( new ComponentActivatorTask( "Enable", this ) { public void doRun() { activateInternal(); } }); } /** * Disables this component and - if active - first deactivates it. The * component may be reenabled by calling the {@link #enable()} method. *
* This method schedules the disablement for asynchronous execution. */ public final void disable() { getActivator().schedule( new ComponentActivatorTask( "Disable", this ) { public void doRun() { deactivateInternal(); disableInternal(); } }); } /** * Disposes off this component deactivating and disabling it first as * required. After disposing off the component, it may not be used anymore. *
* This method unlike the other state change methods immediately takes * action and disposes the component. The reason for this is, that this * method has to actually complete before other actions like bundle stopping * may continue. */ public void dispose() { disposeInternal(); } //---------- Component interface ------------------------------------------ public long getId() { return m_componentId; } public String getName() { return m_componentMetadata.getName(); } public Bundle getBundle() { return getActivator().getBundleContext().getBundle(); } public String getClassName() { return m_componentMetadata.getImplementationClassName(); } public String getFactory() { return m_componentMetadata.getFactoryIdentifier(); } public Reference[] getReferences() { if ( m_dependencyManagers != null && m_dependencyManagers.size() > 0 ) { return (Reference[]) m_dependencyManagers.toArray( new Reference[m_dependencyManagers.size()] ); } return null; } public boolean isImmediate() { return m_componentMetadata.isImmediate(); } public boolean isDefaultEnabled() { return m_componentMetadata.isEnabled(); } public boolean isServiceFactory() { return m_componentMetadata.getServiceMetadata() != null && m_componentMetadata.getServiceMetadata().isServiceFactory(); } public String[] getServices() { if ( m_componentMetadata.getServiceMetadata() != null ) { return m_componentMetadata.getServiceMetadata().getProvides(); } return null; } //-------------- atomic transition methods ------------------------------- /** * Disposes off this component deactivating and disabling it first as * required. After disposing off the component, it may not be used anymore. *
* This method unlike the other state change methods immediately takes
* action and disposes the component. The reason for this is, that this
* method has to actually complete before other actions like bundle stopping
* may continue.
*/
synchronized final void enableInternal()
{
m_state.enableInternal( this );
}
synchronized final void disableInternal()
{
m_state.disableInternal( this );
}
synchronized final void activateInternal()
{
m_state.activateInternal( this );
}
synchronized final void deactivateInternal()
{
m_state.deactivateInternal( this );
}
synchronized final void disposeInternal()
{
m_state.deactivateInternal( this );
// For the sake of the performance(no need to loadDependencyManagers again),
// the disable transition is integrated into the destroy transition.
// That is to say, state "Enabled" goes directly into state "Desctroyed"
// in the event "dipose".
m_state.disposeInternal( this );
}
final ServiceReference getServiceReference()
{
// This method is not synchronized even though it accesses the state.
// The reason for this is that we just want to have the state return
// the service reference which comes from the service registration.
// The only thing that may happen is that the service registration is
// still set on this instance but the service has already been
// unregistered. In this case an IllegalStateException may be thrown
// which we just catch and ignore returning null
State state = m_state;
try
{
return state.getServiceReference( this );
}
catch ( IllegalStateException ise )
{
// may be thrown if the service has already been unregistered but
// the service registration is still set on this component manager
// we ignore this exception and assume there is no service reference
}
return null;
}
//---------- Component handling methods ----------------------------------
/**
* Method is called by {@link #activate()} in STATE_ACTIVATING or by
* {@link DelayedComponentManager#getService(Bundle, ServiceRegistration)}
* in STATE_REGISTERED.
*
* @return true if creation of the component succeeded. If
* false is returned, the cause should have been logged.
*/
protected abstract boolean createComponent();
protected abstract void deleteComponent();
/**
* Returns the service object to be registered if the service element is
* specified.
*
* Extensions of this class may overwrite this method to return a * ServiceFactory to register in the case of a delayed or a service * factory component. * * @return */ protected abstract Object getService(); final State getSatisfiedState() { if ( m_componentMetadata.isFactory() ) { return Factory.getInstance(); } else if ( m_componentMetadata.isImmediate() ) { return Active.getInstance(); } else { return Registered.getInstance(); } } protected ServiceRegistration registerService() { if ( getComponentMetadata().getServiceMetadata() != null ) { log( LogService.LOG_DEBUG, "registering services", m_componentMetadata, null ); // get a copy of the component properties as service properties Dictionary serviceProperties = copyTo( null, getProperties() ); return getActivator().getBundleContext().registerService( getComponentMetadata().getServiceMetadata().getProvides(), getService(), serviceProperties ); } return null; } // 5. Register provided services protected void registerComponentService() { m_serviceRegistration = registerService(); } protected void unregisterComponentService() { if ( m_serviceRegistration != null ) { log( LogService.LOG_DEBUG, "unregistering the services", m_componentMetadata, null ); m_serviceRegistration.unregister(); m_serviceRegistration = null; } } //********************************************************************************************************** BundleComponentActivator getActivator() { return m_activator; } final ServiceRegistration getServiceRegistration() { return m_serviceRegistration; } void clear() { m_activator = null; m_dependencyManagers.clear(); } void log( int level, String message, ComponentMetadata metadata, Throwable ex ) { BundleComponentActivator activator = getActivator(); if ( activator != null ) { activator.log( level, message, metadata, ex ); } } /** * Activates this component if satisfied. If any of the dependencies is * not met, the component is not activated and remains unsatisifed. *
* This method schedules the activation for asynchronous execution. */ public final void activate() { getActivator().schedule( new ComponentActivatorTask( "Activate", this ) { public void doRun() { activateInternal(); } }); } /** * Reconfigures this component by deactivating and activating it. During * activation the new configuration data is retrieved from the Configuration * Admin Service. */ public final void reconfigure() { log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure", m_componentMetadata, null ); reactivate(); } /** * Cycles this component by deactivating it and - if still satisfied - * activating it again asynchronously. *
* This method schedules the deactivation and reactivation for asynchronous
* execution.
*/
public final void reactivate()
{
getActivator().schedule(new ComponentActivatorTask( "Reactivate", this ) {
public void doRun()
{
deactivateInternal();
activateInternal();
}
});
}
public String toString() {
return "Component: " + getName() + " (" + getId() + ")";
}
private void loadDependencyManagers( ComponentMetadata metadata )
{
List depMgrList = new ArrayList();
// If this component has got dependencies, create dependency managers for each one of them.
if ( metadata.getDependencies().size() != 0 )
{
Iterator dependencyit = metadata.getDependencies().iterator();
while ( dependencyit.hasNext() )
{
ReferenceMetadata currentdependency = (ReferenceMetadata) dependencyit.next();
DependencyManager depmanager = new DependencyManager( this, currentdependency );
depMgrList.add( depmanager );
}
}
m_dependencyManagers = depMgrList;
}
private void enableDependencyManagers() throws InvalidSyntaxException
{
Iterator it = getDependencyManagers();
while ( it.hasNext() )
{
DependencyManager dm = (DependencyManager) it.next();
dm.enable();
}
}
private boolean verifyDependencyManagers( Dictionary properties )
{
// indicates whether all dependencies are satisfied
boolean satisfied = true;
Iterator it = getDependencyManagers();
while ( it.hasNext() )
{
DependencyManager dm = (DependencyManager) it.next();
// ensure the target filter is correctly set
dm.setTargetFilter( properties );
// check whether the service is satisfied
if ( !dm.isSatisfied() )
{
// at least one dependency is not satisfied
log( LogService.LOG_INFO, "Dependency not satisfied: " + dm.getName(), m_componentMetadata, null );
satisfied = false;
}
}
return satisfied;
}
Iterator getDependencyManagers()
{
return m_dependencyManagers.iterator();
}
DependencyManager getDependencyManager(String name)
{
Iterator it = getDependencyManagers();
while ( it.hasNext() )
{
DependencyManager dm = (DependencyManager) it.next();
if ( name.equals(dm.getName()) )
{
return dm;
}
}
// not found
return null;
}
private void disposeDependencyManagers()
{
Iterator it = getDependencyManagers();
while ( it.hasNext() )
{
DependencyManager dm = (DependencyManager) it.next();
dm.dispose();
}
}
/**
* Get the object that is implementing this descriptor
*
* @return the object that implements the services
*/
public abstract Object getInstance();
public abstract Dictionary getProperties();
/**
* Copies the properties from the source Dictionary
* into the target Dictionary.
*
* @param target The Dictionary into which to copy the
* properties. If null a new Hashtable is
* created.
* @param source The Dictionary providing the properties to
* copy. If null or empty, nothing is copied.
*
* @return The target is returned, which may be empty if
* source is null or empty and
* target was null.
*/
protected Dictionary copyTo( Dictionary target, Dictionary source )
{
if ( target == null )
{
target = new Hashtable();
}
if ( source != null && !source.isEmpty() )
{
for ( Enumeration ce = source.keys(); ce.hasMoreElements(); )
{
Object key = ce.nextElement();
target.put( key, source.get( key ) );
}
}
return target;
}
/**
*
*/
public ComponentMetadata getComponentMetadata()
{
return m_componentMetadata;
}
public int getState()
{
return m_state.getState();
}
protected State state()
{
return m_state;
}
/**
* sets the state of the manager
**/
void changeState( State newState )
{
log( LogService.LOG_DEBUG,
"State transition : " + m_state + " -> " + newState,
m_componentMetadata, null );
m_state = newState;
}
}