All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.objectweb.petals.component.framework.AbstractComponent Maven / Gradle / Ivy

Go to download

The PEtALS component framework. This framework is used to easily create JBI 1.0 compliant components.

The newest version!
/**
 * PETALS - PETALS Services Platform.
 * Copyright (c) 2007 EBM Websourcing, http://www.ebmwebsourcing.com/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * -------------------------------------------------------------------------
 * $Id$
 * -------------------------------------------------------------------------
 */

package org.objectweb.petals.component.framework;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jbi.JBIException;
import javax.jbi.component.Component;
import javax.jbi.component.ComponentContext;
import javax.jbi.component.ComponentLifeCycle;
import javax.jbi.messaging.DeliveryChannel;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.servicedesc.ServiceEndpoint;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;

import org.objectweb.petals.component.framework.interceptor.Interceptor;
import org.objectweb.petals.component.framework.interceptor.description.InterceptorBuilder;
import org.objectweb.petals.component.framework.interceptor.description.InterceptorConfiguration;
import org.objectweb.petals.component.framework.listener.JBIListenerManager;
import org.objectweb.petals.component.framework.mbean.PerformanceNotification;
import org.objectweb.petals.component.framework.mbean.PerformanceNotifierMBean;
import org.objectweb.petals.component.framework.su.ServiceUnitExtensionsValidator;
import org.objectweb.petals.component.framework.su.ServiceUnitListener;
import org.objectweb.petals.component.framework.su.ServiceUnitManager;
import org.objectweb.petals.component.framework.util.Exchange;
import org.objectweb.petals.component.framework.util.StringHelper;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;

/**
 * An abstract class that can be used to easily create a new JBI Component. It
 * implements Component, ComponentLifeCycle and MessageExchangeProcessor JBI
 * interfaces.
 *
 * @author ofabre
 *
 */
