org.mule.config.bootstrap.SimpleRegistryBootstrap.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.config.bootstrap.SimpleRegistryBootstrap.java

Source

/*
 * $Id$
 * --------------------------------------------------------------------------------------
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.config.bootstrap;

import org.mule.api.MuleContext;
import org.mule.api.MuleException;
import org.mule.api.context.MuleContextAware;
import org.mule.api.lifecycle.Initialisable;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.registry.MuleRegistry;
import org.mule.api.registry.ObjectProcessor;
import org.mule.api.registry.RegistrationException;
import org.mule.api.registry.Registry;
import org.mule.api.registry.TransformerResolver;
import org.mule.api.transaction.TransactionFactory;
import org.mule.api.transformer.Converter;
import org.mule.api.transformer.DiscoverableTransformer;
import org.mule.api.transformer.Transformer;
import org.mule.api.util.StreamCloser;
import org.mule.config.i18n.CoreMessages;
import org.mule.registry.MuleRegistryHelper;
import org.mule.transformer.types.DataTypeFactory;
import org.mule.util.ClassUtils;
import org.mule.util.ExceptionUtils;
import org.mule.util.PropertiesUtils;
import org.mule.util.UUID;

import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * This object will load objects defined in a file called <code>registry-bootstrap.properties</code> into the local registry.
 * This allows modules and transports to make certain objects available by default.  The most common use case is for a
 * module or transport to load stateless transformers into the registry.
 * For this file to be located it must be present in the modules META-INF directory under
 * <pre>META-INF/services/org/mule/config/</pre>
 * <p/>
 * The format of this file is a simple key / value pair. i.e.
 * <pre>
 * myobject=org.foo.MyObject
 * </pre>
 * Will register an instance of MyObject with a key of 'myobject'. If you don't care about the object name and want to
 * ensure that the ojbect gets a unique name you can use -
 * <pre>
 * object.1=org.foo.MyObject
 * object.2=org.bar.MyObject
 * </pre>
 * or
 * <pre>
 * myFoo=org.foo.MyObject
 * myBar=org.bar.MyObject
 * </pre>
 * Loading transformers has a slightly different notation since you can define the 'returnClass' with optional mime type, and 'name'of
 * the transformer as parameters i.e.
 * <pre>
 * transformer.1=org.mule.transport.jms.transformers.JMSMessageToObject,returnClass=byte[]
 * transformer.2=org.mule.transport.jms.transformers.JMSMessageToObject,returnClass=java.lang.String:text/xml, name=JMSMessageToString
 * transformer.3=org.mule.transport.jms.transformers.JMSMessageToObject,returnClass=java.util.Hashtable)
 * </pre>
 * Note that the key used for transformers must be 'transformer.x' where 'x' is a sequential number.  The transformer name will be
 * automatically generated as JMSMessageToXXX where XXX is the return class name i.e. JMSMessageToString unless a 'name'
 * parameter is specified. If no 'returnClass' is specified the default in the transformer will be used.
 * <p/>
 * Note that all objects defined have to have a default constructor. They can implement injection interfaces such as
 * {@link org.mule.api.context.MuleContextAware} and lifecycle interfaces such as {@link org.mule.api.lifecycle.Initialisable}.
 */
public class SimpleRegistryBootstrap implements Initialisable, MuleContextAware {
    public static final String SERVICE_PATH = "META-INF/services/org/mule/config/";

    public static final String REGISTRY_PROPERTIES = "registry-bootstrap.properties";

    public String TRANSFORMER_KEY = ".transformer.";
    public String OBJECT_KEY = ".object.";
    public String SINGLE_TX = ".singletx.";

    protected final transient Log logger = LogFactory.getLog(getClass());

    protected MuleContext context;

    /** {@inheritDoc} */
    public void setMuleContext(MuleContext context) {
        this.context = context;
    }

