View Javadoc

1   /*
2    * $Id: TransientRegistry.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.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("_muleLifecycleStateInjectorProcessor", new LifecycleStateInjectorProcessor(getLifecycleManager().getState()));
69              registry.put("_muleLifecycleManager", getLifecycleManager());
70          }
71      }
72  
73      @java.lang.Override
74      protected void doInitialise() throws InitialisationException
75      {
76          applyProcessors(lookupObjects(Connector.class), null);
77          applyProcessors(lookupObjects(Transformer.class), null);
78          applyProcessors(lookupObjects(ImmutableEndpoint.class), null);
79          applyProcessors(lookupObjects(Agent.class), null);
80          applyProcessors(lookupObjects(Model.class), null);
81          applyProcessors(lookupObjects(Service.class), null);
82          applyProcessors(lookupObjects(Object.class), null);
83      }
84  
85      @Override
86      protected void doDispose()
87      {
88          registry.clear();
89      }
90  
91      protected Map applyProcessors(Map<String, Object> objects)
92      {
93          if (objects == null)
94          {
95              return null;
96          }
97          Map<String, Object> results = new HashMap<String, Object>();
98          for (Map.Entry<String, Object> entry : objects.entrySet())
99          {
100             //We do this in the loop in case the map contains ObjectProcessors
101             Collection<ObjectProcessor> processors = lookupObjects(ObjectProcessor.class);
102             for (ObjectProcessor processor : processors)
103             {
104                 Object result = processor.process(entry.getValue());
105                 //If result is null do not add the object
106                 if(result != null)
107                 {
108                     results.put(entry.getKey(), result);
109                 }
110             }
111         }
112         return results;
113     }
114 
115 
116     public void registerObjects(Map objects) throws RegistrationException
117     {
118         if (objects == null)
119         {
120             return;
121         }
122 
123         for (Iterator iterator = objects.entrySet().iterator(); iterator.hasNext();)
124         {
125             Map.Entry entry = (Map.Entry) iterator.next();
126             registerObject(entry.getKey().toString(), entry.getValue());
127         }
128     }
129 
130     @SuppressWarnings("unchecked")
131     public <T> Map<String, T> lookupByType(Class<T> type)
132     {
133         synchronized(registry)
134         {
135             final Map<String, T> results = new HashMap<String, T>();
136             for (Map.Entry<String, Object> entry : registry.entrySet())
137             {
138                 final Class clazz = entry.getValue().getClass();
139                 if (type.isAssignableFrom(clazz))
140                 {
141                     results.put(entry.getKey(), (T) entry.getValue());
142                 }
143             }
144 
145             return results;
146         }
147     }
148 
149     @SuppressWarnings("unchecked")
150     public <T> T  lookupObject(String key)
151     {
152         synchronized(registry)
153         {
154             return (T) registry.get(key);
155         }
156     }
157 
158     @SuppressWarnings("unchecked")
159     public <T> Collection<T> lookupObjects(Class<T> returntype)
160     {
161         synchronized(registry)
162         {
163             return CollectionUtils.select(registry.values(), new InstanceofPredicate(returntype));
164         }
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         getLifecycleManager().applyCompletedPhases(object);
179         return object;
180     }
181 
182     Object applyLifecycle(Object object, String phase) throws MuleException
183     {
184         getLifecycleManager().applyPhase(object, NotInLifecyclePhase.PHASE_NAME, phase);
185         return object;
186     }
187 
188 
189 
190     Object applyProcessors(Object object, Object metadata)
191     {
192         Object theObject = object;
193 
194         if(!hasFlag(metadata, MuleRegistry.INJECT_PROCESSORS_BYPASS_FLAG))
195         {
196             //Process injectors first
197             Collection<InjectProcessor> injectProcessors = lookupObjects(InjectProcessor.class);
198             for (InjectProcessor processor : injectProcessors)
199             {
200                 theObject = processor.process(theObject);
201             }
202         }
203 
204         if(!hasFlag(metadata, MuleRegistry.PRE_INIT_PROCESSORS_BYPASS_FLAG))
205         {
206             //Then any other processors
207             Collection<PreInitProcessor> processors = lookupObjects(PreInitProcessor.class);
208             for (PreInitProcessor processor : processors)
209             {
210                 theObject = processor.process(theObject);
211                 if(theObject==null)
212                 {
213                     return null;
214                 }
215             }
216         }
217         return theObject;
218     }
219 
220     /**
221      * Allows for arbitary registration of transient objects
222      *
223      * @param key
224      * @param value
225      */
226     public void registerObject(String key, Object value) throws RegistrationException
227     {
228         registerObject(key, value, Object.class);
229     }
230 
231     /**
232      * Allows for arbitrary registration of transient objects
233      *
234      * @param key
235      */
236     public void registerObject(String key, Object object, Object metadata) throws RegistrationException
237     {
238         checkDisposed();
239         if (StringUtils.isBlank(key))
240         {
241             throw new RegistrationException(MessageFactory.createStaticMessage("Attempt to register object with no key"));
242         }
243 
244         if (logger.isDebugEnabled())
245         {
246             logger.debug(String.format("registering key/object %s/%s", key, object));
247         }
248         
249         logger.debug("applying processors");
250         object = applyProcessors(object, metadata);
251         //Don't add the object if the processor returns null
252         if (object==null)
253         {
254             return;
255         }
256 
257         synchronized(registry)
258         {
259             if (registry.containsKey(key))
260             {
261                 // registry.put(key, value) would overwrite a previous entity with the same name.  Is this really what we want?
262                 // Not sure whether to throw an exception or log a warning here.
263                 //throw new RegistrationException("TransientRegistry already contains an object named '" + key + "'.  The previous object would be overwritten.");
264                 logger.warn("TransientRegistry already contains an object named '" + key + "'.  The previous object will be overwritten.");
265             }
266             registry.put(key, object);
267         }
268 
269         try
270         {
271             if (!hasFlag(metadata, MuleRegistry.LIFECYCLE_BYPASS_FLAG))
272             {
273                 if(logger.isDebugEnabled())
274                 {
275                     logger.debug("applying lifecycle to object: " + object);
276                 }
277                 getLifecycleManager().applyCompletedPhases(object);
278             }
279         }
280         catch (MuleException e)
281         {
282             throw new RegistrationException(e);
283         }
284     }
285 
286 
287     protected void checkDisposed() throws RegistrationException
288     {
289         if(getLifecycleManager().isPhaseComplete(Disposable.PHASE_NAME))
290         {
291             throw new RegistrationException(MessageFactory.createStaticMessage("Cannot register objects on the registry as the context is disposed"));
292         }
293     }
294 
295     protected boolean hasFlag(Object metaData, int flag)
296     {
297         return !(metaData == null || !(metaData instanceof Integer)) && ((Integer) metaData & flag) != 0;
298     }
299 
300     /**
301      * Will remove an object by name from the registry. By default the registry will apply all remaining lifecycle phases
302      * to the object when it is removed.
303      *
304      * @param key the name or key of the object to remove from the registry
305      * @param metadata Meta data flags supported are {@link org.mule.api.registry.MuleRegistry.LIFECYCLE_BYPASS_FLAG}
306      * @throws RegistrationException if there is a problem unregistering the object. Typically this will be because
307      * the object's lifecycle threw an exception
308      */
309     public void unregisterObject(String key, Object metadata) throws RegistrationException
310     {
311         Object obj;
312         synchronized (registry)
313         {
314             obj = registry.remove(key);
315         }
316 
317         try
318         {
319             if(!hasFlag(metadata, MuleRegistry.LIFECYCLE_BYPASS_FLAG))
320             {
321                 getLifecycleManager().applyPhase(obj, lifecycleManager.getCurrentPhase(), Disposable.PHASE_NAME);
322             }
323         }
324         catch (MuleException e)
325         {
326             throw new RegistrationException(e);
327         }
328 
329     }
330 
331     public void unregisterObject(String key) throws RegistrationException
332     {
333         unregisterObject(key, Object.class);
334     }
335 
336     // /////////////////////////////////////////////////////////////////////////
337     // Registry Metadata
338     // /////////////////////////////////////////////////////////////////////////
339 
340     public boolean isReadOnly()
341     {
342         return false;
343     }
344 
345     public boolean isRemote()
346     {
347         return false;
348     }
349 
350 }