| /* |
| * 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; |
| |
| import java.util.Dictionary; |
| |
| import org.apache.felix.ipojo.architecture.Architecture; |
| import org.apache.felix.ipojo.architecture.ComponentDescription; |
| import org.apache.felix.ipojo.architecture.InstanceDescription; |
| import org.apache.felix.ipojo.composite.CompositeServiceContext; |
| import org.apache.felix.ipojo.metadata.Element; |
| import org.apache.felix.ipojo.util.Logger; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceReference; |
| |
| /** |
| * 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 { |
| |
| /** |
| * Parent factory (ComponentFactory). |
| */ |
| private ComponentFactory m_factory; |
| |
| /** |
| * Name of the component instance. |
| */ |
| private String m_name; |
| |
| /** |
| * The context of the component. |
| */ |
| private BundleContext m_context; |
| |
| /** |
| * Composite Handler list. |
| */ |
| private CompositeHandler[] m_handlers = new CompositeHandler[0]; |
| |
| /** |
| * Component state (STOPPED at the beginning). |
| */ |
| private int m_state = STOPPED; |
| |
| /** |
| * Instance State Listener List. |
| */ |
| private InstanceStateListener[] m_instanceListeners = new InstanceStateListener[0]; |
| |
| |
| /** |
| * Component type information. |
| */ |
| private ComponentDescription m_componentDesc; |
| |
| /** |
| * Internal service context of the composition. |
| */ |
| private CompositeServiceContext m_internalContext; |
| |
| // Constructor |
| /** |
| * Construct a new Component Manager. |
| * |
| * @param factory : the factory managing the instance manager |
| * @param bc : the bundle context to give to the instance |
| */ |
| public CompositeManager(ComponentFactory factory, BundleContext bc) { |
| m_factory = factory; |
| m_context = bc; |
| // Initialize the service context. |
| m_internalContext = new CompositeServiceContext(m_context, this); |
| m_factory.getLogger().log(Logger.INFO, "[Bundle " + m_context.getBundle().getBundleId() + "] Create an instance manager from the factory " + m_factory); |
| } |
| |
| /** |
| * Configure the instance manager. Stop the existings handler, clear the |
| * handler list, change the metadata, recreate the handler |
| * |
| * @param cm : the component type metadata |
| * @param configuration : the configuration of the instance |
| */ |
| public void configure(Element cm, Dictionary configuration) { |
| // Stop all previous registred handler |
| if (m_handlers.length != 0) { |
| stop(); |
| } |
| |
| // Clear the handler list |
| m_handlers = new CompositeHandler[0]; |
| |
| // ComponentInfo initialization |
| m_componentDesc = new ComponentDescription(m_factory.getName()); |
| |
| // Add the name |
| m_name = (String) configuration.get("name"); |
| |
| // Create the standard handlers and add these handlers to the list |
| for (int i = 0; i < IPojoConfiguration.INTERNAL_COMPOSITE_HANDLERS.length; i++) { |
| // Create a new instance |
| try { |
| CompositeHandler h = (CompositeHandler) IPojoConfiguration.INTERNAL_COMPOSITE_HANDLERS[i].newInstance(); |
| h.configure(this, cm, configuration); |
| } catch (InstantiationException e) { |
| m_factory.getLogger().log(Logger.ERROR, |
| "[" + m_name + "] Cannot instantiate the handler " + IPojoConfiguration.INTERNAL_HANDLERS[i] + " : " + e.getMessage()); |
| } catch (IllegalAccessException e) { |
| m_factory.getLogger().log(Logger.ERROR, |
| "[" + m_name + "] Cannot instantiate the handler " + IPojoConfiguration.INTERNAL_HANDLERS[i] + " : " + e.getMessage()); |
| } |
| } |
| |
| // Look for namespaces |
| for (int i = 0; i < cm.getNamespaces().length; i++) { |
| if (!cm.getNamespaces()[i].equals("")) { |
| // It is not an internal handler, try to load it |
| try { |
| Class c = m_context.getBundle().loadClass(cm.getNamespaces()[i]); |
| CompositeHandler h = (CompositeHandler) c.newInstance(); |
| h.configure(this, cm, configuration); |
| } catch (ClassNotFoundException e) { |
| m_factory.getLogger() |
| .log(Logger.ERROR, "[" + m_name + "] Cannot instantiate the handler " + cm.getNamespaces()[i] + " : " + e.getMessage()); |
| } catch (InstantiationException e) { |
| m_factory.getLogger() |
| .log(Logger.ERROR, "[" + m_name + "] Cannot instantiate the handler " + cm.getNamespaces()[i] + " : " + e.getMessage()); |
| } catch (IllegalAccessException e) { |
| m_factory.getLogger() |
| .log(Logger.ERROR, "[" + m_name + "] Cannot instantiate the handler " + cm.getNamespaces()[i] + " : " + e.getMessage()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Return the component type description of this instance. |
| * @return the component type information. |
| * @see org.apache.felix.ipojo.ComponentInstance#getComponentDescription() |
| */ |
| public ComponentDescription getComponentDescription() { |
| return m_componentDesc; |
| } |
| |
| /** |
| * Return the instance description of this instance. |
| * @return the instance description. |
| * @see org.apache.felix.ipojo.ComponentInstance#getInstanceDescription() |
| */ |
| public synchronized InstanceDescription getInstanceDescription() { |
| int componentState = getState(); |
| InstanceDescription instanceDescription = new InstanceDescription(m_name, componentState, getContext().getBundle().getBundleId(), m_componentDesc); |
| CompositeHandler[] handlers = getRegistredCompositeHandlers(); |
| for (int i = 0; i < handlers.length; i++) { |
| instanceDescription.addHandler(handlers[i].getDescription()); |
| } |
| |
| // Get instances description of internal instance |
| ServiceReference[] refs; |
| try { |
| refs = m_internalContext.getServiceReferences(Architecture.class.getName(), null); |
| if (refs != null) { |
| for (int i = 0; i < refs.length; i++) { |
| Architecture arch = (Architecture) m_internalContext.getService(refs[i]); |
| instanceDescription.addInstance(arch.getInstanceDescription()); |
| m_internalContext.ungetService(refs[i]); |
| } |
| } |
| } catch (InvalidSyntaxException e) { |
| e.printStackTrace(); // Should not happen |
| } |
| return instanceDescription; |
| } |
| |
| /** |
| * REturn the list of handlers plugged on this instace. |
| * @return the list of the registred handlers. |
| */ |
| public CompositeHandler[] getRegistredCompositeHandlers() { |
| return m_handlers; |
| } |
| |
| /** |
| * 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++) { |
| if (m_handlers[i].getClass().getName().equalsIgnoreCase(name)) { |
| return m_handlers[i]; |
| } |
| } |
| return null; |
| } |
| |
| // ===================== Lifecycle management ===================== |
| |
| /** |
| * Start the instance manager. |
| */ |
| public void start() { |
| if (m_state != STOPPED) { |
| return; |
| } // Instance already started |
| |
| // Start all the handlers |
| m_factory.getLogger().log(Logger.INFO, "[" + m_name + "] Start the instance manager with " + m_handlers.length + " handlers"); |
| |
| // The new state of the component is UNRESOLVED |
| m_state = INVALID; |
| |
| m_internalContext.start(); // Turn on the factory tracking |
| |
| for (int i = 0; i < m_handlers.length; i++) { |
| m_handlers[i].start(); |
| } |
| |
| // Defines the state of the component : |
| checkInstanceState(); |
| } |
| |
| /** |
| * Stop the instance manager. |
| */ |
| public 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].stop(); |
| } |
| |
| m_internalContext.stop(); // Turn off the factory tracking |
| m_state = STOPPED; |
| |
| for (int i = 0; i < m_instanceListeners.length; i++) { |
| m_instanceListeners[i].stateChanged(this, STOPPED); |
| } |
| } |
| |
| /** |
| * Dispose the instance. |
| * @see org.apache.felix.ipojo.ComponentInstance#dispose() |
| */ |
| public void dispose() { |
| if (m_state > STOPPED) { |
| stop(); |
| } |
| |
| for (int i = 0; i < m_instanceListeners.length; i++) { |
| m_instanceListeners[i].stateChanged(this, DISPOSED); |
| } |
| |
| m_factory.disposed(this); |
| |
| // Cleaning |
| m_state = DISPOSED; |
| m_handlers = new CompositeHandler[0]; |
| m_instanceListeners = new InstanceStateListener[0]; |
| } |
| |
| /** |
| * Kill the current instance. |
| * Only the factory of this instance can call this method. |
| */ |
| protected void kill() { |
| if (m_state > STOPPED) { |
| stop(); |
| } |
| |
| for (int i = 0; i < m_instanceListeners.length; i++) { |
| m_instanceListeners[i].stateChanged(this, DISPOSED); |
| } |
| |
| // Cleaning |
| m_state = DISPOSED; |
| m_handlers = new CompositeHandler[0]; |
| m_instanceListeners = new InstanceStateListener[0]; |
| } |
| |
| /** |
| * Set the state of the component. |
| * Ff the state changed call the stateChanged(int) method on the handlers. |
| * @param state : new state |
| */ |
| public void setState(int state) { |
| if (m_state != state) { |
| |
| // Log the state change |
| if (state == INVALID) { |
| m_factory.getLogger().log(Logger.INFO, "[" + m_name + "] State -> INVALID"); |
| } |
| if (state == VALID) { |
| m_factory.getLogger().log(Logger.INFO, "[" + m_name + "] State -> VALID"); |
| } |
| |
| // The state changed call the handler stateChange method |
| m_state = state; |
| for (int i = m_handlers.length - 1; i > -1; i--) { |
| m_handlers[i].stateChanged(state); |
| } |
| |
| for (int i = 0; i < m_instanceListeners.length; i++) { |
| m_instanceListeners[i].stateChanged(this, state); |
| } |
| } |
| } |
| |
| /** |
| * 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; |
| } |
| |
| /** |
| * 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) { |
| for (int i = 0; (m_instanceListeners != null) && (i < m_instanceListeners.length); i++) { |
| if (m_instanceListeners[i] == listener) { |
| return; |
| } |
| } |
| |
| if (m_instanceListeners.length > 0) { |
| InstanceStateListener[] newInstances = new InstanceStateListener[m_instanceListeners.length + 1]; |
| System.arraycopy(m_instanceListeners, 0, newInstances, 0, m_instanceListeners.length); |
| newInstances[m_instanceListeners.length] = listener; |
| m_instanceListeners = newInstances; |
| } else { |
| m_instanceListeners = new InstanceStateListener[] { listener }; |
| } |
| } |
| |
| /** |
| * 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) { |
| int idx = -1; |
| for (int i = 0; i < m_instanceListeners.length; i++) { |
| if (m_instanceListeners[i] == listener) { |
| idx = i; |
| break; |
| } |
| } |
| |
| if (idx >= 0) { |
| if ((m_instanceListeners.length - 1) == 0) { |
| m_instanceListeners = new InstanceStateListener[0]; |
| } else { |
| InstanceStateListener[] newInstances = new InstanceStateListener[m_instanceListeners.length - 1]; |
| System.arraycopy(m_instanceListeners, 0, newInstances, 0, idx); |
| if (idx < newInstances.length) { |
| System.arraycopy(m_instanceListeners, idx + 1, newInstances, idx, newInstances.length - idx); |
| } |
| m_instanceListeners = newInstances; |
| } |
| } |
| } |
| |
| // ===================== end Lifecycle management ===================== |
| |
| // ================== Class & Instance management =================== |
| |
| /** |
| * 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; |
| } |
| |
| // ======================== Handlers Management ====================== |
| |
| /** |
| * Register the given handler to the current instance manager. |
| * |
| * @param h : the handler to register |
| */ |
| public void register(CompositeHandler h) { |
| for (int i = 0; (m_handlers != null) && (i < m_handlers.length); i++) { |
| if (m_handlers[i] == h) { |
| return; |
| } |
| } |
| |
| if (m_handlers != null) { |
| CompositeHandler[] newList = new CompositeHandler[m_handlers.length + 1]; |
| System.arraycopy(m_handlers, 0, newList, 0, m_handlers.length); |
| newList[m_handlers.length] = h; |
| m_handlers = newList; |
| } |
| } |
| |
| /** |
| * Unregister the given handler. |
| * |
| * @param h : the handler to unregiter |
| */ |
| public void unregister(CompositeHandler h) { |
| int idx = -1; |
| for (int i = 0; i < m_handlers.length; i++) { |
| if (m_handlers[i] == h) { |
| idx = i; |
| break; |
| } |
| } |
| |
| if (idx >= 0) { |
| if ((m_handlers.length - 1) == 0) { |
| m_handlers = new CompositeHandler[0]; |
| } else { |
| CompositeHandler[] newList = new CompositeHandler[m_handlers.length - 1]; |
| System.arraycopy(m_handlers, 0, newList, 0, idx); |
| if (idx < newList.length) { |
| System.arraycopy(m_handlers, idx + 1, newList, idx, newList.length - idx); |
| } |
| m_handlers = newList; |
| } |
| } |
| } |
| |
| /** |
| * 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; |
| } |
| |
| /** |
| * Check the state of all handlers. |
| */ |
| public void checkInstanceState() { |
| m_factory.getLogger().log(Logger.INFO, "[" + m_name + "] Check the instance state"); |
| boolean isValid = true; |
| for (int i = 0; i < m_handlers.length; i++) { |
| boolean b = m_handlers[i].isValid(); |
| isValid = isValid && b; |
| } |
| |
| // Update the component state if necessary |
| if (!isValid && m_state == VALID) { |
| // Need to update the state to UNRESOLVED |
| setState(INVALID); |
| return; |
| } |
| if (isValid && m_state == INVALID) { |
| setState(VALID); |
| } |
| } |
| |
| /** |
| * Get the instance name. |
| * @return the instance name |
| * @see org.apache.felix.ipojo.ComponentInstance#getInstanceName() |
| */ |
| public String getInstanceName() { |
| return m_name; |
| } |
| |
| /** |
| * Reconfigure the current instance. |
| * @param configuration : the new instance ocnfiguration. |
| * @see org.apache.felix.ipojo.ComponentInstance#reconfigure(java.util.Dictionary) |
| */ |
| public void reconfigure(Dictionary configuration) { |
| for (int i = 0; i < m_handlers.length; i++) { |
| m_handlers[i].reconfigure(configuration); |
| } |
| } |
| |
| /** |
| * Get the internal service context of this instance. |
| * @return the internal service context. |
| */ |
| public ServiceContext getServiceContext() { |
| return m_internalContext; |
| } |
| } |