    /** {@inheritDoc} */
    public void initialise() throws InitialisationException {
        Enumeration<?> e = ClassUtils.getResources(SERVICE_PATH + REGISTRY_PROPERTIES, getClass());
        List<Properties> bootstraps = new LinkedList<Properties>();

        // load ALL of the bootstrap files first
        while (e.hasMoreElements()) {
            try {
                URL url = (URL) e.nextElement();
                if (logger.isDebugEnabled()) {
                    logger.debug("Reading bootstrap file: " + url.toString());
                }
                Properties p = new Properties();
                p.load(url.openStream());
                bootstraps.add(p);
            } catch (Exception e1) {
                throw new InitialisationException(e1, this);
            }
        }

        // ... and only then merge and process them
        int objectCounter = 1;
        int transformerCounter = 1;
        Properties transformers = new Properties();
        Properties namedObjects = new Properties();
        Properties unnamedObjects = new Properties();
        Map<String, String> singleTransactionFactories = new HashMap<String, String>();

        for (Properties bootstrap : bootstraps) {
            for (Map.Entry entry : bootstrap.entrySet()) {
                final String key = (String) entry.getKey();
                if (key.contains(OBJECT_KEY)) {
                    String newKey = key.substring(0, key.lastIndexOf(".")) + objectCounter++;
                    unnamedObjects.put(newKey, entry.getValue());
                } else if (key.contains(TRANSFORMER_KEY)) {
                    String newKey = key.substring(0, key.lastIndexOf(".")) + transformerCounter++;
                    transformers.put(newKey, entry.getValue());
                } else if (key.contains(SINGLE_TX)) {
                    if (!key.contains(".transaction.resource")) {
                        String transactionResourceKey = key.replace(".transaction.factory",
                                ".transaction.resource");
                        String transactionResource = bootstrap.getProperty(transactionResourceKey);
                        if (transactionResource == null) {
                            throw new InitialisationException(CoreMessages.createStaticMessage(String.format(
                                    "Theres no transaction resource specified for transaction factory %s", key)),
                                    this);
                        }
                        singleTransactionFactories.put((String) entry.getValue(), transactionResource);
                    }
                } else {
                    // we allow arbitrary keys in the registry-bootstrap.properties but since we're
                    // aggregating multiple files here we must make sure that the keys are unique
                    //                    if (accumulatedProps.getProperty(key) != null)
                    //                    {
                    //                        throw new IllegalStateException(
                    //                                "more than one registry-bootstrap.properties file contains a key " + key);
                    //                    }
                    //                    else
                    {
                        namedObjects.put(key, entry.getValue());
                    }
                }
            }
        }

        try {
            registerUnnamedObjects(unnamedObjects, context.getRegistry());
            registerTransformers((MuleRegistryHelper) context.getRegistry());
            registerTransformers(transformers, context.getRegistry());
            registerObjects(namedObjects, context.getRegistry());
            registerTransactionFactories(singleTransactionFactories, context);
        } catch (Exception e1) {
            throw new InitialisationException(e1, this);
        }
    }

    private void registerTransactionFactories(Map<String, String> singleTransactionFactories, MuleContext context)
            throws Exception {
        for (String transactionFactoryClassName : singleTransactionFactories.keySet()) {
            String transactionResourceClassName = singleTransactionFactories.get(transactionFactoryClassName);
            context.getTransactionFactoryManager().registerTransactionFactory(
                    Class.forName(transactionResourceClassName),
                    (TransactionFactory) Class.forName(transactionFactoryClassName).newInstance());
        }
    }