public abstract class AbstractComponent implements Component,
        ComponentLifeCycle {

    /**
     * InOnly Mep shortcut
     */
    public static final String IN_ONLY = "in-only";

    /**
     * InOnly Mep shortcut
     */
    public static final String ROBUST_IN_ONLY = "robust-in-only";

    /**
     * InOnly Mep shortcut
     */
    public static final String IN_OUT = "in-out";

    /**
     * InOnly Mep shortcut
     */
    public static final String IN_OPTIONAL_OUT = "in-optional-out";

    /**
     * The component's delivery channel
     */
    private DeliveryChannel channel;

    /**
     * The Component's Context
     */
    private ComponentContext context;

    /**
     * The component configuration
     */
    private ComponentConfiguration componentConfiguration;

    /**
     * The message exchange listener
     */
    private JBIListenerManager listenerManager;

    /**
     * The component's logger
     */
    private Logger log; // NOPMD by ofabre

    /**
     * The ServiceUnit lifecycle listener
     */
    private ServiceUnitListener serviceUnitListener;

    /**
     * The service unit extensions validator
     */
    private ServiceUnitExtensionsValidator serviceUnitExtensionsValidator;

    /**
     * The component's service unit manager
     */
    private ServiceUnitManager suManager;

    /**
     * All the component interceptors. Key is the name of the interceptor. All
     * the
     */
    protected Map interceptors;

    /**
     * JMX Performance notifier MBean
     */
    private PerformanceNotifierMBean jmxPerformanceNotifierMBean = null;

    /**
     * Creates a new {@link JBIListenerManager}
     *
     * @param configuration
     *            Configuration of the component
     * @return the created {@link JBIListenerManager}
     */
    private JBIListenerManager createJBIListenerManager(
            final ComponentConfiguration configuration) {
        return new JBIListenerManager(this, configuration, this.log,
                this.suManager);
    }

    /**
     * Can be overidden to provide a specific service unit manager
     *
     * @return the service unit manager used by this component.
     */
    protected ServiceUnitManager createServiceUnitManager() {
        return new ServiceUnitManager(this);
    }

    /**
     * Creates the component configuration from the component manager. The
     * component configuration contains all PCF properties as attributes.
     *
     * @return the component configuration.
     */
    protected ComponentConfiguration createComponentConfiguration()
            throws PEtALSCDKException {
        final ComponentConfiguration conf = new ComponentConfiguration();

        // get the component properties manager to load extension values
        final ComponentPropertiesManager extensionProperties =
            new ComponentPropertiesManager();
        extensionProperties.setRootPath(this.getContext().getInstallRoot());

        if (!extensionProperties.load()) {
            throw new PEtALSCDKException(
                    "Failed to load extensions section in the component descriptor file");
        }

        final Properties properties = extensionProperties.getProperties();

        // create configuration from required values
        int poolSize = 0;
        try {
            if ((extensionProperties.getProperty(
                    ComponentPropertiesManager.POOL_SIZE) == null)||
                    (extensionProperties.getProperty(
                    ComponentPropertiesManager.POOL_SIZE).trim().equals(""))) {
                extensionProperties.getProperties().setProperty(
                        ComponentPropertiesManager.POOL_SIZE,
                        ComponentPropertiesManager.DEFAULT_POOL_SIZE);
            }

            poolSize = Integer.parseInt(extensionProperties.getProperty(
                    ComponentPropertiesManager.POOL_SIZE,
                    ComponentPropertiesManager.DEFAULT_POOL_SIZE));
        } catch (final NumberFormatException e) {
            throw new PEtALSCDKException("The PCF parameter '"
                    + ComponentPropertiesManager.POOL_SIZE
                    + "' is invalid in the component descriptor file");
        }
        if (poolSize <= 0) {
            throw new PEtALSCDKException("The PCF parameter '"
                    + ComponentPropertiesManager.POOL_SIZE
                    + "' is invalid in the component descriptor file");
        }
        conf.setPoolSize(poolSize);
        properties.setProperty(ComponentPropertiesManager.POOL_SIZE, Integer
                .toString(conf.getPoolSize()));

        IgnoredStatusConstants ignoreStatus;
        try {
            if ((extensionProperties.getProperty(
                    ComponentPropertiesManager.IGNORED_STATUS) == null)||(extensionProperties.getProperty(
                    ComponentPropertiesManager.IGNORED_STATUS).trim()
                    .equals(""))) {
                extensionProperties.getProperties().setProperty(
                        ComponentPropertiesManager.IGNORED_STATUS,
                        ComponentPropertiesManager.DEFAULT_IGNORED_STATUS);
            }

            ignoreStatus = IgnoredStatusConstants.valueOf(extensionProperties
                    .getProperty(ComponentPropertiesManager.IGNORED_STATUS,
                            ComponentPropertiesManager.DEFAULT_IGNORED_STATUS));
        } catch (final IllegalArgumentException e) {
            throw new PEtALSCDKException("The PCF parameter '"
                    + ComponentPropertiesManager.IGNORED_STATUS
                    + "' is invalid in the component descriptor file");
        }
        conf.setIgnoredStatus(ignoreStatus);
        properties.setProperty(ComponentPropertiesManager.IGNORED_STATUS, conf
                .getIgnoredStatus().value());

        final String jbiListenerClassName = extensionProperties
                .getProperty(ComponentPropertiesManager.JBI_LISTENER_CLASSNAME);
        if (StringHelper.isNullOrEmpty(jbiListenerClassName)) {
            throw new PEtALSCDKException("The PCF parameter '"
                    + ComponentPropertiesManager.JBI_LISTENER_CLASSNAME
                    + "' is invalid or absent in the component descriptor file");
        }
        conf.setJbiListenerClassName(jbiListenerClassName);
        conf.setExternalListenerClassName(extensionProperties
                        .getProperty(ComponentPropertiesManager.
                                EXTERNAL_LISTENER_CLASSNAME));
        this.log.info("Component configuration -> Thread pool size : "
                + conf.getPoolSize() + ", Ignored message exchange status : "
                + conf.getIgnoredStatus().value());

        // put the updated properties
        conf.setProperties(properties);

        return conf;
    }

    /**
     * Returns the component delivery channel, used to send messages to petals
     * container
     *
     * @return the delivery channel. Not null.
     */
    public DeliveryChannel getChannel() {
        return this.channel;
    }

    /**
     * The component context
     *
     * @return the component context. Not null.
     */
    public ComponentContext getContext() {
        return this.context;
    }

    /**
     * Returns null by default as this class does not provides JMX extension
     * MBean
     *
     * @see javax.jbi.component.ComponentLifeCycle#getExtensionMBeanName()
     */
    public ObjectName getExtensionMBeanName() {
        return null;
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.Component#getLifeCycle()
     */
    public ComponentLifeCycle getLifeCycle() {
        return this;
    }

    /**
     * Returns the component logger
     *
     * @return component logger. Not null.
     */
    public Logger getLogger() {
        return this.log;
    }

    /**
     * Can be overidden to return a custom resource bundle name
     *
     * @return the resource bundle name or null if no resource bundle name has
     *         to be used (default value)
     */
    protected String getResourceBundleName() {
        return null;
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.Component#getServiceDescription(javax.jbi.servicedesc.ServiceEndpoint)
     */
    public Document getServiceDescription(final ServiceEndpoint endpoint) {
        return this.suManager.getServiceDescription(endpoint);
    }

    public ServiceUnitListener getServiceUnitListener() {
        return this.serviceUnitListener;
    }

    public ServiceUnitExtensionsValidator getServiceUnitExtensionsValidator() {
        return this.serviceUnitExtensionsValidator;
    }

    /**
     * Get all the interceptors
     *
     * @return
     */
    public Map getInterceptors() {
        return this.interceptors;
    }

    /**
     * Get the interceptor that have the given name.
     *
     * @param name
     * @return null if the interceptor is not found of is there are no
     *         interceptor in the component
     */
    public Interceptor getInterceptor(final String name) {
        Interceptor interceptor = null;

        if (this.interceptors != null) {
            interceptor = this.interceptors.get(name);
        }
        return interceptor;
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.Component#getServiceUnitManager()
     */
    public javax.jbi.component.ServiceUnitManager getServiceUnitManager() {
        if (this.suManager == null) {
            this.suManager = this.createServiceUnitManager();
        }
        return this.suManager;
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.ComponentLifeCycle#init(javax.jbi.component.ComponentContext)
     */
    public final void init(final ComponentContext compContext)
            throws JBIException {
        this.context = compContext;
        this.log = this.context.getLogger("", this.getResourceBundleName());
        this.log.fine("Component initialization in progress...");

        this.channel = this.context.getDeliveryChannel();
        this.componentConfiguration = this.createComponentConfiguration();
        this.interceptors = this.loadInterceptors();
        this.suManager = this.createServiceUnitManager();

        this.log.fine("Calling specific initialization...");
        this.doInit();
        this.log.fine("Specific initialization done.");
        this.log.log(Level.INFO, "Component initialized");
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.Component#isExchangeWithConsumerOkay(javax.jbi.servicedesc.ServiceEndpoint,
     *      javax.jbi.messaging.MessageExchange)
     */
    public boolean isExchangeWithConsumerOkay(final ServiceEndpoint endpoint,
            final MessageExchange exchange) {
        return true;
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.Component#isExchangeWithProviderOkay(javax.jbi.servicedesc.ServiceEndpoint,
     *      javax.jbi.messaging.MessageExchange)
     */
    public boolean isExchangeWithProviderOkay(final ServiceEndpoint endpoint,
            final MessageExchange exchange) {
        return true;
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.Component#resolveEndpointReference(org.w3c.dom.DocumentFragment)
     */
    public ServiceEndpoint resolveEndpointReference(final DocumentFragment epr) {
        return null;
    }

    public void setServiceUnitListener(
            final ServiceUnitListener serviceUnitListener) {
        this.serviceUnitListener = serviceUnitListener;
    }

    public void setServiceUnitExtensionsValidator(
            final ServiceUnitExtensionsValidator serviceUnitExtensionsValidator) {
        this.serviceUnitExtensionsValidator = serviceUnitExtensionsValidator;
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.ComponentLifeCycle#shutDown()
     */
    public final void shutDown() throws JBIException {
        this.log.log(Level.INFO, "shutdown");
        this.doShutdown();
        this.listenerManager = null; // NOPMD frees the memory while
        // component is
        // shutdown
        this.context = null; // NOPMD idem
        this.log = null; // NOPMD idem
        this.channel = null; // NOPMD idem
        this.suManager = null; // NOPMD idem
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.ComponentLifeCycle#start()
     */
    public final void start() throws JBIException {
        this.log.log(Level.INFO, "start");
        this.registerPerformanceNotifierMBean();
        this.listenerManager = this
                .createJBIListenerManager(this.componentConfiguration);
        this.listenerManager.startListening();

        this.log.fine("Calling specific start...");
        this.doStart();
        this.log.fine("Specific start done.");
    }

    /*
     * (non-Javadoc)
     *
     * @see javax.jbi.component.ComponentLifeCycle#stop()
     */
    public final void stop() throws JBIException {
        this.log.log(Level.INFO, "stop");
        // FIXME : call terminate or close?
        this.unregisterPerformanceNotifierMBean();
        this.listenerManager.stopListening();

        this.log.fine("Calling specific stop...");
        this.doStop();
        this.log.fine("Specific stop done.");
    }

    /**
     * A convenience method which can be overridden so that there's no need to
     * call super.doInit(). This method is called at the end of the component
     * classical initialization. When this method is called, the component's
     * delivery channel, context, logger and service unit manager are available.
     *
     */
    protected void doInit() throws JBIException {
    }

    /**
     * A convenience method which can be overridden so that there's no need to
     * call super.doStart(). This method is called at the end of the component
     * classical start.
     *
     */
    protected void doStart() throws JBIException {
    }

    /**
     * A convenience method which can be overridden so that there's no need to
     * call super.doStop(). This method is called at the end of the component
     * classical stop.
     *
     */
    protected void doStop() throws JBIException {
    }

    /**
     * A convenience method which can be overridden so that there's no need to
     * call super.doShutdown(). This method is called at the end of the
     * component classical shutdown.
     *
     */
    protected void doShutdown() throws JBIException {
    }

    public ComponentConfiguration getComponentConfiguration() {
        return this.componentConfiguration;
    }

    /**
     * Load the interceptors
     *
     * @param configuration
     */
    protected final Map loadInterceptors() {
        Map interceptors = null;
        final InterceptorBuilder builder = InterceptorBuilder.getInstance();
        try {
            final List list = builder
                    .loadComponentInterceptors(this.getContext()
                            .getInstallRoot());
            interceptors = this.instanciateInterceptors(list);
        } catch (final PEtALSCDKException e) {
            e.printStackTrace();
        }
        return interceptors;
    }

    /**
     * Load the accept interceptors
     *
     * @return
     */
    protected final Map instanciateInterceptors(
            final List interceptors) {
        final Map loaded = new HashMap();

        if (interceptors != null) {
            final InterceptorBuilder builder = InterceptorBuilder.getInstance();
            for (final InterceptorConfiguration interceptorConfig : interceptors) {
                try {
                    this.getLogger().info(
                            "Loading interceptor : "
                                    + interceptorConfig.getName());
                    final Interceptor itc = builder
                            .loadInstance(interceptorConfig.getClazz());
                    itc.init(this, interceptorConfig.getName(),
                            interceptorConfig.isActive(), interceptorConfig
                                    .getParameters(), this.getLogger());
                    loaded.put(itc.getName(), itc);
                } catch (final PEtALSCDKException e) {
                    this.getLogger().log(
                            Level.WARNING,
                            "Could not load or initialize interceptor '"
                                    + interceptorConfig.getName()
                                    + "' from class '"
                                    + interceptorConfig.getClazz()
                                    + "', this interceptor is skipped");
                }
            }
        }
        return loaded;
    }

    /**
     *
     * @return
     */
    public JBIListenerManager getListenerManager() {
        return this.listenerManager;
    }

    /**
     * Register the performance notifier in the JMX server
     *
     * @throws JBIException
     */
    private void registerPerformanceNotifierMBean() throws JBIException {
        try {
            final ObjectName jmxPerformanceNotifierName = this.context
                    .getMBeanNames().createCustomComponentMBeanName(
                            "performance_notifier_"
                                    + this.context.getComponentName());

            this.jmxPerformanceNotifierMBean = new PerformanceNotifierMBean(
                    this.componentConfiguration, jmxPerformanceNotifierName);

            final MBeanServer server = this.context.getMBeanServer();

            if (server == null) {
                throw new JBIException("MBean server is null !");
            }

            if (server.isRegistered(jmxPerformanceNotifierName)) {
                server.unregisterMBean(jmxPerformanceNotifierName);
            }

            server.registerMBean(this.jmxPerformanceNotifierMBean,
                    jmxPerformanceNotifierName);

        } catch (final InstanceNotFoundException e) {
            throw new JBIException(e);
        } catch (final MBeanRegistrationException e) {
            throw new JBIException(e);
        } catch (final InstanceAlreadyExistsException e) {
            throw new JBIException(e);
        } catch (final NotCompliantMBeanException e) {
            throw new JBIException(e);
        }
    }

    /**
     * Unregister the performance notifier
     *
     * @throws JBIException
     */
    private void unregisterPerformanceNotifierMBean() throws JBIException {
        try {
            final MBeanServer server = this.context.getMBeanServer();
            server.unregisterMBean(this.jmxPerformanceNotifierMBean
                    .getJmxPerformanceNotifierName());
        } catch (final InstanceNotFoundException e) {
            throw new JBIException(e);
        } catch (final MBeanRegistrationException e) {
            throw new JBIException(e);
        }
    }

    /**
     * Get the performance notifier
     *
     * @return
     */
    public PerformanceNotifierMBean getJmxPerformanceNotifierMBean() {
        return this.jmxPerformanceNotifierMBean;
    }

    /**
     * Create a performance notification which the type RECEIVING_FROM_OUTSIDE
     *
     * @return The performance notification to send.
     */
    public PerformanceNotification createPerformanceNotificationReceivingFromOutside(
            final String userData, final Exchange msgExchange) {
        return this.createPerformanceNotification(
                PerformanceNotification.RECEIVING_FROM_OUTSIDE, userData,
                msgExchange);
    }

    /**
     * Create a performance notification which the type SENDING_TO_OUTSIDE
     *
     * @return The performance notification to send.
     */
    public PerformanceNotification createPerformanceNotificationSendingToOutside(
            final String userData, final Exchange msgExchange) {
        return this.createPerformanceNotification(
                PerformanceNotification.SENDING_TO_OUTSIDE, userData,
                msgExchange);
    }

    /**
     * Create a performance notification which the type RECEIVING_FROM_NMR
     *
     * @return The performance notification to send.
     */
    public PerformanceNotification createPerformanceNotificationReceivingFromNMR(
            final String userData, final Exchange msgExchange) {
        return this.createPerformanceNotification(
                PerformanceNotification.RECEIVING_FROM_NMR, userData,
                msgExchange);
    }

    /**
     * Create a performance notification which the type SENDING_TO_NMR
     *
     * @return The performance notification to send.
     */
    public PerformanceNotification createPerformanceNotificationSendingToNMR(
            final String userData, final Exchange msgExchange) {
        return this.createPerformanceNotification(
                PerformanceNotification.SENDING_TO_NMR, userData, msgExchange);
    }

    /**
     * Create a new notification
     *
     * @param type
     * @param userData
     * @param msgExchange
     * @return
     */
    private PerformanceNotification createPerformanceNotification(
            final String type, final String userData, final Exchange msgExchange) {
        PerformanceNotification performanceNotification = null;

        if (this.componentConfiguration.isPerformanceNotificationsEnabled()) {
            performanceNotification = this.jmxPerformanceNotifierMBean
                    .createPerformanceNotifications(System.currentTimeMillis(),
                            this.context.getComponentName(), type, userData,
                            msgExchange);
        }
        return performanceNotification;
    }

    /**
     * Send a performance notification using the performance notifier
     *
     * @param performanceNotification
     */
    public void sendPerformanceNotification(
            final PerformanceNotification performanceNotification) {
        if (this.componentConfiguration.isPerformanceNotificationsEnabled()) {
            this.jmxPerformanceNotifierMBean.send(performanceNotification);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy