Coverage Report - org.mule.config.bootstrap.SimpleRegistryBootstrap
 
Classes in this File Line Coverage Branch Coverage Complexity
SimpleRegistryBootstrap
0%
0/142
0%
0/70
0
 
 1  
 /*
 2  
  * $Id: SimpleRegistryBootstrap.java 19191 2010-08-25 21:05:23Z tcarlson $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 package org.mule.config.bootstrap;
 11  
 
 12  
 import org.mule.api.MuleContext;
 13  
 import org.mule.api.context.MuleContextAware;
 14  
 import org.mule.api.lifecycle.Initialisable;
 15  
 import org.mule.api.lifecycle.InitialisationException;
 16  
 import org.mule.api.registry.MuleRegistry;
 17  
 import org.mule.api.registry.ObjectProcessor;
 18  
 import org.mule.api.registry.RegistrationException;
 19  
 import org.mule.api.registry.Registry;
 20  
 import org.mule.api.transformer.DiscoverableTransformer;
 21  
 import org.mule.api.transformer.Transformer;
 22  
 import org.mule.api.util.StreamCloser;
 23  
 import org.mule.config.i18n.CoreMessages;
 24  
 import org.mule.transformer.types.DataTypeFactory;
 25  
 import org.mule.util.ClassUtils;
 26  
 import org.mule.util.ExceptionUtils;
 27  
 import org.mule.util.PropertiesUtils;
 28  
 import org.mule.util.UUID;
 29  
 
 30  
 import java.lang.reflect.InvocationTargetException;
 31  
 import java.net.URL;
 32  
 import java.util.Enumeration;
 33  
 import java.util.LinkedList;
 34  
 import java.util.List;
 35  
 import java.util.Map;
 36  
 import java.util.Properties;
 37  
 
 38  
 import org.apache.commons.logging.Log;
 39  
 import org.apache.commons.logging.LogFactory;
 40  
 
 41  
 /**
 42  
  * This object will load objects defined in a file called <code>registry-bootstrap.properties</code> into the local registry.
 43  
  * This allows modules and transports to make certain objects available by default.  The most common use case is for a
 44  
  * module or transport to load stateless transformers into the registry.
 45  
  * For this file to be located it must be present in the modules META-INF directory under
 46  
  * <pre>META-INF/services/org/mule/config/</pre>
 47  
  * <p/>
 48  
  * The format of this file is a simple key / value pair. i.e.
 49  
  * <pre>
 50  
  * myobject=org.foo.MyObject
 51  
  * </pre>
 52  
  * Will register an instance of MyObject with a key of 'myobject'. If you don't care about the object name and want to
 53  
  * ensure that the ojbect gets a unique name you can use -
 54  
  * <pre>
 55  
  * object.1=org.foo.MyObject
 56  
  * object.2=org.bar.MyObject
 57  
  * </pre>
 58  
  * or
 59  
  * <pre>
 60  
  * myFoo=org.foo.MyObject
 61  
  * myBar=org.bar.MyObject
 62  
  * </pre>
 63  
  * Loading transformers has a slightly different notation since you can define the 'returnClass' with optional mime type, and 'name'of
 64  
  * the transformer as parameters i.e.
 65  
  * <pre>
 66  
  * transformer.1=org.mule.transport.jms.transformers.JMSMessageToObject,returnClass=byte[]
 67  
  * transformer.2=org.mule.transport.jms.transformers.JMSMessageToObject,returnClass=java.lang.String:text/xml, name=JMSMessageToString
 68  
  * transformer.3=org.mule.transport.jms.transformers.JMSMessageToObject,returnClass=java.util.Hashtable)
 69  
  * </pre>
 70  
  * Note that the key used for transformers must be 'transformer.x' where 'x' is a sequential number.  The transformer name will be
 71  
  * automatically generated as JMSMessageToXXX where XXX is the return class name i.e. JMSMessageToString unless a 'name'
 72  
  * parameter is specified. If no 'returnClass' is specified the default in the transformer will be used.
 73  
  * <p/>
 74  
  * Note that all objects defined have to have a default constructor. They can implement injection interfaces such as
 75  
  * {@link org.mule.api.context.MuleContextAware} and lifecycle interfaces such as {@link org.mule.api.lifecycle.Initialisable}.
 76  
  */
 77  0
 public class SimpleRegistryBootstrap implements Initialisable, MuleContextAware
 78  
 {
 79  
     public static final String SERVICE_PATH = "META-INF/services/org/mule/config/";
 80  
 
 81  
     public static final String REGISTRY_PROPERTIES = "registry-bootstrap.properties";
 82  
 
 83  0
     public String TRANSFORMER_KEY = ".transformer.";
 84  0
     public String OBJECT_KEY = ".object.";
 85  
 
 86  0
     protected final transient Log logger = LogFactory.getLog(getClass());
 87  
 
 88  
     protected MuleContext context;
 89  
 
 90  
     /** {@inheritDoc} */
 91  
     public void setMuleContext(MuleContext context)
 92  
     {
 93  0
         this.context = context;
 94  0
     }
 95  
 
 96  
     /** {@inheritDoc} */
 97  
     public void initialise() throws InitialisationException
 98  
     {
 99  0
         Enumeration<?> e = ClassUtils.getResources(SERVICE_PATH + REGISTRY_PROPERTIES, getClass());
 100  0
         List<Properties> bootstraps = new LinkedList<Properties>();
 101  
 
 102  
         // load ALL of the bootstrap files first
 103  0
         while (e.hasMoreElements())
 104  
         {
 105  
             try
 106  
             {
 107  0
                 URL url = (URL) e.nextElement();
 108  0
                 if (logger.isDebugEnabled())
 109  
                 {
 110  0
                     logger.debug("Reading bootstrap file: " + url.toString());
 111  
                 }
 112  0
                 Properties p = new Properties();
 113  0
                 p.load(url.openStream());
 114  0
                 bootstraps.add(p);
 115  
             }
 116  0
             catch (Exception e1)
 117  
             {
 118  0
                 throw new InitialisationException(e1, this);
 119  0
             }
 120  
         }
 121  
 
 122  
         // ... and only then merge and process them
 123  0
         int objectCounter = 1;
 124  0
         int transformerCounter = 1;
 125  0
         Properties transformers = new Properties();
 126  0
         Properties namedObjects = new Properties();
 127  0
         Properties unnamedObjects = new Properties();
 128  
 
 129  0
         for (Properties bootstrap : bootstraps)
 130  
         {
 131  0
             for (Map.Entry entry : bootstrap.entrySet())
 132  
             {
 133  0
                 final String key = (String) entry.getKey();
 134  0
                 if (key.contains(OBJECT_KEY))
 135  
                 {
 136  0
                     String newKey = key.substring(0, key.lastIndexOf(".")) + objectCounter++;
 137  0
                     unnamedObjects.put(newKey, entry.getValue());
 138  0
                 }
 139  0
                 else if (key.contains(TRANSFORMER_KEY))
 140  
                 {
 141  0
                     String newKey = key.substring(0, key.lastIndexOf(".")) + transformerCounter++;
 142  0
                     transformers.put(newKey, entry.getValue());
 143  0
                 }
 144  
                 else
 145  
                 {
 146  
                     // we allow arbitrary keys in the registry-bootstrap.properties but since we're
 147  
                     // aggregating multiple files here we must make sure that the keys are unique
 148  
 //                    if (accumulatedProps.getProperty(key) != null)
 149  
 //                    {
 150  
 //                        throw new IllegalStateException(
 151  
 //                                "more than one registry-bootstrap.properties file contains a key " + key);
 152  
 //                    }
 153  
 //                    else
 154  
                     {
 155  0
                         namedObjects.put(key, entry.getValue());
 156  
                     }
 157  
                 }
 158  0
             }
 159  
         }
 160  
 
 161  
         try
 162  
         {
 163  0
             registerUnnamedObjects(unnamedObjects, context.getRegistry());
 164  0
             registerTransformers(transformers, context.getRegistry());
 165  0
             registerObjects(namedObjects, context.getRegistry());
 166  
         }
 167  0
         catch (Exception e1)
 168  
         {
 169  0
             throw new InitialisationException(e1, this);
 170  0
         }
 171  0
     }
 172  
 
 173  
     private void registerTransformers(Properties props, MuleRegistry registry) throws Exception
 174  
     {
 175  
         String transString;
 176  0
         String name = null;
 177  
         String returnClassString;
 178  0
         boolean optional = false;
 179  
 
 180  0
         for (Map.Entry<Object, Object> entry : props.entrySet())
 181  
         {
 182  0
             transString = (String)entry.getValue();
 183  
             // reset
 184  0
             Class<?> returnClass = null;
 185  0
             returnClassString = null;
 186  0
             int x = transString.indexOf(",");
 187  0
             if (x > -1)
 188  
             {
 189  0
                 Properties p = PropertiesUtils.getPropertiesFromString(transString.substring(x + 1), ',');
 190  0
                 name = p.getProperty("name", null);
 191  0
                 returnClassString = p.getProperty("returnClass", null);
 192  0
                 optional = p.containsKey("optional");
 193  
             }
 194  
 
 195  0
             final String transClass = (x == -1 ? transString : transString.substring(0, x));
 196  
             try
 197  
             {
 198  0
                 String mime = null;
 199  0
                 if (returnClassString != null)
 200  
                 {
 201  0
                     int i = returnClassString.indexOf(":");
 202  0
                     if(i > -1)
 203  
                     {
 204  0
                         mime = returnClassString.substring(i + 1);
 205  0
                         returnClassString = returnClassString.substring(0, i);
 206  
                     }
 207  0
                     if (returnClassString.equals("byte[]"))
 208  
                     {
 209  0
                         returnClass = byte[].class;
 210  
                     }
 211  
                     else
 212  
                     {
 213  0
                         returnClass = ClassUtils.loadClass(returnClassString, getClass());
 214  
                     }
 215  
                 }
 216  0
                 Transformer trans = (Transformer) ClassUtils.instanciateClass(transClass);
 217  0
                 if (!(trans instanceof DiscoverableTransformer))
 218  
                 {
 219  0
                     throw new RegistrationException(CoreMessages.transformerNotImplementDiscoverable(trans));
 220  
                 }
 221  0
                 if (returnClass != null)
 222  
                 {
 223  0
                     trans.setReturnDataType(DataTypeFactory.create(returnClass, mime));
 224  
                 }
 225  0
                 if (name != null)
 226  
                 {
 227  0
                     trans.setName(name);
 228  
                 }
 229  
                 else
 230  
                 {
 231  
                     //This will generate a default name for the transformer
 232  0
                     name = trans.getName();
 233  
                     //We then prefix the name to ensure there is less chance of conflict if the user registers
 234  
                     // the transformer with the same name
 235  0
                     trans.setName("_" + name);
 236  
                 }
 237  0
                 registry.registerTransformer(trans);
 238  
             }
 239  0
             catch (InvocationTargetException itex)
 240  
             {
 241  0
                 Throwable cause = ExceptionUtils.getCause(itex);
 242  0
                 if (cause instanceof NoClassDefFoundError && optional)
 243  
                 {
 244  0
                     if (logger.isDebugEnabled())
 245  
                     {
 246  0
                         logger.debug("Ignoring optional transformer: " + transClass);
 247  
                     }
 248  
                 }
 249  
                 else
 250  
                 {
 251  0
                     throw new Exception(cause);
 252  
                 }
 253  
             }
 254  0
             catch (NoClassDefFoundError ncdfe)
 255  
             {
 256  0
                 if (optional)
 257  
                 {
 258  0
                     if (logger.isDebugEnabled())
 259  
                     {
 260  0
                         logger.debug("Ignoring optional transformer: " + transClass);
 261  
                     }
 262  
                 }
 263  
                 else
 264  
                 {
 265  0
                     throw ncdfe;
 266  
                 }
 267  
             }
 268  0
             catch (ClassNotFoundException cnfe)
 269  
             {
 270  0
                 if (optional)
 271  
                 {
 272  0
                     if (logger.isDebugEnabled())
 273  
                     {
 274  0
                         logger.debug("Ignoring optional transformer: " + transClass);
 275  
                     }
 276  
                 }
 277  
                 else
 278  
                 {
 279  0
                     throw cnfe;
 280  
                 }
 281  0
             }
 282  
 
 283  0
             name = null;
 284  0
             returnClass = null;
 285  0
         }
 286  0
     }
 287  
 
 288  
     private void registerObjects(Properties props, Registry registry) throws Exception
 289  
     {
 290  0
         for (Map.Entry<Object, Object> entry : props.entrySet())
 291  
         {
 292  0
             registerObject((String)entry.getKey(), (String)entry.getValue(), registry);
 293  
         }
 294  0
         props.clear();
 295  0
     }
 296  
 
 297  
     private void registerUnnamedObjects(Properties props, Registry registry) throws Exception
 298  
     {
 299  0
         for (Map.Entry<Object, Object> entry : props.entrySet())
 300  
         {
 301  0
             final String key = String.format("%s#%s", entry.getKey(), UUID.getUUID());
 302  0
             registerObject(key, (String) entry.getValue(), registry);
 303  0
         }
 304  0
         props.clear();
 305  0
     }
 306  
 
 307  
     private void registerObject(String key, String value, Registry registry) throws Exception
 308  
     {
 309  0
         boolean optional = false;
 310  0
         String className = null;
 311  
 
 312  
         try
 313  
         {
 314  0
             int x = value.indexOf(",");
 315  0
             if (x > -1)
 316  
             {
 317  0
                 Properties p = PropertiesUtils.getPropertiesFromString(value.substring(x + 1), ',');
 318  0
                 optional = p.containsKey("optional");
 319  0
                 className = value.substring(0, x);
 320  0
             }
 321  
             else
 322  
             {
 323  0
                 className = value;
 324  
             }
 325  0
             Object o = ClassUtils.instanciateClass(className);
 326  0
             Class<?> meta = Object.class;
 327  
 
 328  0
             if (o instanceof ObjectProcessor)
 329  
             {
 330  0
                 meta = ObjectProcessor.class;
 331  
             }
 332  0
             else if (o instanceof StreamCloser)
 333  
             {
 334  0
                 meta = StreamCloser.class;
 335  
             }
 336  0
             else if (o instanceof BootstrapObjectFactory)
 337  
             {
 338  0
                 o = ((BootstrapObjectFactory)o).create();
 339  
             }
 340  0
             registry.registerObject(key, o, meta);
 341  
         }
 342  0
         catch (InvocationTargetException itex)
 343  
         {
 344  0
             Throwable cause = ExceptionUtils.getCause(itex);
 345  0
             if (cause instanceof NoClassDefFoundError && optional)
 346  
             {
 347  0
                 if (logger.isDebugEnabled())
 348  
                 {
 349  0
                     logger.debug("Ignoring optional object: " + className);
 350  
                 }
 351  
             }
 352  
             else
 353  
             {
 354  0
                 throw new Exception(cause);
 355  
             }
 356  
         }
 357  0
         catch (NoClassDefFoundError ncdfe)
 358  
         {
 359  0
             if (optional)
 360  
             {
 361  0
                 if (logger.isDebugEnabled())
 362  
                 {
 363  0
                     logger.debug("Ignoring optional object: " + className);
 364  
                 }
 365  
             }
 366  
             else
 367  
             {
 368  0
                 throw ncdfe;
 369  
             }
 370  
         }
 371  0
         catch (ClassNotFoundException cnfe)
 372  
         {
 373  0
             if (optional)
 374  
             {
 375  0
                 if (logger.isDebugEnabled())
 376  
                 {
 377  0
                     logger.debug("Ignoring optional object: " + className);
 378  
                 }
 379  
             }
 380  
             else
 381  
             {
 382  0
                 throw cnfe;
 383  
             }
 384  0
         }
 385  0
     }
 386  
 }