    private void registerTransformers(Properties props, MuleRegistry registry) throws Exception {
        String transString;
        String name = null;
        String returnClassString;
        boolean optional = false;

        for (Map.Entry<Object, Object> entry : props.entrySet()) {
            transString = (String) entry.getValue();
            // reset
            Class<?> returnClass = null;
            returnClassString = null;
            int x = transString.indexOf(",");
            if (x > -1) {
                Properties p = PropertiesUtils.getPropertiesFromString(transString.substring(x + 1), ',');
                name = p.getProperty("name", null);
                returnClassString = p.getProperty("returnClass", null);
                optional = p.containsKey("optional");
            }

            final String transClass = (x == -1 ? transString : transString.substring(0, x));
            try {
                String mime = null;
                if (returnClassString != null) {
                    int i = returnClassString.indexOf(":");
                    if (i > -1) {
                        mime = returnClassString.substring(i + 1);
                        returnClassString = returnClassString.substring(0, i);
                    }
                    if (returnClassString.equals("byte[]")) {
                        returnClass = byte[].class;
                    } else {
                        returnClass = ClassUtils.loadClass(returnClassString, getClass());
                    }
                }
                Transformer trans = (Transformer) ClassUtils.instanciateClass(transClass);
                if (!(trans instanceof DiscoverableTransformer)) {
                    throw new RegistrationException(CoreMessages.transformerNotImplementDiscoverable(trans));
                }
                if (returnClass != null) {
                    trans.setReturnDataType(DataTypeFactory.create(returnClass, mime));
                }
                if (name != null) {
                    trans.setName(name);
                } else {
                    //This will generate a default name for the transformer
                    name = trans.getName();
                    //We then prefix the name to ensure there is less chance of conflict if the user registers
                    // the transformer with the same name
                    trans.setName("_" + name);
                }
                registry.registerTransformer(trans);
            } catch (InvocationTargetException itex) {
                Throwable cause = ExceptionUtils.getCause(itex);
                if (cause instanceof NoClassDefFoundError && optional) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Ignoring optional transformer: " + transClass);
                    }
                } else {
                    throw new Exception(cause);
                }
            } catch (NoClassDefFoundError ncdfe) {
                if (optional) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Ignoring optional transformer: " + transClass);
                    }
                } else {
                    throw ncdfe;
                }
            } catch (ClassNotFoundException cnfe) {
                if (optional) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Ignoring optional transformer: " + transClass);
                    }
                } else {
                    throw cnfe;
                }
            }

            name = null;
            returnClass = null;
        }
    }

    private void registerTransformers(MuleRegistryHelper registry) throws MuleException {
        Map<String, Converter> converters = registry.lookupByType(Converter.class);
        for (Converter converter : converters.values()) {
            registry.notifyTransformerResolvers(converter, TransformerResolver.RegistryAction.ADDED);
        }
    }

    private void registerObjects(Properties props, Registry registry) throws Exception {
        for (Map.Entry<Object, Object> entry : props.entrySet()) {
            registerObject((String) entry.getKey(), (String) entry.getValue(), registry);
        }
        props.clear();
    }

    private void registerUnnamedObjects(Properties props, Registry registry) throws Exception {
        for (Map.Entry<Object, Object> entry : props.entrySet()) {
            final String key = String.format("%s#%s", entry.getKey(), UUID.getUUID());
            registerObject(key, (String) entry.getValue(), registry);
        }
        props.clear();
    }

    private void registerObject(String key, String value, Registry registry) throws Exception {
        boolean optional = false;
        String className = null;

        try {
            int x = value.indexOf(",");
            if (x > -1) {
                Properties p = PropertiesUtils.getPropertiesFromString(value.substring(x + 1), ',');
                optional = p.containsKey("optional");
                className = value.substring(0, x);
            } else {
                className = value;
            }
            Object o = ClassUtils.instanciateClass(className);
            Class<?> meta = Object.class;

            if (o instanceof ObjectProcessor) {
                meta = ObjectProcessor.class;
            } else if (o instanceof StreamCloser) {
                meta = StreamCloser.class;
            } else if (o instanceof BootstrapObjectFactory) {
                o = ((BootstrapObjectFactory) o).create();
            }
            registry.registerObject(key, o, meta);
        } catch (InvocationTargetException itex) {
            Throwable cause = ExceptionUtils.getCause(itex);
            if (cause instanceof NoClassDefFoundError && optional) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Ignoring optional object: " + className);
                }
            } else {
                throw new Exception(cause);
            }
        } catch (NoClassDefFoundError ncdfe) {
            if (optional) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Ignoring optional object: " + className);
                }
            } else {
                throw ncdfe;
            }
        } catch (ClassNotFoundException cnfe) {
            if (optional) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Ignoring optional object: " + className);
                }
            } else {
                throw cnfe;
            }
        }
    }
}