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