/* * 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.handlers.lifecycle.callback; import java.lang.reflect.InvocationTargetException; import java.util.Dictionary; import org.apache.felix.ipojo.ComponentInstance; import org.apache.felix.ipojo.ConfigurationException; import org.apache.felix.ipojo.InstanceManager; import org.apache.felix.ipojo.PrimitiveHandler; import org.apache.felix.ipojo.metadata.Element; import org.apache.felix.ipojo.parser.MethodMetadata; import org.apache.felix.ipojo.parser.PojoMetadata; /** * Lifecycle callback handler. * * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class LifecycleCallbackHandler extends PrimitiveHandler { /** * The list of the callback of the component. */ private LifecycleCallback[] m_callbacks = new LifecycleCallback[0]; /** * State of the instance manager (unresolved at the beginning). */ private int m_state = InstanceManager.INVALID; /** * Does a POJO object be created at starting. */ private boolean m_immediate = false; /** * Add the given callback to the callback list. * * @param callback : the element to add */ private void addCallback(LifecycleCallback callback) { for (int i = 0; (m_callbacks != null) && (i < m_callbacks.length); i++) { if (m_callbacks[i] == callback) { return; } } if (m_callbacks != null && m_callbacks.length > 0) { //TODO check here if we can improve the test LifecycleCallback[] newHk = new LifecycleCallback[m_callbacks.length + 1]; System.arraycopy(m_callbacks, 0, newHk, 0, m_callbacks.length); newHk[m_callbacks.length] = callback; m_callbacks = newHk; } else { m_callbacks = new LifecycleCallback[] { callback }; } } /** * Configure the handler. * @param metadata : the component type metadata * @param configuration : the instance configuration * @throws ConfigurationException : one callback metadata is not correct (either the transition or the method are not correct). * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary) */ public void configure(Element metadata, Dictionary configuration) throws ConfigurationException { m_callbacks = new LifecycleCallback[0]; String imm = metadata.getAttribute("immediate"); m_immediate = imm != null && imm.equalsIgnoreCase("true"); PojoMetadata meta = getFactory().getPojoMetadata(); Element[] hooksMetadata = metadata.getElements("callback"); for (int i = 0; hooksMetadata != null && i < hooksMetadata.length; i++) { String method = hooksMetadata[i].getAttribute("method"); if (method == null) { throw new ConfigurationException("Lifecycle callback : A callback needs to contain a method attribute"); } MethodMetadata met = meta.getMethod(method, new String[0]); int transition = -1; String trans = hooksMetadata[i].getAttribute("transition"); if (trans == null) { throw new ConfigurationException("Lifecycle callback : the transition attribute is missing"); } else { if (trans.equalsIgnoreCase("validate")) { transition = LifecycleCallback.VALIDATE; } else if (trans.equalsIgnoreCase("invalidate")) { transition = LifecycleCallback.INVALIDATE; } else { throw new ConfigurationException("Lifecycle callback : Unknown or malformed transition : " + trans); } } LifecycleCallback callback = null; if (met == null) { callback = new LifecycleCallback(this, transition, method); } else { callback = new LifecycleCallback(this, transition, met); } addCallback(callback); } } /** * Start the handler. * @see org.apache.felix.ipojo.Handler#start() */ public void start() { // Do nothing during the start } /** * Stop the handler. * @see org.apache.felix.ipojo.Handler#stop() */ public void stop() { m_state = InstanceManager.INVALID; } /** * When the state change call the associated callback. * * @param state : the new instance state. * @see org.apache.felix.ipojo.Handler#stateChanged(int) */ public void stateChanged(int state) { int transition = -1; if (m_state == ComponentInstance.INVALID && state == ComponentInstance.VALID) { transition = LifecycleCallback.VALIDATE; } if (m_state == ComponentInstance.VALID && state == ComponentInstance.INVALID) { transition = LifecycleCallback.INVALIDATE; } // Manage immediate component if (m_immediate && transition == LifecycleCallback.VALIDATE && getInstanceManager().getPojoObjects() == null) { getInstanceManager().getPojoObject(); } for (int i = 0; i < m_callbacks.length; i++) { if (m_callbacks[i].getTransition() == transition) { try { m_callbacks[i].call(); } catch (NoSuchMethodException e) { error("[" + getInstanceManager().getInstanceName() + "] The callback method " + m_callbacks[i].getMethod() + " is not found"); throw new IllegalStateException(e); } catch (IllegalAccessException e) { error("[" + getInstanceManager().getInstanceName() + "] The callback method " + m_callbacks[i].getMethod() + " is not accessible"); throw new IllegalStateException(e); } catch (InvocationTargetException e) { error("[" + getInstanceManager().getInstanceName() + "] The callback method " + m_callbacks[i].getMethod() + " has thrown an exception : " + e.getTargetException().getMessage(), e.getTargetException()); throw new IllegalStateException(e.getTargetException()); } } } // Update to internal state m_state = state; } }