View Javadoc

1   /*
2    * $Id: MuleRegistryHelper.java 20637 2010-12-11 02:32:12Z 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  
11  package org.mule.registry;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.MuleException;
15  import org.mule.api.NamedObject;
16  import org.mule.api.agent.Agent;
17  import org.mule.api.config.MuleProperties;
18  import org.mule.api.construct.FlowConstruct;
19  import org.mule.api.endpoint.EndpointBuilder;
20  import org.mule.api.endpoint.EndpointFactory;
21  import org.mule.api.endpoint.ImmutableEndpoint;
22  import org.mule.api.lifecycle.Disposable;
23  import org.mule.api.lifecycle.Initialisable;
24  import org.mule.api.lifecycle.InitialisationException;
25  import org.mule.api.lifecycle.LifecycleException;
26  import org.mule.api.model.Model;
27  import org.mule.api.registry.AbstractServiceDescriptor;
28  import org.mule.api.registry.MuleRegistry;
29  import org.mule.api.registry.RegistrationException;
30  import org.mule.api.registry.ResolverException;
31  import org.mule.api.registry.ServiceDescriptor;
32  import org.mule.api.registry.ServiceDescriptorFactory;
33  import org.mule.api.registry.ServiceException;
34  import org.mule.api.registry.ServiceType;
35  import org.mule.api.registry.TransformerResolver;
36  import org.mule.api.service.Service;
37  import org.mule.api.transformer.DataType;
38  import org.mule.api.transformer.DiscoverableTransformer;
39  import org.mule.api.transformer.Transformer;
40  import org.mule.api.transformer.TransformerException;
41  import org.mule.api.transport.Connector;
42  import org.mule.config.i18n.CoreMessages;
43  import org.mule.transformer.types.SimpleDataType;
44  import org.mule.util.SpiUtils;
45  import org.mule.util.StringUtils;
46  import org.mule.util.UUID;
47  
48  import java.util.ArrayList;
49  import java.util.Collection;
50  import java.util.Collections;
51  import java.util.Comparator;
52  import java.util.Iterator;
53  import java.util.List;
54  import java.util.Map;
55  import java.util.Properties;
56  
57  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
58  
59  import org.apache.commons.logging.Log;
60  import org.apache.commons.logging.LogFactory;
61  
62  /**
63   * Adds lookup/register/unregister methods for Mule-specific entities to the standard
64   * Registry interface.
65   */
66  public class MuleRegistryHelper implements MuleRegistry
67  {
68      protected transient Log logger = LogFactory.getLog(MuleRegistryHelper.class);
69  
70      /**
71       * A reference to Mule's internal registry
72       */
73      private DefaultRegistryBroker registry;
74  
75      /**
76       * We cache transformer searches so that we only search once
77       */
78      protected ConcurrentHashMap/*<String, Transformer>*/ exactTransformerCache = new ConcurrentHashMap/*<String, Transformer>*/(8);
79      protected ConcurrentHashMap/*Map<String, List<Transformer>>*/ transformerListCache = new ConcurrentHashMap/*<String, List<Transformer>>*/(8);
80  
81      private MuleContext muleContext;
82  
83      public MuleRegistryHelper(DefaultRegistryBroker registry, MuleContext muleContext)
84      {
85          this.registry = registry;
86          this.muleContext = muleContext;
87      }
88  
89      /**
90       * {@inheritDoc}
91       */
92      public void initialise() throws InitialisationException
93      {
94          //no-op
95  
96          //This is called when the MuleContext starts up, and should only do initialisation for any state on this class, the lifecycle
97          //for the registries will be handled by the LifecycleManager on the registry that this class wraps
98      }
99  
100     /**
101      * {@inheritDoc}
102      */
103     public void dispose()
104     {
105         transformerListCache.clear();
106         exactTransformerCache.clear();
107     }
108 
109     public void fireLifecycle(String phase) throws LifecycleException
110     {
111         if(Initialisable.PHASE_NAME.equals(phase))
112         {
113             registry.initialise();
114         }
115         else if(Disposable.PHASE_NAME.equals(phase))
116         {
117             registry.dispose();
118         }
119         else
120         {
121             registry.fireLifecycle(phase);
122         }
123     }
124 
125     /**
126      * {@inheritDoc}
127      */
128     public Connector lookupConnector(String name)
129     {
130         return (Connector) registry.lookupObject(name);
131     }
132 
133     /**
134      * Removed this method from {@link Registry} API as it should only be used
135      * internally and may confuse users. The {@link EndpointFactory} should be used
136      * for creating endpoints.<br/><br/> Looks up an returns endpoints registered in the
137      * registry by their identifier (currently endpoint name)<br/><br/ <b>NOTE:
138      * This method does not create new endpoint instances, but rather returns
139      * existing endpoint instances that have been registered. This lookup method
140      * should be avoided and the intelligent, role specific endpoint lookup methods
141      * should be used instead.<br/><br/>
142      *
143      * @param name the idendtifer/name used to register endpoint in registry
144      * @return foo
145      */
146     /*public ImmutableEndpoint lookupEndpoint(String name)
147     {
148         Object obj = registry.lookupObject(name);
149         if (obj instanceof ImmutableEndpoint)
150         {
151             return (ImmutableEndpoint) obj;
152         }
153         else
154         {
155             logger.debug("No endpoint with the name: "
156                     + name
157                     + "found.  If "
158                     + name
159                     + " is a global endpoint you should use the EndpointFactory to create endpoint instances from global endpoints.");
160             return null;
161         }
162     }*/
163 
164     /**
165      * {@inheritDoc}
166      */
167     public EndpointBuilder lookupEndpointBuilder(String name)
168     {
169         Object o = registry.lookupObject(name);
170         if (o instanceof EndpointBuilder)
171         {
172             logger.debug("Global endpoint EndpointBuilder for name: " + name + " found");
173             return (EndpointBuilder) o;
174         }
175         else
176         {
177             logger.debug("No endpoint builder with the name: " + name + " found.");
178             return null;
179         }
180     }
181 
182     /**
183      * {@inheritDoc}
184      */
185     public EndpointFactory lookupEndpointFactory()
186     {
187         return (EndpointFactory) registry.lookupObject(MuleProperties.OBJECT_MULE_ENDPOINT_FACTORY);
188     }
189 
190     /**
191      * {@inheritDoc}
192      */
193     public Transformer lookupTransformer(String name)
194     {
195         return (Transformer) registry.lookupObject(name);
196     }
197 
198     /**
199      * {@inheritDoc}
200      *
201      * @deprecated use {@link #lookupTransformer(org.mule.api.transformer.DataType, org.mule.api.transformer.DataType)} instead.  This
202      * method should only be used internally to discover transformers, typically a user does not need ot do this
203      * directly
204      */
205     @Deprecated
206     public Transformer lookupTransformer(Class inputType, Class outputType) throws TransformerException
207     {
208         return lookupTransformer(new SimpleDataType(inputType), new SimpleDataType(outputType));
209     }
210 
211     /**
212      * {@inheritDoc}
213      *
214      * @deprecated use {@link #lookupTransformer(org.mule.api.transformer.DataType, org.mule.api.transformer.DataType)} instead.  This
215      * method should only be used internally to discover transformers, typically a user does not need ot do this
216      * directly
217      */
218     @Deprecated
219     public List<Transformer> lookupTransformers(Class input, Class output)
220     {
221         return lookupTransformers(new SimpleDataType(input), new SimpleDataType(output));
222     }
223 
224     /**
225      * {@inheritDoc}
226      */
227     public Transformer lookupTransformer(DataType source, DataType result) throws TransformerException
228     {
229         final String dataTypePairHash = getDataTypeSourceResultPairHash(source, result);
230         Transformer cachedTransformer = (Transformer) exactTransformerCache.get(dataTypePairHash);
231         if (cachedTransformer != null)
232         {
233             return cachedTransformer;
234         }
235 
236         Transformer trans = resolveTransformer(source, result);
237 
238         if (trans != null)
239         {
240             Transformer concurrentlyAddedTransformer = (Transformer) exactTransformerCache.putIfAbsent(
241                 dataTypePairHash, trans);
242             if (concurrentlyAddedTransformer != null)
243             {
244                 return concurrentlyAddedTransformer;
245             }
246             else
247             {
248                 return trans;
249             }
250         }
251         else
252         {
253             throw new TransformerException(CoreMessages.noTransformerFoundForMessage(source, result));
254         }
255     }
256 
257     protected Transformer resolveTransformer(DataType source, DataType result) throws TransformerException
258     {
259         List<TransformerResolver> resolvers = (List<TransformerResolver>) lookupObjects(TransformerResolver.class);
260         Collections.sort(resolvers, new TransformerResolverComparator());
261 
262         for (TransformerResolver resolver : resolvers)
263         {
264             try
265             {
266                 Transformer trans = resolver.resolve(source, result);
267                 if (trans != null)
268                 {
269                     return trans;
270                 }
271             }
272             catch (ResolverException e)
273             {
274                 throw new TransformerException(CoreMessages.noTransformerFoundForMessage(source, result), e);
275             }
276         }
277         return null;
278     }
279 
280     /**
281      * {@inheritDoc}
282      */
283     public List<Transformer> lookupTransformers(DataType source, DataType result)
284     {
285         final String dataTypePairHash = getDataTypeSourceResultPairHash(source, result);
286 
287         List<Transformer> results = (List<Transformer>) transformerListCache.get(dataTypePairHash);
288         if (results != null)
289         {
290             return results;
291         }
292 
293         results = new ArrayList<Transformer>(2);
294         Collection<Transformer> transformers = getTransformers();
295         for (Transformer t : transformers)
296         {
297             // The transformer must have the DiscoveryTransformer interface if we are
298             // going to
299             // find it here
300             if (!(t instanceof DiscoverableTransformer))
301             {
302                 continue;
303             }
304             DataType dt = t.getReturnDataType();
305             if (result.isCompatibleWith(dt) && t.isSourceDataTypeSupported(source))
306             {
307                 results.add(t);
308             }
309         }
310 
311         List<Transformer> concurrentlyAddedTransformers = (List<Transformer>) transformerListCache.putIfAbsent(
312             dataTypePairHash, results);
313         if (concurrentlyAddedTransformers != null)
314         {
315             return concurrentlyAddedTransformers;
316         }
317         else
318         {
319             return results;
320         }
321     }
322 
323     /**
324      * {@inheritDoc}
325      */
326     public Model lookupModel(String name)
327     {
328         return (Model) registry.lookupObject(name);
329     }
330 
331     /**
332      * {@inheritDoc}
333      */
334     public Model lookupSystemModel()
335     {
336         return lookupModel(MuleProperties.OBJECT_SYSTEM_MODEL);
337     }
338 
339     /**
340      * {@inheritDoc}
341      */
342     public Collection<Model> getModels()
343     {
344         return registry.lookupObjects(Model.class);
345     }
346 
347     /**
348      * {@inheritDoc}
349      */
350     public Collection<Connector> getConnectors()
351     {
352         return registry.lookupObjects(Connector.class);
353     }
354 
355     /**
356      * {@inheritDoc}
357      */
358     public Collection<Agent> getAgents()
359     {
360         return registry.lookupObjects(Agent.class);
361     }
362 
363     /**
364      * {@inheritDoc}
365      */
366     public Collection<ImmutableEndpoint> getEndpoints()
367     {
368         return registry.lookupObjects(ImmutableEndpoint.class);
369     }
370 
371     /**
372      * {@inheritDoc}
373      */
374     public Collection<Transformer> getTransformers()
375     {
376         return registry.lookupObjects(Transformer.class);
377     }
378 
379     /**
380      * {@inheritDoc}
381      */
382     public Agent lookupAgent(String name)
383     {
384         return (Agent) registry.lookupObject(name);
385     }
386 
387     /**
388      * {@inheritDoc}
389      */
390     public Service lookupService(String name)
391     {
392         return (Service) registry.lookupObject(name);
393     }
394 
395     /**
396      * {@inheritDoc}
397      */
398     public Collection<Service> lookupServices()
399     {
400         return lookupObjects(Service.class);
401     }
402 
403     /**
404      * {@inheritDoc}
405      */
406     public Collection<Service> lookupServices(String model)
407     {
408         Collection<Service> services = lookupServices();
409         List<Service> modelServices = new ArrayList<Service>();
410         Iterator it = services.iterator();
411         Service service;
412         while (it.hasNext())
413         {
414             service = (Service) it.next();
415             if (model.equals(service.getModel().getName()))
416             {
417                 modelServices.add(service);
418             }
419         }
420         return modelServices;
421     }
422 
423     /**
424      * {@inheritDoc}
425      */
426     public FlowConstruct lookupFlowConstruct(String name)
427     {
428         return (FlowConstruct) registry.lookupObject(name);
429     }
430 
431     /**
432      * {@inheritDoc}
433      */
434     public Collection<FlowConstruct> lookupFlowConstructs()
435     {
436         return lookupObjects(FlowConstruct.class);
437     }
438 
439     /**
440      * {@inheritDoc}
441      */
442     public final void registerTransformer(Transformer transformer) throws MuleException
443     {
444         registry.registerObject(getName(transformer), transformer, Transformer.class);
445         notifyTransformerResolvers(transformer, TransformerResolver.RegistryAction.ADDED);
446     }
447 
448     protected void notifyTransformerResolvers(Transformer t, TransformerResolver.RegistryAction action)
449     {
450         if (t instanceof DiscoverableTransformer)
451         {
452             Collection<TransformerResolver> resolvers = lookupObjects(TransformerResolver.class);
453             for (TransformerResolver resolver : resolvers)
454             {
455                 resolver.transformerChange(t, action);
456             }
457             transformerListCache.clear();
458             exactTransformerCache.clear();
459         }
460     }
461 
462     /**
463      * Looks up the service descriptor from a singleton cache and creates a new one if not found.
464      */
465     public ServiceDescriptor lookupServiceDescriptor(ServiceType type, String name, Properties overrides) throws ServiceException
466     {
467         String key = new AbstractServiceDescriptor.Key(name, overrides).getKey();
468         // TODO If we want these descriptors loaded form Spring we need to change the key mechanism
469         // and the scope, and then deal with circular reference issues.
470         ServiceDescriptor sd = (ServiceDescriptor) registry.lookupObject(key);
471 
472         synchronized (this)
473         {
474             if (sd == null)
475             {
476                 sd = createServiceDescriptor(type, name, overrides);
477                 try
478                 {
479                     registry.registerObject(key, sd, ServiceDescriptor.class);
480                 }
481                 catch (RegistrationException e)
482                 {
483                     throw new ServiceException(e.getI18nMessage(), e);
484                 }
485             }
486         }
487         return sd;
488     }
489 
490     protected ServiceDescriptor createServiceDescriptor(ServiceType type, String name, Properties overrides) throws ServiceException
491     {
492         //Stripe off and use the meta-scheme if present
493         String scheme = name;
494         if (name.contains(":"))
495         {
496             scheme = name.substring(0, name.indexOf(":"));
497         }
498 
499         Properties props = SpiUtils.findServiceDescriptor(type, scheme);
500         if (props == null)
501         {
502             throw new ServiceException(CoreMessages.failedToLoad(type + " " + scheme));
503         }
504 
505         return ServiceDescriptorFactory.create(type, name, props, overrides, muleContext, null);
506     }
507 
508     /**
509      * {@inheritDoc}
510      */
511     public void registerAgent(Agent agent) throws MuleException
512     {
513         registry.registerObject(getName(agent), agent, Agent.class);
514     }
515 
516     /**
517      * {@inheritDoc}
518      */
519     public void registerConnector(Connector connector) throws MuleException
520     {
521         registry.registerObject(getName(connector), connector, Connector.class);
522     }
523 
524     /**
525      * {@inheritDoc}
526      */
527     public void registerEndpoint(ImmutableEndpoint endpoint) throws MuleException
528     {
529         registry.registerObject(getName(endpoint), endpoint, ImmutableEndpoint.class);
530     }
531 
532     /**
533      * {@inheritDoc}
534      */
535     public void registerEndpointBuilder(String name, EndpointBuilder builder) throws MuleException
536     {
537         registry.registerObject(name, builder, EndpointBuilder.class);
538     }
539 
540     /**
541      * {@inheritDoc}
542      */
543     public void registerModel(Model model) throws MuleException
544     {
545         registry.registerObject(getName(model), model, Model.class);
546     }
547 
548     /**
549      * {@inheritDoc}
550      */
551     public void registerService(Service service) throws MuleException
552     {
553         registry.registerObject(getName(service), service, Service.class);
554     }
555 
556     /**
557      * {@inheritDoc}
558      */
559     public void unregisterService(String serviceName) throws MuleException
560     {
561         registry.unregisterObject(serviceName, Service.class);
562     }
563 
564     /**
565      * {@inheritDoc}
566      */
567     public void registerFlowConstruct(FlowConstruct flowConstruct) throws MuleException
568     {
569         registry.registerObject(getName(flowConstruct), flowConstruct, FlowConstruct.class);
570     }
571 
572     /**
573      * {@inheritDoc}
574      */
575     public void unregisterFlowConstruct(String flowConstructName) throws MuleException
576     {
577         registry.unregisterObject(flowConstructName, FlowConstruct.class);
578     }
579 
580     /**
581      * {@inheritDoc}
582      */
583     public void unregisterAgent(String agentName) throws MuleException
584     {
585         registry.unregisterObject(agentName, Agent.class);
586     }
587 
588     /**
589      * {@inheritDoc}
590      */
591     public void unregisterConnector(String connectorName) throws MuleException
592     {
593         registry.unregisterObject(connectorName, Connector.class);
594     }
595 
596     /**
597      * {@inheritDoc}
598      */
599     public void unregisterEndpoint(String endpointName) throws MuleException
600     {
601         registry.unregisterObject(endpointName, ImmutableEndpoint.class);
602     }
603 
604     /**
605      * {@inheritDoc}
606      */
607     public void unregisterModel(String modelName) throws MuleException
608     {
609         registry.unregisterObject(modelName, Model.class);
610     }
611 
612     /**
613      * {@inheritDoc}
614      */
615     public void unregisterTransformer(String transformerName) throws MuleException
616     {
617         Transformer transformer = lookupTransformer(transformerName);
618         notifyTransformerResolvers(transformer, TransformerResolver.RegistryAction.REMOVED);
619         registry.unregisterObject(transformerName, Transformer.class);
620 
621     }
622 
623     /**
624      * {@inheritDoc}
625      */
626     public Object applyProcessorsAndLifecycle(Object object) throws MuleException
627     {
628         object = applyProcessors(object);
629         object = applyLifecycle(object);
630         return object;
631     }
632 
633     /**
634      * {@inheritDoc}
635      */
636     public Object applyProcessors(Object object) throws MuleException
637     {
638         return registry.getTransientRegistry().applyProcessors(object, null);
639     }
640 
641     /**
642      * {@inheritDoc}
643      */
644     public Object applyProcessors(Object object, int flags) throws MuleException
645     {
646         return registry.getTransientRegistry().applyProcessors(object, flags);
647     }
648 
649     /**
650      * {@inheritDoc}
651      */
652     public Object applyLifecycle(Object object) throws MuleException
653     {
654         return registry.getTransientRegistry().applyLifecycle(object);
655     }
656 
657     public Object applyLifecycle(Object object, String phase) throws MuleException
658     {
659         return registry.getTransientRegistry().applyLifecycle(object, phase);        
660     }
661 
662     ////////////////////////////////////////////////////////////////////////////
663     // Delegate to internal registry
664     ////////////////////////////////////////////////////////////////////////////
665 
666     /**
667      * {@inheritDoc}
668      */
669     public <T> T lookupObject(Class<T> type) throws RegistrationException
670     {
671         return registry.lookupObject(type);
672     }
673 
674     @SuppressWarnings("unchecked")
675     public <T> T lookupObject(String key)
676     {
677         return (T) registry.lookupObject(key);
678     }
679 
680     /**
681      * {@inheritDoc}
682      */
683     public <T> Collection<T> lookupObjects(Class<T> type)
684     {
685         return registry.lookupObjects(type);
686     }
687 
688     /**
689      * {@inheritDoc}
690      */
691     public <T> Collection<T> lookupObjectsForLifecycle(Class<T> type)
692     {
693         return registry.lookupObjectsForLifecycle(type);
694     }
695     
696     @SuppressWarnings("unchecked")
697     public <T> T get(String key)
698     {
699         return (T)registry.get(key);
700     }
701 
702     public <T> Map<String, T> lookupByType(Class<T> type)
703     {
704         return registry.lookupByType(type);
705     }
706 
707     /**
708      * {@inheritDoc}
709      */
710     public void registerObject(String key, Object value, Object metadata) throws RegistrationException
711     {
712         registry.registerObject(key, value, metadata);
713     }
714 
715     /**
716      * {@inheritDoc}
717      */
718     public void registerObject(String key, Object value) throws RegistrationException
719     {
720         registry.registerObject(key, value);
721     }
722 
723     /**
724      * {@inheritDoc}
725      */
726     public void registerObjects(Map objects) throws RegistrationException
727     {
728         registry.registerObjects(objects);
729     }
730 
731     /**
732      * {@inheritDoc}
733      */
734     public void unregisterObject(String key, Object metadata) throws RegistrationException
735     {
736         registry.unregisterObject(key, metadata);
737     }
738 
739     /**
740      * {@inheritDoc}
741      */
742     public void unregisterObject(String key) throws RegistrationException
743     {
744         registry.unregisterObject(key);
745     }
746 
747     /**
748      * Returns the name for the object passed in.  If the object implements {@link org.mule.api.NamedObject}, then
749      * {@link org.mule.api.NamedObject#getName()} will be returned, otherwise a name is generated using the class name
750      * and a generated UUID.
751      * @param obj the object to inspect
752      * @return the name for this object
753      */
754     protected String getName(Object obj)
755     {
756         String name = null;
757         if (obj instanceof NamedObject)
758         {
759             name = ((NamedObject) obj).getName();
760         }
761         if (StringUtils.isBlank(name))
762         {
763             name = obj.getClass().getName() + ":" + UUID.getUUID();
764         }
765         return name;
766     }
767 
768     ////////////////////////////////////////////////////////////////////////////
769     // Registry Metadata
770     ////////////////////////////////////////////////////////////////////////////
771 
772     /**
773      * {@inheritDoc}
774      */
775     public String getRegistryId()
776     {
777         return this.toString();
778     }
779 
780     /**
781      * {@inheritDoc}
782      */
783     public boolean isReadOnly()
784     {
785         return false;
786     }
787 
788     /**
789      * {@inheritDoc}
790      */
791     public boolean isRemote()
792     {
793         return false;
794     }
795     
796     private String getDataTypeSourceResultPairHash(DataType<?> source, DataType<?> result)
797     {
798         return source.getClass().getName() + source.hashCode() + ":" + result.getClass().getName()
799                + result.hashCode();
800     }
801 
802     private class TransformerResolverComparator implements Comparator<TransformerResolver>
803     {
804         public int compare(TransformerResolver transformerResolver, TransformerResolver transformerResolver1)
805         {
806             if (transformerResolver.getClass().equals(TypeBasedTransformerResolver.class))
807             {
808                 return 1;
809             }
810 
811             if (transformerResolver1.getClass().equals(TypeBasedTransformerResolver.class))
812             {
813                 return -1;
814             }
815             return 0;
816         }
817     }
818 }
819 
820