View Javadoc

1   /*
2    * $Id: TransientRegistry.java 20267 2010-11-19 03:15:43Z dfeist $
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.registry;
11  
12  import org.mule.api.MuleContext;
13  import org.mule.api.MuleException;
14  import org.mule.api.agent.Agent;
15  import org.mule.api.endpoint.ImmutableEndpoint;
16  import org.mule.api.lifecycle.Disposable;
17  import org.mule.api.lifecycle.InitialisationException;
18  import org.mule.api.model.Model;
19  import org.mule.api.registry.InjectProcessor;
20  import org.mule.api.registry.MuleRegistry;
21  import org.mule.api.registry.ObjectProcessor;
22  import org.mule.api.registry.PreInitProcessor;
23  import org.mule.api.registry.RegistrationException;
24  import org.mule.api.service.Service;
25  import org.mule.api.transformer.Transformer;
26  import org.mule.api.transport.Connector;
27  import org.mule.config.i18n.MessageFactory;
28  import org.mule.lifecycle.phases.NotInLifecyclePhase;
29  import org.mule.util.CollectionUtils;
30  import org.mule.util.StringUtils;
31  
32  import java.util.Collection;
33  import java.util.HashMap;
34  import java.util.Iterator;
35  import java.util.Map;
36  
37  import org.apache.commons.collections.functors.InstanceofPredicate;
38  import org.apache.commons.logging.Log;
39  import org.apache.commons.logging.LogFactory;
40  
41  /**
42   * Use synchronized(registry) when reading/writing/iterating over the contents of the registry hashmap.
43   */
44  //@ThreadSafe
45  public class TransientRegistry extends AbstractRegistry
46  {
47      /** logger used by this class */
48      protected transient final Log logger = LogFactory.getLog(TransientRegistry.class);
49      public static final String REGISTRY_ID = "org.mule.Registry.Transient";
50  
51      //@ThreadSafe synchronized(registry)
52      private final Map<String, Object> registry = new HashMap<String, Object>();
53  
54  
55      public TransientRegistry(MuleContext muleContext)
56      {
57          this(REGISTRY_ID, muleContext);
58      }
59  
60      public TransientRegistry(String id, MuleContext muleContext)
61      {
62          super(id, muleContext);
63          synchronized(registry)
64          {
65              registry.put("_muleContextProcessor", new MuleContextProcessor(muleContext));
66              //registry.put("_muleNotificationProcessor", new NotificationListenersProcessor(muleContext));
67              registry.put("_muleExpressionEvaluatorProcessor", new ExpressionEvaluatorProcessor(muleContext));
68              registry.put("_muleExpressionEnricherProcessor", new ExpressionEnricherProcessor(muleContext));
69              registry.put("_muleLifecycleStateInjectorProcessor", new LifecycleStateInjectorProcessor(getLifecycleManager().getState()));
70              registry.put("_muleLifecycleManager", getLifecycleManager());
71          }
72      }
73  
74      @Override
75      protected void doInitialise() throws InitialisationException
76      {
77          applyProcessors(lookupObjects(Connector.class), null);
78          applyProcessors(lookupObjects(Transformer.class), null);
79          applyProcessors(lookupObjects(ImmutableEndpoint.class), null);
80          applyProcessors(lookupObjects(Agent.class), null);
81          applyProcessors(lookupObjects(Model.class), null);
82          applyProcessors(lookupObjects(Service.class), null);
83          applyProcessors(lookupObjects(Object.class), null);
84      }
85  
86      @Override
87      protected void doDispose()
88      {
89          registry.clear();
90      }
91  
92      protected Map applyProcessors(Map<String, Object> objects)
93      {
94          if (objects == null)
95          {
96              return null;
97          }
98          Map<String, Object> results = new HashMap<String, Object>();
99          for (Map.Entry<String, Object> entry : objects.entrySet())
100         {
101             //We do this in the loop in case the map contains ObjectProcessors
102             Collection<ObjectProcessor> processors = lookupObjects(ObjectProcessor.class);
103             for (ObjectProcessor processor : processors)
104             {
105                 Object result = processor.process(entry.getValue());
106                 //If result is null do not add the object
107                 if(result != null)
108                 {
109                     results.put(entry.getKey(), result);
110                 }
111             }
112         }
113         return results;
114     }
115 
116 
117     public void registerObjects(Map objects) throws RegistrationException
118     {
119         if (objects == null)
120         {
121             return;
122         }
123 
124         for (Iterator iterator = objects.entrySet().iterator(); iterator.hasNext();)
125         {
126             Map.Entry entry = (Map.Entry) iterator.next();
127             registerObject(entry.getKey().toString(), entry.getValue());
128         }
129     }
130 
131     @SuppressWarnings("unchecked")
132     public <T> Map<String, T> lookupByType(Class<T> type)
133     {
134         synchronized(registry)
135         {
136             final Map<String, T> results = new HashMap<String, T>();
137             for (Map.Entry<String, Object> entry : registry.entrySet())
138             {
139                 final Class clazz = entry.getValue().getClass();
140                 if (type.isAssignableFrom(clazz))
141                 {
142                     results.put(entry.getKey(), (T) entry.getValue());
143                 }
144             }
145 
146             return results;
147         }
148     }
149 
150     @SuppressWarnings("unchecked")
151     public <T> T  lookupObject(String key)
152     {
153         synchronized(registry)
154         {
155             return (T) registry.get(key);
156         }
157     }
158 
159     @SuppressWarnings("unchecked")
160     public <T> Collection<T> lookupObjects(Class<T> returntype)
161     {
162         synchronized(registry)
163         {
164             return CollectionUtils.select(registry.values(), new InstanceofPredicate(returntype));
165         }
166     }
167 
168     /**
169      * Will fire any lifecycle methods according to the current lifecycle without actually
170      * registering the object in the registry.  This is useful for prototype objects that are created per request and would
171      * clutter the registry with single use objects.
172      *
173      * @param object the object to process
174      * @return the same object with lifecycle methods called (if it has any)
175      * @throws org.mule.api.MuleException if the registry fails to perform the lifecycle change for the object.
176      */
177     Object applyLifecycle(Object object) throws MuleException
178     {
179         getLifecycleManager().applyCompletedPhases(object);
180         return object;
181     }
182 
183     Object applyLifecycle(Object object, String phase) throws MuleException
184     {
185         getLifecycleManager().applyPhase(object, NotInLifecyclePhase.PHASE_NAME, phase);
186         return object;
187     }
188 
189 
190 
191     Object applyProcessors(Object object, Object metadata)
192     {
193         Object theObject = object;
194 
195         if(!hasFlag(metadata, MuleRegistry.INJECT_PROCESSORS_BYPASS_FLAG))
196         {
197             //Process injectors first
198             Collection<InjectProcessor> injectProcessors = lookupObjects(InjectProcessor.class);
199             for (InjectProcessor processor : injectProcessors)
200             {
201                 theObject = processor.process(theObject);
202             }
203         }
204 
205         if(!hasFlag(metadata, MuleRegistry.PRE_INIT_PROCESSORS_BYPASS_FLAG))
206         {
207             //Then any other processors
208             Collection<PreInitProcessor> processors = lookupObjects(PreInitProcessor.class);
209             for (PreInitProcessor processor : processors)
210             {
211                 theObject = processor.process(theObject);
212                 if(theObject==null)
213                 {
214                     return null;
215                 }
216             }
217         }
218         return theObject;
219     }
220 
221     /**
222      * Allows for arbitary registration of transient objects
223      *
224      * @param key
225      * @param value
226      */
227     public void registerObject(String key, Object value) throws RegistrationException
228     {
229         registerObject(key, value, Object.class);
230     }
231 
232     /**
233      * Allows for arbitrary registration of transient objects
234      *
235      * @param key
236      */
237     public void registerObject(String key, Object object, Object metadata) throws RegistrationException
238     {
239         checkDisposed();
240         if (StringUtils.isBlank(key))
241         {
242             throw new RegistrationException(MessageFactory.createStaticMessage("Attempt to register object with no key"));
243         }
244 
245         if (logger.isDebugEnabled())
246         {
247             logger.debug(String.format("registering key/object %s/%s", key, object));
248         }
249         
250         logger.debug("applying processors");
251         object = applyProcessors(object, metadata);
252         //Don't add the object if the processor returns null
253         if (object==null)
254         {
255             return;
256         }
257 
258         synchronized(registry)
259         {
260             if (registry.containsKey(key))
261             {
262                 // registry.put(key, value) would overwrite a previous entity with the same name.  Is this really what we want?
263                 // Not sure whether to throw an exception or log a warning here.
264                 //throw new RegistrationException("TransientRegistry already contains an object named '" + key + "'.  The previous object would be overwritten.");
265                 logger.warn("TransientRegistry already contains an object named '" + key + "'.  The previous object will be overwritten.");
266             }
267             registry.put(key, object);
268         }
269 
270         try
271         {
272             if (!hasFlag(metadata, MuleRegistry.LIFECYCLE_BYPASS_FLAG))
273             {
274                 if(logger.isDebugEnabled())
275                 {
276                     logger.debug("applying lifecycle to object: " + object);
277                 }
278                 getLifecycleManager().applyCompletedPhases(object);
279             }
280         }
281         catch (MuleException e)
282         {
283             throw new RegistrationException(e);
284         }
285     }
286 
287 
288     protected void checkDisposed() throws RegistrationException
289     {
290         if(getLifecycleManager().isPhaseComplete(Disposable.PHASE_NAME))
291         {
292             throw new RegistrationException(MessageFactory.createStaticMessage("Cannot register objects on the registry as the context is disposed"));
293         }
294     }
295 
296     protected boolean hasFlag(Object metaData, int flag)
297     {
298         return !(metaData == null || !(metaData instanceof Integer)) && ((Integer) metaData & flag) != 0;
299     }
300 
301     /**
302      * Will remove an object by name from the registry. By default the registry will apply all remaining lifecycle phases
303      * to the object when it is removed.
304      *
305      * @param key the name or key of the object to remove from the registry
306      * @param metadata Meta data flags supported are {@link org.mule.api.registry.MuleRegistry#LIFECYCLE_BYPASS_FLAG}
307      * @throws RegistrationException if there is a problem unregistering the object. Typically this will be because
308      * the object's lifecycle threw an exception
309      */
310     public void unregisterObject(String key, Object metadata) throws RegistrationException
311     {
312         Object obj;
313         synchronized (registry)
314         {
315             obj = registry.remove(key);
316         }
317 
318         try
319         {
320             if(!hasFlag(metadata, MuleRegistry.LIFECYCLE_BYPASS_FLAG))
321             {
322                 getLifecycleManager().applyPhase(obj, lifecycleManager.getCurrentPhase(), Disposable.PHASE_NAME);
323             }
324         }
325         catch (MuleException e)
326         {
327             throw new RegistrationException(e);
328         }
329 
330     }
331 
332     public void unregisterObject(String key) throws RegistrationException
333     {
334         unregisterObject(key, Object.class);
335     }
336 
337     // /////////////////////////////////////////////////////////////////////////
338     // Registry Metadata
339     // /////////////////////////////////////////////////////////////////////////
340 
341     public boolean isReadOnly()
342     {
343         return false;
344     }
345 
346     public boolean isRemote()
347     {
348         return false;
349     }
350 
351 }