blob: 1fe3a10a9dd2636af16d4a85a10f1e4509f6e226 [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.ipojo.composite;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;
import org.apache.felix.ipojo.ComponentFactory;
import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.ConfigurationException;
import org.apache.felix.ipojo.Handler;
import org.apache.felix.ipojo.HandlerFactory;
import org.apache.felix.ipojo.HandlerManager;
import org.apache.felix.ipojo.IPojoContext;
import org.apache.felix.ipojo.InstanceStateListener;
import org.apache.felix.ipojo.ServiceContext;
import org.apache.felix.ipojo.architecture.InstanceDescription;
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.util.Logger;
import org.osgi.framework.BundleContext;
/**
* iPOJO Composite manager. The composite manager class manages one instance of
* a component type which is a composition. It manages component lifecycle, and
* handlers...
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class CompositeManager implements ComponentInstance, InstanceStateListener {
/**
* The context of the component.
*/
private final BundleContext m_context;
/**
* Parent factory (ComponentFactory).
*/
private final CompositeFactory m_factory;
/**
* Composite Handler list.
*/
private HandlerManager[] m_handlers;
/**
* Instance State Listener List.
*/
private List m_listeners = new ArrayList();
/**
* Internal service context of the composition.
*/
private CompositeServiceContext m_internalContext;
/**
* The instance description.
*/
private final CompositeInstanceDescription m_description;
/**
* Name of the component instance.
*/
private String m_name;
/**
* Component state (STOPPED at the beginning).
*/
private int m_state = STOPPED;
/**
* Logger.
*/
private Logger m_logger;
/**
* Construct a new Component Manager.
* @param factory : the factory managing the instance manager
* @param context : the bundle context to give to the instance
* @param handlers : the handlers to plug
*/
public CompositeManager(CompositeFactory factory, BundleContext context, HandlerManager[] handlers) {
m_factory = factory;
m_context = context;
// Initialize the service context.
m_internalContext = new CompositeServiceContext(m_context, this);
m_handlers = handlers;
m_description = new CompositeInstanceDescription(m_factory.getComponentDescription(), this);
m_logger = new Logger(m_context, this);
}
/**
* Plug the given handler to the current container.
* @param handler : the handler to plug.
*/
public synchronized void addCompositeHandler(HandlerManager handler) {
if (m_handlers.length > 0) {
HandlerManager[] newInstances = new HandlerManager[m_handlers.length + 1];
System.arraycopy(m_handlers, 0, newInstances, 0, m_handlers.length);
newInstances[m_handlers.length] = handler;
m_handlers = newInstances;
} else {
m_handlers = new HandlerManager[] { handler };
}
}
/**
* Add an instance to the created instance list.
* @param listener : the instance state listener to add.
* @see org.apache.felix.ipojo.ComponentInstance#addInstanceStateListener(org.apache.felix.ipojo.InstanceStateListener)
*/
public void addInstanceStateListener(InstanceStateListener listener) {
synchronized (m_listeners) {
m_listeners.add(listener);
}
}
/**
* Configure the instance manager. Stop the existing handler, clear the
* handler list, change the metadata, recreate the handler
*
* @param metadata : the component type metadata
* @param configuration : the configuration of the instance
* @throws ConfigurationException : occurs when the component type are incorrect.
*/
public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
// Add the name
m_name = (String) configuration.get("instance.name");
// Create the standard handlers and add these handlers to the list
for (int i = 0; i < m_handlers.length; i++) {
m_handlers[i].init(this, metadata, configuration);
}
}
/**
* Dispose the instance.
* @see org.apache.felix.ipojo.ComponentInstance#dispose()
*/
public void dispose() {
if (m_state > STOPPED) { stop(); }
for (int i = 0; i < m_listeners.size(); i++) {
((InstanceStateListener) m_listeners.get(i)).stateChanged(this, DISPOSED);
}
m_factory.disposed(this);
// Cleaning
m_state = DISPOSED;
for (int i = m_handlers.length - 1; i > -1; i--) {
m_handlers[i].dispose();
}
m_handlers = new HandlerManager[0];
m_listeners.clear();
}
/**
* Return a specified handler.
* @param name : class name of the handler to find
* @return : the handler, or null if not found
*/
public CompositeHandler getCompositeHandler(String name) {
for (int i = 0; i < m_handlers.length; i++) {
HandlerFactory fact = (HandlerFactory) m_handlers[i].getFactory();
if (fact.getHandlerName().equals(name) || fact.getComponentDescription().getClassName().equals(name)) {
return (CompositeHandler) m_handlers[i].getHandler();
}
}
return null;
}
/**
* Get the bundle context used by this instance.
* @return the parent context of the instance.
* @see org.apache.felix.ipojo.ComponentInstance#getContext()
*/
public BundleContext getContext() {
return m_context;
}
/**
* Get the factory which create this instance.
* @return the factory of the component
* @see org.apache.felix.ipojo.ComponentInstance#getFactory()
*/
public ComponentFactory getFactory() {
return m_factory;
}
/**
* Get the global bundle context.
* @return the global bundle context.
*/
public BundleContext getGlobalContext() {
IPojoContext context = (IPojoContext) m_context;
return context.getGlobalContext();
}
/**
* Return the instance description of this instance.
* @return the instance description.
* @see org.apache.felix.ipojo.ComponentInstance#getInstanceDescription()
*/
public InstanceDescription getInstanceDescription() {
return m_description;
}
/**
* Get the instance name.
* @return the instance name
* @see org.apache.felix.ipojo.ComponentInstance#getInstanceName()
*/
public String getInstanceName() {
return m_name;
}
/**
* Get the parent service context.
* @return the parent service context.
*/
public ServiceContext getParentServiceContext() {
IPojoContext context = (IPojoContext) m_context;
return context.getServiceContext();
}
/**
* REturn the list of handlers plugged on this instance.
* @return the list of the registered handlers.
*/
public CompositeHandler[] getRegistredCompositeHandlers() {
CompositeHandler[] handler = new CompositeHandler[m_handlers.length];
for (int i = 0; i < m_handlers.length; i++) {
handler[i] = (CompositeHandler) m_handlers[i].getHandler();
}
return handler;
}
/**
* Get the internal service context of this instance.
* @return the internal service context.
*/
public ServiceContext getServiceContext() {
return m_internalContext;
}
/**
* Get the actual state of the instance.
* @return the actual state of the instance
* @see org.apache.felix.ipojo.ComponentInstance#getState()
*/
public int getState() {
return m_state;
}
/**
* Check if the instance is started.
* @return true if the instance is started.
* @see org.apache.felix.ipojo.ComponentInstance#isStarted()
*/
public boolean isStarted() {
return m_state > STOPPED;
}
/**
* Reconfigure the current instance.
* @param configuration : the new instance configuration.
* @see org.apache.felix.ipojo.ComponentInstance#reconfigure(java.util.Dictionary)
*/
public void reconfigure(Dictionary configuration) {
m_logger.log(Logger.INFO, "Reconfiguring composite with " + configuration);
for (int i = 0; i < m_handlers.length; i++) {
m_logger.log(Logger.INFO, "Delegating reconfiguration to " + m_handlers[i].getClassName());
m_handlers[i].getHandler().reconfigure(configuration);
}
}
/**
* Remove an instance state listener.
* @param listener : the listener to remove
* @see org.apache.felix.ipojo.ComponentInstance#removeInstanceStateListener(org.apache.felix.ipojo.InstanceStateListener)
*/
public void removeInstanceStateListener(InstanceStateListener listener) {
synchronized (m_listeners) {
m_listeners.remove(listener);
}
}
/**
* Set the state of the component.
* if the state changed call the stateChanged(int) method on the handlers.
* @param state : new state
*/
public void setState(int state) {
if (m_state != state) {
if (state > m_state) {
// The state increases (Stopped = > IV, IV => V) => invoke handlers from the higher priority to the lower
m_state = state;
for (int i = 0; i < m_handlers.length; i++) {
m_handlers[i].getHandler().stateChanged(state);
}
} else {
// The state decreases (V => IV, IV = > Stopped, Stopped => Disposed)
m_state = state;
for (int i = m_handlers.length - 1; i > -1; i--) {
m_handlers[i].getHandler().stateChanged(state);
}
}
for (int i = 0; i < m_listeners.size(); i++) {
((InstanceStateListener) m_listeners.get(i)).stateChanged(this, state);
}
}
}
/**
* Start the instance manager.
*/
public synchronized void start() {
if (m_state > STOPPED) {
return;
} // Instance already started
// The new state of the component is UNRESOLVED
m_state = INVALID;
m_internalContext.start(); // Turn on the factory tracking
// Plug handler descriptions
Handler[] handlers = getRegistredCompositeHandlers();
for (int i = 0; i < handlers.length; i++) {
m_description.addHandler(handlers[i].getDescription());
}
for (int i = 0; i < m_handlers.length; i++) {
m_handlers[i].start();
m_handlers[i].addInstanceStateListener(this);
}
for (int i = 0; i < m_handlers.length; i++) {
if (m_handlers[i].getState() != VALID) {
setState(INVALID);
return;
}
}
setState(VALID);
}
/**
* State Change listener callback.
* This method is notified at each time a plugged handler becomes invalid.
* @param instance : changing instance
* @param newState : new state
* @see org.apache.felix.ipojo.InstanceStateListener#stateChanged(org.apache.felix.ipojo.ComponentInstance, int)
*/
public synchronized void stateChanged(ComponentInstance instance, int newState) {
if (m_state <= STOPPED) { return; }
// Update the component state if necessary
if (newState == INVALID && m_state == VALID) {
// Need to update the state to UNRESOLVED
setState(INVALID);
return;
}
if (newState == VALID && m_state == INVALID) {
// An handler becomes valid => check if all handlers are valid
boolean isValid = true;
for (int i = 0; i < m_handlers.length; i++) {
isValid = isValid && m_handlers[i].getState() == VALID;
}
if (isValid) { setState(VALID); }
}
if (newState == DISPOSED) {
kill();
}
}
/**
* Stop the instance manager.
*/
public synchronized void stop() {
if (m_state <= STOPPED) {
return;
} // Instance already stopped
setState(INVALID);
// Stop all the handlers
for (int i = m_handlers.length - 1; i > -1; i--) {
m_handlers[i].removeInstanceStateListener(this);
m_handlers[i].stop();
}
m_internalContext.stop(); // Turn off the factory tracking
m_state = STOPPED;
for (int i = 0; i < m_listeners.size(); i++) {
((InstanceStateListener) m_listeners.get(i)).stateChanged(this, STOPPED);
}
}
/**
* Kill the current instance.
* Only the factory of this instance can call this method.
*/
protected synchronized void kill() {
if (m_state > STOPPED) { stop(); }
for (int i = 0; i < m_listeners.size(); i++) {
((InstanceStateListener) m_listeners.get(i)).stateChanged(this, DISPOSED);
}
// Cleaning
m_state = DISPOSED;
for (int i = m_handlers.length - 1; i > -1; i--) {
m_handlers[i].dispose();
}
m_handlers = new HandlerManager[0];
m_listeners.clear();
}
}