Package org.apache.felix.ipojo

Source Code of org.apache.felix.ipojo.InstanceManager

/*
* 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 org.apache.felix.ipojo.architecture.InstanceDescription;
import org.apache.felix.ipojo.extender.internal.linker.InstanceBundleContextAware;
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.parser.FieldMetadata;
import org.apache.felix.ipojo.parser.MethodMetadata;
import org.apache.felix.ipojo.util.Logger;
import org.apache.felix.ipojo.util.Property;
import org.osgi.framework.BundleContext;

import java.lang.reflect.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;

/**
* This class defines the container of primitive instances. It manages content initialization
* and handlers cooperation.
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class InstanceManager implements ComponentInstance, InstanceStateListener, InstanceBundleContextAware {
    /**
     * The name of the component instance.
     */
    protected String m_name;

    /**
     * The name of the component type implementation class.
     */
    protected String m_className;

    /**
     * The handler object list.
     */
    protected final HandlerManager[] m_handlers;

    /**
     * The current instance state ({@link ComponentInstance#STOPPED} at the beginning).
     * Possible value are
     * <li>{@link ComponentInstance#INVALID}</li>
     * <li>{@link ComponentInstance#VALID}</li>
     * <li>{@link ComponentInstance#DISPOSED}</li>
     * <li>{@link ComponentInstance#STOPPED}</li>
     */
    protected int m_state = STOPPED;

    /**
     * The instance state listener list.
     *
     * @see InstanceStateListener
     */
    protected List m_listeners = null;

    /**
     * The content of the current instance.
     */
    protected List m_pojoObjects;

    /**
     * The instance factory.
     */
    private final ComponentFactory m_factory;

    /**
     * The instance logger.
     */
    private final Logger m_logger;

    /**
     * The instance description.
     */
    private final PrimitiveInstanceDescription m_description;

    /**
     * The bundle context of the instance.
     */
    private final BundleContext m_context;

    /**
     * The map [field, {@link FieldInterceptor} list] storing interceptors monitoring fields.
     * Once configured, this map can't change.
     */
    private Map m_fieldRegistration;

    /**
     * the map [method identifier, {@link MethodInterceptor} list] interested
     * by the method.
     * Once configured, this map can't change.
     */
    private Map m_methodRegistration;

    /**
     * the map (sorted by parameter index) or {@link ConstructorInjector} interested by
     * injecting constructor parameter.
     * Once configured, this list can't change.
     */
    private Map m_constructorRegistration;

    /**
     * The manipulated class.
     * Once set, this field doesn't change.
     */
    private Class m_clazz;

    /**
     * The factory method used to create content objects.
     * If <code>null</code>, the regular constructor is used.
     * Once set, this field is immutable.
     */
    private String m_factoryMethod = null;

    /**
     * Is the component instance state changing?
     */
    private boolean m_inTransition = false;

    /**
     * The queue of stored state changed.
     */
    private List m_stateQueue = new ArrayList();

    /**
     * The map of [field, value], storing POJO managed
     * field value.
     */
    private Map m_fields = new HashMap();

    /**
     * The Map storing the Method objects by ids.
     * [id=>{@link Method}].
     */
    private Map m_methods = new HashMap();

    /**
     * The instance's bundle context.
     */
    private BundleContext m_instanceContext;


    /**
     * Creates a new Component Manager.
     * The instance is not initialized.
     *
     * @param factory  the factory managing the instance manager
     * @param context  the bundle context to give to the instance
     * @param handlers handler object array
     */
    public InstanceManager(ComponentFactory factory, BundleContext context, HandlerManager[] handlers) {
        m_factory = factory;
        m_context = context;
        m_handlers = handlers;
        m_description = new PrimitiveInstanceDescription(m_factory.getComponentDescription(), this);
        m_logger = new Logger(m_context, this);
    }

    /**
     * Sets the instance bundle context.
     *
     * @param context the bundle context of the bundle having declared the instance
     * @since 1.11.2
     */
    public void setInstanceBundleContext(BundleContext context) {
        m_instanceContext = context;
    }

    /**
     * The instance logger.
     *
     * @return the logger
     */
    public Logger getLogger() {
        return m_logger;
    }

    /**
     * Configures the instance manager.
     * Sets the class name, and the instance name as well as the factory method.
     * Initializes handlers.
     *
     * @param metadata      the component type metadata
     * @param configuration the configuration of the instance
     * @throws ConfigurationException if the metadata are not correct
     */
    public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {
        m_className = metadata.getAttribute("classname");

        // Add the name
        m_name = (String) configuration.get(Factory.INSTANCE_NAME_PROPERTY);

        // Check if an object is injected in the instance
        Object obj = configuration.get("instance.object");
        if (obj != null) {
            m_pojoObjects = new ArrayList(1);
            m_pojoObjects.add(obj);
        }

        // Get the factory method if presents.
        m_factoryMethod = (String) metadata.getAttribute("factory-method");

        // Check if we have an instance bundle context given as property, it should not be used,
        // but it's a way to provide the instance bundle context when using the Factory service.
        // The instance context is set only if it was not already set.
        if (m_instanceContext == null) {
            m_instanceContext = (BundleContext) configuration.get("instance.bundle.context");
        }

        // Create the standard handlers and add these handlers to the list
        for (HandlerManager handler : m_handlers) {
            handler.init(this, metadata, configuration);
        }


        // Fix for Felix-3576
        handleBCInjections();


        // Check that the constructor parameter are continuous.
        if (m_constructorRegistration != null) {
            for (int i = 0; i < m_constructorRegistration.size(); i++) {
                if (!m_constructorRegistration.containsKey(i)) {
                    throw new ConfigurationException("The constructor parameter " + i + " is not managed");
                }
            }
        }
    }

    /**
     * BundleContext injection is not registered with the InstanceManager.
     * We're iterating through factory's all constructors and register first
     * BundleContext parameter as constructor injection. So rest of the code
     * don't have to do anything to handle BundleContext mixed with other
     * injections.
     *
     * @throws ConfigurationException
     */
    private void handleBCInjections() throws ConfigurationException {
        MethodMetadata[] constructors = getFactory().getPojoMetadata().getConstructors();
        for (MethodMetadata constructor : constructors) {
            String[] ctorArguments = constructor.getMethodArguments();

            for (int index = 0; index < ctorArguments.length; index++) {
                if (ctorArguments[index].equals(BundleContext.class.getName())
                        && (m_constructorRegistration == null || !m_constructorRegistration.containsKey(index))) {
                    //Check if its used with only other injections.
                    boolean injectionsConsistent = true;
                    for (int siblingIndex = 0; siblingIndex < ctorArguments.length; siblingIndex++) {
                        if (siblingIndex == index) {
                            continue;
                        }

                        String injectionType = ctorArguments[siblingIndex];
                        if (m_constructorRegistration != null && m_constructorRegistration.containsKey(siblingIndex)) {
                            ConstructorInjector siblingInjector =
                                    (ConstructorInjector) m_constructorRegistration.get(siblingIndex);
                            Class injectorClass = siblingInjector.getConstructorParameterType(siblingIndex);

                            if (injectorClass != null && !injectorClass.getName().equals(injectionType)) {
                                injectionsConsistent = false;
                                break;
                            }
                        } else {
                            injectionsConsistent = false;
                            break;
                        }
                    }

                    if (injectionsConsistent) {
                        Property contextInjection =
                                new Property("__context", null, null, index, null,
                                        BundleContext.class.getName(), this, null);

                        contextInjection.setValue(getContext());
                        register(index, contextInjection);

                        // We register the first valid BC injection.
                        break;
                    }
                }
            }
        }
    }

    /**
     * Gets the description of the current instance.
     *
     * @return the instance description.
     * @see org.apache.felix.ipojo.ComponentInstance#getInstanceDescription()
     */
    public InstanceDescription getInstanceDescription() {
        return m_description;
    }

    /**
     * Gets the list of handlers plugged (i.e. attached) on the instance.
     * This method does not need a synchronized block as the handler set is constant.
     *
     * @return the handler array of plugged handlers.
     */
    public Handler[] getRegisteredHandlers() {
        Handler[] handler = new Handler[m_handlers.length];
        for (int i = 0; i < m_handlers.length; i++) {
            handler[i] = m_handlers[i].getHandler();
        }
        return handler;
    }

    /**
     * Returns a specified handler.
     * This method allows cross-handler interactions.
     * This must does not need a synchronized block as the handler set is constant.
     *
     * @param name the class name of the handler to find or its qualified name (namespace:name)
     * @return the handler, or null if not found
     */
    public Handler getHandler(String name) {
        for (int i = 0; i < m_handlers.length; i++) {
            HandlerFactory fact = (HandlerFactory) m_handlers[i].getHandler().getHandlerManager().getFactory();
            if (fact.getHandlerName().equals(name)) {
                return m_handlers[i].getHandler();
            }
        }
        return null;
    }

    /**
     * Gives access to a field value of the first created pojo.
     * This method processes by analyzing both managed fields and pojo fields (by reflection).
     * If no pojo were already created try only on managed fields.
     *
     * @param fieldName the field name.
     * @return the field value, <code>null</code> is returned if the value is managed and not already set.
     */
    public synchronized Object getFieldValue(String fieldName) {
        if (m_pojoObjects == null) {
            return getFieldValue(fieldName, null);
        } else {
            return getFieldValue(fieldName, m_pojoObjects.get(0)); // Use the first pojo.
        }
    }

    /**
     * Gives access to a field value to the given created pojo.
     * This method processes by analyzing both managed fields and pojo fields (by reflection).
     * If the given pojo is <code>null</code>, tries only on managed fields.
     *
     * @param fieldName the field name.
     * @param pojo      the pojo on which computing field value.
     * @return the field value, <code>null</code> is returned if the value is managed and not already set.
     */
    public synchronized Object getFieldValue(String fieldName, Object pojo) {
        Object setByContainer = null;

        if (m_fields != null) {
            setByContainer = m_fields.get(fieldName);
        }

        if (setByContainer == null && pojo != null) { // In the case of no given pojo, return null.
            // If null either the value was not already set or has the null value.
            try {
                Field field = pojo.getClass().getDeclaredField(fieldName);
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }
                return field.get(pojo);
            } catch (SecurityException e) {
                m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
            } catch (NoSuchFieldException e) {
                m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
            } catch (IllegalArgumentException e) {
                m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
            } catch (IllegalAccessException e) {
                m_logger.log(Logger.ERROR, "Cannot reflect on field " + fieldName + " to obtain the value : " + e.getMessage());
            }
            return null;
        } else {
            return setByContainer;
        }
    }

    /**
     * Starts the instance manager.
     * This method activates plugged handlers,
     * and computes the initial instance state.
     */
    public void start() {
        synchronized (this) {
            if (m_state != STOPPED) { // Instance already started
                return;
            } else {
                m_state = -2; // Temporary state.
            }
        }

        // Plug handler descriptions
        Handler[] handlers = getRegisteredHandlers();
        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].addInstanceStateListener(this);
            try {
                m_handlers[i].start();
            } catch (IllegalStateException e) {
                m_logger.log(Logger.ERROR, e.getMessage());
                stop();
                throw e;
            }
        }

        // Is an object already contained (i.e. injected)
        if (m_pojoObjects != null && !m_pojoObjects.isEmpty()) {
            managedInjectedObject();
        }

        for (int i = 0; i < m_handlers.length; i++) {
            if (m_handlers[i].getState() != VALID) {
                setState(INVALID);
                return;
            }
        }
        setState(VALID);
    }

    /**
     * Stops the instance manager.
     * This methods sets the instance state to {@link ComponentInstance#STOPPED},
     * disables attached handlers, and notifies listeners ({@link InstanceStateListener})
     * of the instance stopping process.
     */
    public void stop() {
        List listeners = null;
        synchronized (this) {
            if (m_state == STOPPED) { // Instance already stopped
                return;
            }
            m_stateQueue.clear();
            m_inTransition = false;
        }

        setState(INVALID); // Must be called outside a synchronized block.

        // Stop all the handlers
        for (int i = m_handlers.length - 1; i > -1; i--) {
            m_handlers[i].removeInstanceStateListener(this);
            m_handlers[i].stop();
        }

        synchronized (this) {
            m_state = STOPPED;
            if (m_listeners != null) {
                listeners = new ArrayList(m_listeners); // Stack confinement
            }
            m_pojoObjects = null;
        }

        if (listeners != null) {
            for (int i = 0; i < listeners.size(); i++) {
                ((InstanceStateListener) listeners.get(i)).stateChanged(this, STOPPED);
            }
        }
    }

    /**
     * Disposes the instance.
     * This method does the following process:
     * <li>Stop the instance is not {@link ComponentInstance#STOPPED}</li>
     * <li>Notifies listeners {@link InstanceStateListener} of the destruction</li>
     * <li>Disposes attached handlers</li>
     * <li>Clears structures</li>
     *
     * @see org.apache.felix.ipojo.ComponentInstance#dispose()
     */
    public void dispose() {
        List listeners = null;
        int state; // Will be confined in stack.
        synchronized (this) {
            state = m_state; // Stack confinement
            if (m_listeners != null) {
                listeners = new ArrayList(m_listeners); // Stack confinement
            }
            m_listeners = null;
        }

        if (state > STOPPED) { // Valid or invalid
            stop(); // Does not hold the lock.
        }

        synchronized (this) {
            m_state = DISPOSED;
        }

        for (int i = 0; listeners != null && i < listeners.size(); i++) {
            ((InstanceStateListener) listeners.get(i)).stateChanged(this, DISPOSED);
        }

        for (int i = m_handlers.length - 1; i > -1; i--) {
            m_handlers[i].dispose();
        }

        synchronized (this) {
            m_factory.disposed(this);
            m_clazz = null;
            // Do not clean registration map, so injection still works
            // after disposal for late callbacks.
        }
    }

    /**
     * Sets the state of the component instance.
     * If the state changes, calls the {@link PrimitiveHandler#stateChanged(int)} method on the attached handlers.
     * This method has a reentrant mechanism. If in the flow of the first call the method is called another times,
     * the second call is stored and executed after the first one finished.
     *
     * @param state the new state
     */
    public void setState(int state) {
        int originalState = -2;
        List listeners = null;
        synchronized (this) {
            if (m_inTransition) {
                m_stateQueue.add(new Integer(state));
                return;
            }

            if (m_state != state) {
                m_inTransition = true;
                originalState = m_state; // Stack confinement.
                m_state = state;
                if (m_listeners != null) {
                    listeners = new ArrayList(m_listeners); // Stack confinement.
                }
            }
        }

        // This section can be executed only by one thread at the same time. The m_inTransition pseudo semaphore block access to this section.
        if (m_inTransition) { // Check that we are really changing.
            if (state > originalState) {
                // The state increases (Stopped = > IV, IV => V) => invoke handlers from the higher priority to the lower
                try {
                    for (int i = 0; i < m_handlers.length; i++) {
                        m_handlers[i].getHandler().stateChanged(state);
                    }
                } catch (IllegalStateException e) {
                    // When an illegal state exception happens, the instance manager must be stopped immediately.
                    stop();
                    m_logger.log(Logger.ERROR, e.getMessage(), e);
                    return;
                }
            } else {
                // The state decreases (V => IV, IV = > Stopped, Stopped => Disposed)
                try {
                    for (int i = m_handlers.length - 1; i > -1; i--) {
                        m_handlers[i].getHandler().stateChanged(state);
                    }
                } catch (IllegalStateException e) {
                    // When an illegal state exception happens, the instance manager must be stopped immediately.
                    stop();
                    m_logger.log(Logger.ERROR, e.getMessage());
                    return;
                }
            }
        }

        if (listeners != null) {
            for (int i = 0; i < listeners.size(); i++) {
                ((InstanceStateListener) listeners.get(i)).stateChanged(this, state);
            }
        }

        synchronized (this) {
            m_inTransition = false;
            if (!m_stateQueue.isEmpty()) {
                int newState = ((Integer) (m_stateQueue.remove(0))).intValue();
                setState(newState);
            }
        }
    }

    /**
     * Gets the actual state of the instance.
     * Possible values are:
     * <li>{@link ComponentInstance#INVALID}</li>
     * <li>{@link ComponentInstance#VALID}</li>
     * <li>{@link ComponentInstance#DISPOSED}</li>
     * <li>{@link ComponentInstance#STOPPED}</li>
     *
     * @return the actual state of the component instance.
     * @see org.apache.felix.ipojo.ComponentInstance#getState()
     */
    public synchronized int getState() {
        return m_state;
    }

    /**
     * Checks if the instance is started.
     * An instance is started if the state is either
     * {@link ComponentInstance#VALID} or {@link ComponentInstance#INVALID}.
     *
     * @return <code>true</code> if the instance is started.
     * @see org.apache.felix.ipojo.ComponentInstance#isStarted()
     */
    public synchronized boolean isStarted() {
        return m_state > STOPPED;
    }

    /**
     * Registers an instance state listener.
     *
     * @param listener the listener to register.
     * @see org.apache.felix.ipojo.ComponentInstance#addInstanceStateListener(org.apache.felix.ipojo.InstanceStateListener)
     */
    public synchronized void addInstanceStateListener(InstanceStateListener listener) {
        if (m_listeners == null) {
            m_listeners = new ArrayList();
        }
        m_listeners.add(listener);
    }

    /**
     * Unregisters an instance state listener.
     *
     * @param listener the listener to unregister.
     * @see org.apache.felix.ipojo.ComponentInstance#removeInstanceStateListener(org.apache.felix.ipojo.InstanceStateListener)
     */
    public synchronized void removeInstanceStateListener(InstanceStateListener listener) {
        if (m_listeners != null) {
            m_listeners.remove(listener);
            if (m_listeners.isEmpty()) {
                m_listeners = null;
            }
        }
    }

    /**
     * Gets the factory which has created the current instance.
     *
     * @return the factory of the component
     * @see org.apache.felix.ipojo.ComponentInstance#getFactory()
     */
    public ComponentFactory getFactory() {
        return m_factory;
    }

    /**
     * Loads the manipulated class.
     */
    private void load() {
        try {
            m_clazz = m_factory.loadClass(m_className);
        } catch (ClassNotFoundException e) {
            m_logger.log(Logger.ERROR, "[" + m_name + "] Class not found during the loading phase : " + e.getMessage(), e);
            stop();
            return;
        }
    }

    /**
     * Gets the object array created by the instance.
     *
     * @return the created content objects of the component instance.
     */
    public synchronized Object[] getPojoObjects() {
        if (m_pojoObjects == null) {
            return null;
        }
        return m_pojoObjects.toArray(new Object[m_pojoObjects.size()]);
    }

    /**
     * Creates a POJO objects.
     * This method is not synchronized and does not require any locks.
     * If a {@link InstanceManager#m_factoryMethod} is specified,
     * this method called this static method to creates the object.
     * Otherwise, the methods uses the regular constructor.
     * All those methods can receive the {@link BundleContext} in
     * argument.
     *
     * @return the created object or <code>null</code> if an error
     * occurs during the creation.
     */
    protected Object createObject() {
        if (m_clazz == null) {
            load();
        }

        // The following code doesn't need to be synchronized as is deal only with immutable fields.
        Object instance = null;
        if (m_factoryMethod == null) {
            // No factory-method, we use the constructor.
            try {
                // Try to find the correct constructor.
                if (m_constructorRegistration != null) {
                    // Initialize the injected values and types
                    // We have the IM first.
                    Object[] values = new Object[m_constructorRegistration.size() + 1];
                    Class[] types = new Class[m_constructorRegistration.size() + 1];
                    values[0] = this;
                    types[0] = InstanceManager.class;

                    // Iterate over the constructor injector
                    for (int i = 0; i < m_constructorRegistration.size(); i++) {
                        ConstructorInjector injector = (ConstructorInjector)
                                m_constructorRegistration.get(new Integer(i));
                        Object v = injector.getConstructorParameter(i);
                        if (v != null) {
                            values[i + 1] = v;
                            Class t = injector.getConstructorParameterType(i);
                            if (t == null) {
                                t = v.getClass();
                            }
                            types[i + 1] = t;
                        }
                    }
                    // Find the constructor.
                    Constructor cst = m_clazz.getDeclaredConstructor(types);
                    if (!cst.isAccessible()) {
                        cst.setAccessible(true);
                    }
                    String methodId = MethodMetadata.computeMethodId(cst);
                    onEntry(null, methodId, values);
                    instance = cst.newInstance(values);
                    onExit(instance, methodId, instance);
                } else {
                    // Old semantic
                    // Try to find if there is a constructor with a bundle context as parameter :
                    try {
                        Constructor cst = m_clazz.getDeclaredConstructor(new Class[]{InstanceManager.class, BundleContext.class});
                        if (!cst.isAccessible()) {
                            cst.setAccessible(true);
                        }
                        Object[] args = new Object[]{this, m_context};
                        onEntry(null, MethodMetadata.BC_CONSTRUCTOR_ID, new Object[]{m_context});
                        instance = cst.newInstance(args);
                        onExit(instance, MethodMetadata.BC_CONSTRUCTOR_ID, instance);
                    } catch (NoSuchMethodException e) {
                        // Create an instance if no instance are already created with <init>()BundleContext
                        if (instance == null) {
                            Constructor cst = m_clazz.getDeclaredConstructor(new Class[]{InstanceManager.class});
                            if (!cst.isAccessible()) {
                                cst.setAccessible(true);
                            }
                            Object[] args = new Object[]{this};
                            onEntry(null, MethodMetadata.EMPTY_CONSTRUCTOR_ID, new Object[0]);
                            instance = cst.newInstance(args);
                            onExit(instance, MethodMetadata.EMPTY_CONSTRUCTOR_ID, instance);
                        }
                    }
                }

            } catch (IllegalAccessException e) {
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] createInstance -> The POJO constructor is not accessible : " + e.getMessage(), e);
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor is not accessible", e);
            } catch (SecurityException e) {
                m_logger.log(
                        Logger.ERROR,
                        "["
                                + m_name
                                + "] createInstance -> The POJO constructor is not accessible (security reason) : "
                                + e.getMessage(), e
                );
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor is not accessible", e);
            } catch (InvocationTargetException e) {
                m_logger.log(
                        Logger.ERROR,
                        "["
                                + m_name
                                + "] createInstance -> Cannot invoke the constructor method - the constructor throws an exception : "
                                + e.getTargetException().getMessage(), e.getTargetException()
                );
                onError(null, m_className, e.getTargetException());
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor has thrown an exception", e.getTargetException());
            } catch (NoSuchMethodException e) {
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] createInstance -> Cannot invoke the constructor (method not found) : " + e.getMessage(), e);
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor cannot be found", e);
            } catch (Throwable e) {
                // Catch every other possible error and runtime exception.
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] createInstance -> The POJO constructor invocation failed : " + e.getMessage(), e);
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the POJO constructor invocation has thrown an exception", e);
            }
        } else {
            try {
                // Build the pojo object with the factory-method.
                Method factory = null;
                // Try with the bundle context
                try {
                    factory = m_clazz.getDeclaredMethod(m_factoryMethod, new Class[]{BundleContext.class});
                    if (!factory.isAccessible()) {
                        factory.setAccessible(true);
                    }
                    Object[] args = new Object[]{m_context};
                    onEntry(null, m_className, args);
                    instance = factory.invoke(null, new Object[]{m_context});
                } catch (NoSuchMethodException e1) {
                    // Try without the bundle context
                    try {
                        factory = m_clazz.getDeclaredMethod(m_factoryMethod, new Class[0]);
                        if (!factory.isAccessible()) {
                            factory.setAccessible(true);
                        }
                        Object[] args = new Object[0];
                        onEntry(null, m_className, args);
                        instance = factory.invoke(null, args);
                    } catch (NoSuchMethodException e2) {
                        // Error : factory-method not found
                        m_logger.log(
                                Logger.ERROR,
                                "["
                                        + m_name
                                        + "] createInstance -> Cannot invoke the factory-method (method not found) : "
                                        + e2.getMessage(), e2
                        );
                        stop();
                        throw new RuntimeException("Cannot create a POJO instance, the factory-method cannot be found", e2);
                    }
                }

                // Now call the setInstanceManager method.
                // Find declaring super class.
                Class declaringClass = instance.getClass();
                Method method = null;
                while (declaringClass != null && method == null) {
                    try {
                        method = declaringClass.getDeclaredMethod("_setInstanceManager",
                                new Class[]{InstanceManager.class});
                    } catch (NoSuchMethodException e) {
                        //Do nothing
                    }

                    declaringClass = declaringClass.getSuperclass();
                }

                if (method == null) {
                    // Error : _setInstanceManager method is missing
                    m_logger
                            .log(
                                    Logger.ERROR,
                                    "["
                                            + m_name
                                            + "] createInstance -> Cannot invoke the factory-method (the _setInstanceManager method does not exist"
                            );
                    stop();
                    throw new RuntimeException("Cannot create a POJO instance, the factory-method cannot be found");
                }

                if (!method.isAccessible()) {
                    method.setAccessible(true);
                }
                method.invoke(instance, new Object[]{this});
                onExit(null, m_className, instance);

            } catch (InvocationTargetException e) {
                // Error : invocation failed
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] createInstance -> The factory-method throws an exception : " + e.getTargetException(), e.getTargetException());
                onError(null, m_className, e.getTargetException());
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the factory-method has thrown an exception", e.getTargetException());
            } catch (Throwable e) {
                // Catch every other possible error and runtime exception.
                m_logger.log(Logger.ERROR,
                        "[" + m_name + "] createInstance -> The factory-method invocation failed : " + e.getMessage(), e);
                stop();
                throw new RuntimeException("Cannot create a POJO instance, the factory-method invocation has thrown an exception", e);
            }
        }
        return instance;
    }

    /**
     * Creates an instance of the content.
     * This method needs to be called once only for singleton provided service.
     * This methods call the {@link InstanceManager#createObject()} method, and adds
     * the created object to the {@link InstanceManager#m_pojoObjects} list. Then,
     * it calls the {@link PrimitiveHandler#onCreation(Object)} methods on attached
     * handlers.
     *
     * @return a new instance or <code>null</code> if an error occurs during the
     * creation.
     */
    public Object createPojoObject() {
        Object instance = createObject();

        // Add the new instance in the instance list.
        synchronized (this) {
            if (m_pojoObjects == null) {
                m_pojoObjects = new ArrayList(1);
            }
            m_pojoObjects.add(instance);
        }
        // Call createInstance on Handlers :
        for (int i = 0; i < m_handlers.length; i++) {
            // This methods must be call without the monitor lock.
            ((PrimitiveHandler) m_handlers[i].getHandler()).onCreation(instance);
        }

        return instance;
    }

    /**
     * Deletes a POJO object.
     *
     * @param pojo the pojo to remove from the list of created pojos.
     */
    public synchronized void deletePojoObject(Object pojo) {
        if (m_pojoObjects != null) {
            m_pojoObjects.remove(pojo);
        }
    }

    /**
     * Gets the first object created by the instance.
     * If no object created, creates and returns a POJO object.
     * This methods call the {@link InstanceManager#createObject()} method, and adds
     * the created object to the {@link InstanceManager#m_pojoObjects} list. Then,
     * it calls the {@link PrimitiveHandler#onCreation(Object)} methods on attached
     * handlers.
     * <br/>
     * <p>
     * <b>TODO</b> this method has a potential race condition if two threads require a pojo
     * object at the same time. Only one object will be created, but the second thread
     * can receive the created object before the {@link PrimitiveHandler#onCreation(Object)}
     * calls.
     * </p>
     *
     * @return the pojo object of the component instance to use for singleton component
     */
    public Object getPojoObject() {
        Object pojo = null;
        boolean newPOJO = false;
        synchronized (this) {
            if (m_pojoObjects != null) {
                pojo = m_pojoObjects.get(0); // Stack confinement
            } else {
                pojo = createObject()// Stack confinement
                if (m_pojoObjects == null) {
                    m_pojoObjects = new ArrayList(1);
                }
                m_pojoObjects.add(pojo);
                newPOJO = true;
            }
        }

        // Call createInstance on Handlers :
        for (int i = 0; newPOJO && i < m_handlers.length; i++) {
            ((PrimitiveHandler) m_handlers[i].getHandler()).onCreation(pojo);
        }
        //NOTE this method allows returning a POJO object before calling the onCreation on handler:
        // a second thread get the created object before the first one (which created the object),
        // call onCreation.

        return pojo;
    }

    /**
     * Gets the manipulated class.
     * The method does not need to be synchronized.
     * Reassigning the internal class will use the same class object.
     *
     * @return the manipulated class
     */
    public Class getClazz() {
        if (m_clazz == null) {
            load();
        }
        return m_clazz;
    }

    /**
     * Configures an injected object in this container.
     */
    private void managedInjectedObject() {
        Object obj = m_pojoObjects.get(0); // Get first object.

        if (!(obj instanceof Pojo)) {
            // Error, the injected object is not a POJO.
            throw new RuntimeException("The injected object in " + m_name + " is not a POJO");
        }

        load(); // Load the class.

        if (!m_clazz.isInstance(obj)) {
            throw new RuntimeException("The injected object in " + m_name + " is not an instance of " + m_className);
        }

        // Call _setInstanceManager
        try {
            Method setIM = m_clazz.getDeclaredMethod("_setInstanceManager", new Class[]{this.getClass()});
            setIM.setAccessible(true); // Necessary as the method is private
            setIM.invoke(obj, new Object[]{this});
        } catch (Exception e) {
            // If anything wrong happened...
            throw new RuntimeException("Cannot attach the injected object with the container of " + m_name, e);
        }

        // Call createInstance on Handlers :
        for (int i = 0; i < m_handlers.length; i++) {
            // This methods must be call without the monitor lock.
            ((PrimitiveHandler) m_handlers[i].getHandler()).onCreation(obj);
        }


    }

    /**
     * Registers an handler.
     * This methods is called by handler wanting to monitor
     * fields and/or methods of the implementation class.
     *
     * @param handler the handler to register
     * @param fields  the field metadata list
     * @param methods the method metadata list
     * @deprecated use {@link InstanceManager#register(FieldMetadata, FieldInterceptor)}
     * and {@link InstanceManager#register(MethodMetadata, MethodInterceptor)} instead.
     */
    public void register(PrimitiveHandler handler, FieldMetadata[] fields, MethodMetadata[] methods) {
        for (int i = 0; fields != null && i < fields.length; i++) {
            register(fields[i], handler);
        }
        for (int i = 0; methods != null && i < methods.length; i++) {
            register(methods[i], handler);
        }

    }

    /**
     * Registers a field interceptor.
     * A field interceptor will be notified of field access of the
     * implementation class. Note that handlers are field interceptors.
     *
     * @param field       the field to monitor
     * @param interceptor the field interceptor object
     */
    public void register(FieldMetadata field, FieldInterceptor interceptor) {
        if (m_fieldRegistration == null) {
            m_fieldRegistration = new HashMap();
            m_fieldRegistration.put(field.getFieldName(), new FieldInterceptor[]{interceptor});
        } else {
            FieldInterceptor[] list = (FieldInterceptor[]) m_fieldRegistration.get(field.getFieldName());
            if (list == null) {
                m_fieldRegistration.put(field.getFieldName(), new FieldInterceptor[]{interceptor});
            } else {
                for (int j = 0; j < list.length; j++) {
                    if (list[j] == interceptor) {
                        return;
                    }
                }
                FieldInterceptor[] newList = new FieldInterceptor[list.length + 1];
                System.arraycopy(list, 0, newList, 0, list.length);
                newList[list.length] = interceptor;
                m_fieldRegistration.put(field.getFieldName(), newList);
            }
        }
    }

    /**
     * Registers a method interceptor.
     * A method interceptor will be notified of method entries, exits
     * and errors. Note that handlers are method interceptors.
     *
     * @param method      the field to monitor
     * @param interceptor the field interceptor object
     */
    public void register(MethodMetadata method, MethodInterceptor interceptor) {
        if (m_methodRegistration == null) {
            m_methodRegistration = new HashMap();
            m_methodRegistration.put(method.getMethodIdentifier(), new MethodInterceptor[]{interceptor});
        } else {
            MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(method.getMethodIdentifier());
            if (list == null) {
                m_methodRegistration.put(method.getMethodIdentifier(), new MethodInterceptor[]{interceptor});
            } else {
                for (int j = 0; j < list.length; j++) {
                    if (list[j] == interceptor) {
                        return;
                    }
                }
                MethodInterceptor[] newList = new MethodInterceptor[list.length + 1];
                System.arraycopy(list, 0, newList, 0, list.length);
                newList[list.length] = interceptor;
                m_methodRegistration.put(method.getMethodIdentifier(), newList);
            }
        }
    }

    /**
     * Registers a method interceptor on a methods from an inner class.
     * A method interceptor will be notified of method entries, exits
     * and errors. Note that handlers are method interceptors.
     *
     * @param method      the field to monitor
     * @param innerClass  the inner class name
     * @param interceptor the field interceptor object
     */
    public void register(MethodMetadata method, String innerClass, MethodInterceptor interceptor) {
        if (m_methodRegistration == null) {
            m_methodRegistration = new HashMap();
            m_methodRegistration.put(innerClass + "___" + method.getMethodIdentifier(),
                    new MethodInterceptor[]{interceptor});
        } else {
            MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(method.getMethodIdentifier());
            if (list == null) {
                m_methodRegistration.put(innerClass + "___" + method.getMethodIdentifier(),
                        new MethodInterceptor[]{interceptor});
            } else {
                for (int j = 0; j < list.length; j++) {
                    if (list[j] == interceptor) {
                        return;
                    }
                }
                MethodInterceptor[] newList = new MethodInterceptor[list.length + 1];
                System.arraycopy(list, 0, newList, 0, list.length);
                newList[list.length] = interceptor;
                m_methodRegistration.put(innerClass + "___" + method.getMethodIdentifier(), newList);
            }
        }
    }

    /**
     * Registers a constructor injector.
     * The constructor injector will be called when a pojo object is going to be
     * created.
     *
     * @param index    the index of the parameter. Only one injector per index can
     *                 be registered.
     * @param injector the injector object.
     * @throws ConfigurationException if the given index is already injected by another
     *                                injector
     */
    public void register(int index, ConstructorInjector injector) throws ConfigurationException {
        if (m_constructorRegistration == null) {
            m_constructorRegistration = new HashMap();
        }
        if (!m_constructorRegistration.containsKey(index)) {
            m_constructorRegistration.put(index, injector);
        } else {
            throw new ConfigurationException("Another constructor injector " +
                    "manages the parameter " + index + " : " + m_constructorRegistration.get(index) + ", so cannot " +
                    "register " + injector);
        }
    }

    /**
     * This method is called by the manipulated class each time that a GETFIELD instruction is executed.
     * The method asks to each attached handler monitoring this field which value need
     * to be injected (i.e. returned) by invoking the {@link PrimitiveHandler#onGet(Object, String, Object)}
     * method. If the field value changes, this method call the {@link PrimitiveHandler#onSet(Object, String, Object)}
     * method on each field interceptor monitoring the field in order to advertize the new value.
     *
     * @param pojo      the pojo object on which the field was get
     * @param fieldName the field name on which the GETFIELD instruction is called
     * @return the value decided by the last asked handler (throws a warning if two fields decide two different values)
     */
    public Object onGet(Object pojo, String fieldName) {
        Object initialValue = null;
        synchronized (this) { // Stack confinement.
            initialValue = m_fields.get(fieldName);
        }
        Object result = initialValue;
        boolean hasChanged = false;
        // Get the list of registered handlers
        FieldInterceptor[] list = (FieldInterceptor[]) m_fieldRegistration.get(fieldName); // Immutable list.
        for (int i = 0; list != null && i < list.length; i++) {
            // Call onGet outside of a synchronized block.
            Object handlerResult = list[i].onGet(pojo, fieldName, initialValue);
            if (handlerResult == initialValue) {
                continue; // Non-binding case (default implementation).
            } else {
                if (result != initialValue) {
                    //TODO analyze impact of removing conflict detection
                    if ((handlerResult != null && !handlerResult.equals(result)) || (result != null && handlerResult == null)) {
                        m_logger.log(
                                Logger.WARNING,
                                "A conflict was detected on the injection of "
                                        + fieldName
                        );
                    }
                }
                result = handlerResult;
                hasChanged = true;
            }
        }
        if (hasChanged) {
            // A change occurs => notify the change
            //TODO consider just changing the reference, however multiple thread can be an issue
            synchronized (this) {
                m_fields.put(fieldName, result);
            }
            // Call onset outside of a synchronized block.
            for (int i = 0; list != null && i < list.length; i++) {
                list[i].onSet(pojo, fieldName, result);
            }
        }
        return result;
    }

    /**
     * Dispatches entry method events on registered method interceptors.
     * This method calls the {@link MethodInterceptor#onEntry(Object, java.lang.reflect.Member, Object[])}
     * methods on method interceptors monitoring the method.
     *
     * @param pojo     the pojo object on which method is invoked.
     * @param methodId the method id used to compute the {@link Method} object.
     * @param args     the argument array
     */
    public void onEntry(Object pojo, String methodId, Object[] args) {
        if (m_methodRegistration == null) { // Immutable field.
            return;
        }

        MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(methodId);
        Member method = getMethodById(methodId);
        // We can't find the member object of anonymous methods.

        // In case of a constructor, the method is null, and the list is null too.
        for (int i = 0; list != null && i < list.length; i++) {
            list[i].onEntry(pojo, method, args); // Outside a synchronized block.
        }
    }

    /**
     * Dispatches exit method events on registered method interceptors.
     * The given returned object is an instance of {@link Exception} if the method thrown an
     * exception. If the given object is <code>null</code>, either the method returns <code>void</code>,
     * or the method has returned <code>null</code>
     * This method calls the {@link MethodInterceptor#onExit(Object, java.lang.reflect.Member, Object)} and the
     * {@link MethodInterceptor#onFinally(Object, java.lang.reflect.Member)} methods on method interceptors
     * monitoring the method.
     *
     * @param pojo     the pojo object on which method was invoked.
     * @param methodId the method id used to compute the {@link Method} object.
     * @param result   the returned object.
     */
    public void onExit(Object pojo, String methodId, Object result) {
        if (m_methodRegistration == null) {
            return;
        }
        MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(methodId);
        Member method = getMethodById(methodId);
        for (int i = 0; list != null && i < list.length; i++) {
            list[i].onExit(pojo, method, result);
        }
        for (int i = 0; list != null && i < list.length; i++) {
            list[i].onFinally(pojo, method);
        }
    }

    /**
     * Dispatches error method events on registered method interceptors.
     * or the method has returned <code>null</code>
     * This method calls the {@link MethodInterceptor#onError(Object, java.lang.reflect.Member, Throwable)} and the
     * {@link MethodInterceptor#onFinally(Object, java.lang.reflect.Member)} methods on method interceptors monitoring
     * the method.
     *
     * @param pojo     the pojo object on which the method was invoked
     * @param methodId the method id used to compute the {@link Method} object.
     * @param error    the Throwable object.
     */
    public void onError(Object pojo, String methodId, Throwable error) {
        if (m_methodRegistration == null) {
            return;
        }
        MethodInterceptor[] list = (MethodInterceptor[]) m_methodRegistration.get(methodId);
        Member method = getMethodById(methodId);
        for (int i = 0; list != null && i < list.length; i++) {
            list[i].onError(pojo, method, error);
        }
        for (int i = 0; list != null && i < list.length; i++) {
            list[i].onFinally(pojo, method);
        }
    }

    /**
     * Computes the {@link Method} object from the given id.
     * Once computes, a map is used as a cache to avoid to recompute for
     * the same id.
     *
     * @param methodId the method id
     * @return the method object or <code>null</code> if the method cannot be found.
     */
    private Member getMethodById(String methodId) {
        // Used a synchronized map.
        Member member = (Member) m_methods.get(methodId);
        if (!m_methods.containsKey(methodId) && m_clazz != null) {
            // Is it a inner class method
            if (methodId.contains("___")) { // Mark to detect a inner class method.
                String[] split = methodId.split("___");
                if (split.length != 2) {
                    m_logger.log(Logger.INFO, "A methodID cannot be associated with a method from the POJO class: " + methodId);
                    return null;
                } else {
                    String innerClassName = split[0];
                    methodId = split[1];

                    // We can't find the member objects from anonymous methods, identified by their numeric name
                    // Just escaping in this case.
                    if (innerClassName.matches("-?\\d+")) {
                        m_methods.put(methodId, null);
                        return null;
                    }

                    for (Class c : InstanceManager.getDeclaredClasses(m_clazz)) {
                        if (innerClassName.equals(c.getSimpleName())) {
                            Method[] mets = getDeclaredMethods(c);
                            for (Method met : mets) {
                                if (MethodMetadata.computeMethodId(met).equals(methodId)) {
                                    // Store the new methodId
                                    m_methods.put(methodId, met);
                                    return met;
                                }
                            }
                        }
                        m_logger.log(Logger.INFO, "Cannot find the member associated to " + methodId + " - reason: " +
                                "cannot find the class " + innerClassName + " declared in " + m_clazz.getName());
                    }
                }
            }


            // First try on methods.
            Method[] mets = getDeclaredMethods(m_clazz);
            for (int i = 0; i < mets.length; i++) {
                if (MethodMetadata.computeMethodId(mets[i]).equals(methodId)) {
                    // Store the new methodId
                    m_methods.put(methodId, mets[i]);
                    return mets[i];
                }
            }

            // If not found, it is a constructor, return the constructor object in this case.
            if (methodId.startsWith(MethodMetadata.CONSTRUCTOR_PREFIX)) {
                Constructor[] constructors = getDeclaredConstructors(m_clazz);
                for (int i = 0; i < constructors.length; i++) {
                    // Check if the constructor was not already computed. If not, compute the Id and check.
                    if (MethodMetadata.computeMethodId(constructors[i]).equals(methodId)) {
                        // Store the new methodId
                        m_methods.put(methodId, constructors[i]);
                        return constructors[i];
                    }
                }
            }

            // Should not happen
            m_logger.log(Logger.INFO, "A methodID cannot be associated with a method from the POJO class: " + methodId);
            return null;
        } else {
            return member;
        }
    }

   
    /**
     * Perform privileged access introspection to get declared inner classes
     */
    private static Class<?>[] getDeclaredClasses(final Class<?> clazz) {
      return AccessController.doPrivileged(new PrivilegedAction<Class<?>[]>() {

      public Class<?>[] run() {
        return clazz.getDeclaredClasses();
      }
    });
    }
   
    /**
     * Perform privileged access introspection to get declared methods
     */
    private static Method[] getDeclaredMethods(final Class<?> clazz) {
      return AccessController.doPrivileged(new PrivilegedAction<Method[]>() {

      public Method[] run() {
        return clazz.getDeclaredMethods();
      }
    });
    }

    /**
     * Perform privileged access introspection to get declared constructors
     */
    private static Constructor<?>[] getDeclaredConstructors(final Class<?> clazz) {
      return AccessController.doPrivileged(new PrivilegedAction<Constructor<?>[]>() {

      public Constructor<?>[] run() {
        return clazz.getDeclaredConstructors();
      }
    });
    }

    /**
     * This method is called by the manipulated class each time that a PUTFIELD instruction is executed.
     * The method calls the {@link PrimitiveHandler#onSet(Object, String, Object)} method on each field
     * interceptors monitoring this field.
     * This method can be invoked with a <code>null</code> pojo argument when the changes comes from another
     * handler.
     *
     * @param pojo        the pojo object on which the field was set
     * @param fieldName   the field name on which the PUTFIELD instruction is called
     * @param objectValue the new value of the field
     */
    public void onSet(final Object pojo, final String fieldName, final Object objectValue) {
        synchronized (this) {
            // First, store the new value.
            // This must be done in a synchronized block to avoid
            // concurrent modification
            m_fields.put(fieldName, objectValue);
        }
        // The registrations cannot be modified, so we can directly access
        // the interceptor list.
        FieldInterceptor[] list = (FieldInterceptor[]) m_fieldRegistration
                .get(fieldName);
        for (int i = 0; list != null && i < list.length; i++) {
            // The callback must be call outside the synchronization block.
            list[i].onSet(pojo, fieldName, objectValue);
        }
    }


    /**
     * Gets the bundle context used by this component instance.
     *
     * @return the context of the component.
     * @see org.apache.felix.ipojo.ComponentInstance#getContext()
     */
    public BundleContext getContext() {
        return m_context; // Immutable
    }

    /**
     * Gets the global bundle context. This is the bundle context
     * of the bundle declaring the component type.
     *
     * @return the bundle context of the bundle declaring the component
     * type.
     */
    public BundleContext getGlobalContext() {
        return ((IPojoContext) m_context).getGlobalContext(); // Immutable
    }


    /**
     * Gets the local service context. This service context gives
     * access to the 'local' service registry (the composite one).
     * If the instance lives in the global (i.e. OSGi) context,
     * this method returns <code>null</code>
     *
     * @return the local service context or <code>null</code> if the
     * instance doesn't live in a composite.
     */
    public ServiceContext getLocalServiceContext() {
        return ((IPojoContext) m_context).getServiceContext(); // Immutable
    }

    /**
     * Gets the instance name.
     *
     * @return the instance name.
     * @see org.apache.felix.ipojo.ComponentInstance#getInstanceName()
     */
    public String getInstanceName() {
        return m_name; // Immutable
    }

    /**
     * Reconfigures the current instance.
     * Reconfiguring an instance means re-injecting a new
     * instance configuration. Some properties are immutable
     * such as the instance name.
     * This methods calls the {@link PrimitiveHandler#reconfigure(Dictionary)}
     * methods on each attached handler, and then recompute the instance
     * state. Note that the reconfiguration process does not deactivate the
     * instance.
     *
     * @param configuration the new configuration to push
     * @see org.apache.felix.ipojo.ComponentInstance#reconfigure(java.util.Dictionary)
     */
    public void reconfigure(Dictionary configuration) {
        m_logger.log(Logger.INFO, "Reconfiguring " + getInstanceName());
        for (int i = 0; i < m_handlers.length; i++) {
            m_handlers[i].getHandler().reconfigure(configuration);
        }
        // We synchronized the state computation.
        synchronized (this) {
            if (m_state == STOPPED) {
                m_logger.log(Logger.INFO, "Instance stopped during reconfiguration - Try to restart");
                start();
            } else if (m_state == INVALID) {
                m_logger.log(Logger.INFO, "Instance invalid during reconfiguration - Recompute state");
                // Try to revalidate the instance after reconfiguration
                for (int i = 0; i < m_handlers.length; i++) {
                    if (m_handlers[i].getState() != VALID) {
                        return;
                    }
                }
                setState(VALID);
            }
        }
    }

    /**
     * Gets the implementation class of the component type.
     * This method does not need to be synchronized as the
     * class name is constant once set.
     *
     * @return the class name of the component implementation.
     */
    public String getClassName() {
        return m_className;
    }

    /**
     * State Change listener callback.
     * This method is called every time that a plugged handler becomes valid or invalid.
     * This method computes the new instance state and applies it (by calling the
     * {@link InstanceManager#setState(int)} method.
     *
     * @param instance the handler becoming valid or invalid
     * @param newState the new state of the handler
     * @see org.apache.felix.ipojo.InstanceStateListener#stateChanged(org.apache.felix.ipojo.ComponentInstance, int)
     */
    public void stateChanged(ComponentInstance instance, int newState) {
        int state;
        synchronized (this) {
            if (m_state <= STOPPED) {
                return;
            } else {
                state = m_state; // Stack confinement
            }
        }

        // Update the component state if necessary
        if (newState == INVALID && state == VALID) {
            // Need to update the state to UNRESOLVED
            setState(INVALID);
            return;
        }
        if (newState == VALID && state == INVALID) {
            // An handler becomes valid => check if all handlers are valid
            for (int i = 0; i < m_handlers.length; i++) {
                if (m_handlers[i].getState() != VALID) {
                    return;
                }
            }
            setState(VALID);
            return;
        }
    }

    /**
     * Gets the list of registered fields (containing field names).
     * This method is invoked by the POJO itself during
     * its initialization.
     *
     * @return the set of registered fields.
     */
    public Set getRegistredFields() {
        if (m_fieldRegistration == null) {
            return null;
        }
        return m_fieldRegistration.keySet();
    }

    /**
     * Gets the list of registered methods (containing method ids).
     * This method is invoked by the POJO itself during its
     * initialization.
     *
     * @return the set of registered methods.
     */
    public Set getRegistredMethods() {
        if (m_methodRegistration == null) {
            return null;
        } else {
            return m_methodRegistration.keySet();
        }
    }

    /**
     * Gets the bundle context of the instance, i.e. the bundle context of the bundle having declared this instance.
     *
     * @return the bundle context of the instance.
     * @since 1.11.2
     */
    public BundleContext getInstanceContext() {
        return m_instanceContext;
    }
}
TOP

Related Classes of org.apache.felix.ipojo.InstanceManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.