Coverage Report - org.mule.registry.TransientRegistry
 
Classes in this File Line Coverage Branch Coverage Complexity
TransientRegistry
0%
0/104
0%
0/46
0
TransientRegistry$RegistryMap
0%
0/42
0%
0/2
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.registry;
 8  
 
 9  
 import org.mule.api.MuleContext;
 10  
 import org.mule.api.MuleException;
 11  
 import org.mule.api.agent.Agent;
 12  
 import org.mule.api.endpoint.ImmutableEndpoint;
 13  
 import org.mule.api.lifecycle.Disposable;
 14  
 import org.mule.api.lifecycle.InitialisationException;
 15  
 import org.mule.api.model.Model;
 16  
 import org.mule.api.registry.InjectProcessor;
 17  
 import org.mule.api.registry.MuleRegistry;
 18  
 import org.mule.api.registry.ObjectProcessor;
 19  
 import org.mule.api.registry.PreInitProcessor;
 20  
 import org.mule.api.registry.RegistrationException;
 21  
 import org.mule.api.service.Service;
 22  
 import org.mule.api.transformer.Transformer;
 23  
 import org.mule.api.transport.Connector;
 24  
 import org.mule.config.i18n.MessageFactory;
 25  
 import org.mule.lifecycle.phases.NotInLifecyclePhase;
 26  
 import org.mule.util.CollectionUtils;
 27  
 import org.mule.util.StringUtils;
 28  
 
 29  
 import java.util.Collection;
 30  
 import java.util.HashMap;
 31  
 import java.util.Map;
 32  
 import java.util.Map.Entry;
 33  
 import java.util.Set;
 34  
 import java.util.concurrent.locks.Lock;
 35  
 import java.util.concurrent.locks.ReadWriteLock;
 36  
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 37  
 
 38  
 import org.apache.commons.collections.Predicate;
 39  
 import org.apache.commons.collections.functors.InstanceofPredicate;
 40  
 import org.apache.commons.logging.Log;
 41  
 
 42  
 /**
 43  
  * Use the registryLock when reading/writing/iterating over the contents of the registry hashmap.
 44  
  */
 45  
 //@ThreadSafe
 46  
 public class TransientRegistry extends AbstractRegistry
 47  
 {
 48  
     public static final String REGISTRY_ID = "org.mule.Registry.Transient";
 49  
 
 50  0
     private final RegistryMap registryMap = new RegistryMap(logger);
 51  
 
 52  
     public TransientRegistry(MuleContext muleContext)
 53  
     {
 54  0
         this(REGISTRY_ID, muleContext);
 55  0
     }
 56  
 
 57  
     public TransientRegistry(String id, MuleContext muleContext)
 58  
     {
 59  0
         super(id, muleContext);
 60  0
         putDefaultEntriesIntoRegistry();
 61  0
     }
 62  
 
 63  
     private void putDefaultEntriesIntoRegistry()
 64  
     {
 65  0
         Map<String, Object> processors = new HashMap<String, Object>();
 66  0
         processors.put("_muleContextProcessor", new MuleContextProcessor(muleContext));
 67  
         //processors("_muleNotificationProcessor", new NotificationListenersProcessor(muleContext));
 68  0
         processors.put("_muleExpressionEvaluatorProcessor", new ExpressionEvaluatorProcessor(muleContext));
 69  0
         processors.put("_muleExpressionEnricherProcessor", new ExpressionEnricherProcessor(muleContext));
 70  0
         processors.put("_muleLifecycleStateInjectorProcessor", new LifecycleStateInjectorProcessor(getLifecycleManager().getState()));
 71  0
         processors.put("_muleLifecycleManager", getLifecycleManager());
 72  0
         registryMap.putAll(processors);
 73  0
     }
 74  
 
 75  
     @Override
 76  
     protected void doInitialise() throws InitialisationException
 77  
     {
 78  0
         applyProcessors(lookupObjects(Connector.class), null);
 79  0
         applyProcessors(lookupObjects(Transformer.class), null);
 80  0
         applyProcessors(lookupObjects(ImmutableEndpoint.class), null);
 81  0
         applyProcessors(lookupObjects(Agent.class), null);
 82  0
         applyProcessors(lookupObjects(Model.class), null);
 83  0
         applyProcessors(lookupObjects(Service.class), null);
 84  0
         applyProcessors(lookupObjects(Object.class), null);
 85  0
     }
 86  
 
 87  
     @Override
 88  
     protected void doDispose()
 89  
     {
 90  0
         registryMap.clear();
 91  0
     }
 92  
 
 93  
     protected Map<String, Object> applyProcessors(Map<String, Object> objects)
 94  
     {
 95  0
         if (objects == null)
 96  
         {
 97  0
             return null;
 98  
         }
 99  
 
 100  0
         Map<String, Object> results = new HashMap<String, Object>();
 101  0
         for (Map.Entry<String, Object> entry : objects.entrySet())
 102  
         {
 103  
             // We do this inside the loop in case the map contains ObjectProcessors
 104  0
             Collection<ObjectProcessor> processors = lookupObjects(ObjectProcessor.class);
 105  0
             for (ObjectProcessor processor : processors)
 106  
             {
 107  0
                 Object result = processor.process(entry.getValue());
 108  0
                 if (result != null)
 109  
                 {
 110  0
                     results.put(entry.getKey(), result);
 111  
                 }
 112  0
             }
 113  0
         }
 114  0
         return results;
 115  
     }
 116  
 
 117  
 
 118  
     public void registerObjects(Map<String, Object> objects) throws RegistrationException
 119  
     {
 120  0
         if (objects == null)
 121  
         {
 122  0
             return;
 123  
         }
 124  
 
 125  0
         for (Map.Entry<String, Object> entry : objects.entrySet())
 126  
         {
 127  0
             registerObject(entry.getKey(), entry.getValue());
 128  
         }
 129  0
     }
 130  
 
 131  
     @SuppressWarnings("unchecked")
 132  
     public <T> Map<String, T> lookupByType(Class<T> type)
 133  
     {
 134  0
         final Map<String, T> results = new HashMap<String, T>();
 135  
         try
 136  
         {
 137  0
             registryMap.lockForReading();
 138  
 
 139  0
             for (Map.Entry<String, Object> entry : registryMap.entrySet())
 140  
             {
 141  0
                 final Class<?> clazz = entry.getValue().getClass();
 142  0
                 if (type.isAssignableFrom(clazz))
 143  
                 {
 144  0
                     results.put(entry.getKey(), (T) entry.getValue());
 145  
                 }
 146  0
             }
 147  
         }
 148  
         finally
 149  
         {
 150  0
             registryMap.unlockForReading();
 151  0
         }
 152  
 
 153  0
         return results;
 154  
     }
 155  
 
 156  
     public <T> T lookupObject(String key)
 157  
     {
 158  0
         return registryMap.<T>get(key);
 159  
     }
 160  
 
 161  
     @SuppressWarnings("unchecked")
 162  
     public <T> Collection<T> lookupObjects(Class<T> returntype)
 163  
     {
 164  0
         return (Collection<T>) registryMap.select(new InstanceofPredicate(returntype));
 165  
     }
 166  
 
 167  
     /**
 168  
      * Will fire any lifecycle methods according to the current lifecycle without actually
 169  
      * registering the object in the registry.  This is useful for prototype objects that are created per request and would
 170  
      * clutter the registry with single use objects.
 171  
      *
 172  
      * @param object the object to process
 173  
      * @return the same object with lifecycle methods called (if it has any)
 174  
      * @throws org.mule.api.MuleException if the registry fails to perform the lifecycle change for the object.
 175  
      */
 176  
     Object applyLifecycle(Object object) throws MuleException
 177  
     {
 178  0
         getLifecycleManager().applyCompletedPhases(object);
 179  0
         return object;
 180  
     }
 181  
 
 182  
     Object applyLifecycle(Object object, String phase) throws MuleException
 183  
     {
 184  0
         getLifecycleManager().applyPhase(object, NotInLifecyclePhase.PHASE_NAME, phase);
 185  0
         return object;
 186  
     }
 187  
 
 188  
     Object applyProcessors(Object object, Object metadata)
 189  
     {
 190  0
         Object theObject = object;
 191  
 
 192  0
         if(!hasFlag(metadata, MuleRegistry.INJECT_PROCESSORS_BYPASS_FLAG))
 193  
         {
 194  
             //Process injectors first
 195  0
             Collection<InjectProcessor> injectProcessors = lookupObjects(InjectProcessor.class);
 196  0
             for (InjectProcessor processor : injectProcessors)
 197  
             {
 198  0
                 theObject = processor.process(theObject);
 199  
             }
 200  
         }
 201  
 
 202  0
         if(!hasFlag(metadata, MuleRegistry.PRE_INIT_PROCESSORS_BYPASS_FLAG))
 203  
         {
 204  
             //Then any other processors
 205  0
             Collection<PreInitProcessor> processors = lookupObjects(PreInitProcessor.class);
 206  0
             for (PreInitProcessor processor : processors)
 207  
             {
 208  0
                 theObject = processor.process(theObject);
 209  0
                 if(theObject==null)
 210  
                 {
 211  0
                     return null;
 212  
                 }
 213  
             }
 214  
         }
 215  0
         return theObject;
 216  
     }
 217  
 
 218  
     /**
 219  
      * Allows for arbitary registration of transient objects
 220  
      *
 221  
      * @param key
 222  
      * @param value
 223  
      */
 224  
     public void registerObject(String key, Object value) throws RegistrationException
 225  
     {
 226  0
         registerObject(key, value, Object.class);
 227  0
     }
 228  
 
 229  
     /**
 230  
      * Allows for arbitrary registration of transient objects
 231  
      */
 232  
     public void registerObject(String key, Object object, Object metadata) throws RegistrationException
 233  
     {
 234  0
         checkDisposed();
 235  0
         if (StringUtils.isBlank(key))
 236  
         {
 237  0
             throw new RegistrationException(MessageFactory.createStaticMessage("Attempt to register object with no key"));
 238  
         }
 239  
 
 240  0
         if (logger.isDebugEnabled())
 241  
         {
 242  0
             logger.debug(String.format("registering key/object %s/%s", key, object));
 243  
         }
 244  
 
 245  0
         logger.debug("applying processors");
 246  0
         object = applyProcessors(object, metadata);
 247  0
         if (object == null)
 248  
         {
 249  0
             return;
 250  
         }
 251  
 
 252  0
         registryMap.putAndLogWarningIfDuplicate(key, object);
 253  
 
 254  
         try
 255  
         {
 256  0
             if (!hasFlag(metadata, MuleRegistry.LIFECYCLE_BYPASS_FLAG))
 257  
             {
 258  0
                 if(logger.isDebugEnabled())
 259  
                 {
 260  0
                     logger.debug("applying lifecycle to object: " + object);
 261  
                 }
 262  0
                 getLifecycleManager().applyCompletedPhases(object);
 263  
             }
 264  
         }
 265  0
         catch (MuleException e)
 266  
         {
 267  0
             throw new RegistrationException(e);
 268  0
         }
 269  0
     }
 270  
 
 271  
     protected void checkDisposed() throws RegistrationException
 272  
     {
 273  0
         if(getLifecycleManager().isPhaseComplete(Disposable.PHASE_NAME))
 274  
         {
 275  0
             throw new RegistrationException(MessageFactory.createStaticMessage("Cannot register objects on the registry as the context is disposed"));
 276  
         }
 277  0
     }
 278  
 
 279  
     protected boolean hasFlag(Object metaData, int flag)
 280  
     {
 281  0
         return !(metaData == null || !(metaData instanceof Integer)) && ((Integer) metaData & flag) != 0;
 282  
     }
 283  
 
 284  
     /**
 285  
      * Will remove an object by name from the registry. By default the registry will apply all remaining lifecycle phases
 286  
      * to the object when it is removed.
 287  
      *
 288  
      * @param key the name or key of the object to remove from the registry
 289  
      * @param metadata Meta data flags supported are {@link org.mule.api.registry.MuleRegistry#LIFECYCLE_BYPASS_FLAG}
 290  
      * @throws RegistrationException if there is a problem unregistering the object. Typically this will be because
 291  
      * the object's lifecycle threw an exception
 292  
      */
 293  
     public void unregisterObject(String key, Object metadata) throws RegistrationException
 294  
     {
 295  0
         Object obj = registryMap.remove(key);
 296  
 
 297  
         try
 298  
         {
 299  0
             if (!hasFlag(metadata, MuleRegistry.LIFECYCLE_BYPASS_FLAG))
 300  
             {
 301  0
                 getLifecycleManager().applyPhase(obj, lifecycleManager.getCurrentPhase(), Disposable.PHASE_NAME);
 302  
             }
 303  
         }
 304  0
         catch (MuleException e)
 305  
         {
 306  0
             throw new RegistrationException(e);
 307  0
         }
 308  
 
 309  0
     }
 310  
 
 311  
     public void unregisterObject(String key) throws RegistrationException
 312  
     {
 313  0
         unregisterObject(key, Object.class);
 314  0
     }
 315  
 
 316  
     // /////////////////////////////////////////////////////////////////////////
 317  
     // Registry Metadata
 318  
     // /////////////////////////////////////////////////////////////////////////
 319  
 
 320  
     public boolean isReadOnly()
 321  
     {
 322  0
         return false;
 323  
     }
 324  
 
 325  
     public boolean isRemote()
 326  
     {
 327  0
         return false;
 328  
     }
 329  
 
 330  
     /**
 331  
      * This class encapsulates the {@link HashMap} that's used for storing the objects in the
 332  
      * transient registry and also shields client code from having to deal with locking the
 333  
      * {@link ReadWriteLock} for the exposed Map operations.
 334  
      */
 335  
     private static class RegistryMap
 336  
     {
 337  0
         private final Map<String, Object> registry = new HashMap<String, Object>();
 338  0
         private final ReadWriteLock registryLock = new ReentrantReadWriteLock();
 339  
 
 340  
         private Log logger;
 341  
 
 342  
         public RegistryMap(Log log)
 343  
         {
 344  0
             super();
 345  0
             logger = log;
 346  0
         }
 347  
 
 348  
         public Collection<?> select(Predicate predicate)
 349  
         {
 350  0
             Lock readLock = registryLock.readLock();
 351  
             try
 352  
             {
 353  0
                 readLock.lock();
 354  0
                 return CollectionUtils.select(registry.values(), predicate);
 355  
             }
 356  
             finally
 357  
             {
 358  0
                 readLock.unlock();
 359  
             }
 360  
         }
 361  
 
 362  
         public void clear()
 363  
         {
 364  0
             Lock writeLock = registryLock.writeLock();
 365  
             try
 366  
             {
 367  0
                 writeLock.lock();
 368  0
                 registry.clear();
 369  
             }
 370  
             finally
 371  
             {
 372  0
                 writeLock.unlock();
 373  0
             }
 374  0
         }
 375  
 
 376  
         public void putAndLogWarningIfDuplicate(String key, Object object)
 377  
         {
 378  0
             Lock writeLock = registryLock.writeLock();
 379  
             try
 380  
             {
 381  0
                 writeLock.lock();
 382  
 
 383  0
                 if (registry.containsKey(key))
 384  
                 {
 385  
                     // registry.put(key, value) would overwrite a previous entity with the same name.  Is this really what we want?
 386  
                     // Not sure whether to throw an exception or log a warning here.
 387  
                     //throw new RegistrationException("TransientRegistry already contains an object named '" + key + "'.  The previous object would be overwritten.");
 388  0
                     logger.warn("TransientRegistry already contains an object named '" + key + "'.  The previous object will be overwritten.");
 389  
                 }
 390  0
                 registry.put(key, object);
 391  
             }
 392  
             finally
 393  
             {
 394  0
                 writeLock.unlock();
 395  0
             }
 396  0
         }
 397  
 
 398  
         public void putAll(Map<String, Object> map)
 399  
         {
 400  0
             Lock writeLock = registryLock.writeLock();
 401  
             try
 402  
             {
 403  0
                 writeLock.lock();
 404  0
                 registry.putAll(map);
 405  
             }
 406  
             finally
 407  
             {
 408  0
                 writeLock.unlock();
 409  0
             }
 410  0
         }
 411  
 
 412  
         @SuppressWarnings("unchecked")
 413  
         public <T> T get(String key)
 414  
         {
 415  0
             Lock readLock = registryLock.readLock();
 416  
             try
 417  
             {
 418  0
                 readLock.lock();
 419  0
                 return (T) registry.get(key);
 420  
             }
 421  
             finally
 422  
             {
 423  0
                 readLock.unlock();
 424  
             }
 425  
         }
 426  
 
 427  
         public Object remove(String key)
 428  
         {
 429  0
             Lock writeLock = registryLock.writeLock();
 430  
             try
 431  
             {
 432  0
                 writeLock.lock();
 433  0
                 return registry.remove(key);
 434  
             }
 435  
             finally
 436  
             {
 437  0
                 writeLock.unlock();
 438  
             }
 439  
         }
 440  
 
 441  
         public Set<Entry<String, Object>> entrySet()
 442  
         {
 443  0
             return registry.entrySet();
 444  
         }
 445  
 
 446  
         public void lockForReading()
 447  
         {
 448  0
             registryLock.readLock().lock();
 449  0
         }
 450  
 
 451  
         public void unlockForReading()
 452  
         {
 453  0
             registryLock.readLock().unlock();
 454  0
         }
 455  
     }
 456  
 }