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