/* * 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) || name.equals(fact.getComponentDescription().getClassName())) { 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(); } }