View Javadoc

1   /*
2    * $Id: MuleRegistryHelper.java 22048 2011-05-31 14:39:03Z 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.NameableObject;
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  import java.util.concurrent.ConcurrentHashMap;
57  
58  import org.apache.commons.logging.Log;
59  import org.apache.commons.logging.LogFactory;
60  
61  /**
62   * Adds lookup/register/unregister methods for Mule-specific entities to the standard
63   * Registry interface.
64   */
65  public class MuleRegistryHelper implements MuleRegistry
66  {
67      protected transient Log logger = LogFactory.getLog(MuleRegistryHelper.class);
68  
69      /**
70       * A reference to Mule's internal registry
71       */
72      private DefaultRegistryBroker registry;
73  
74      /**
75       * We cache transformer searches so that we only search once
76       */
77      protected ConcurrentHashMap/*<String, Transformer>*/ exactTransformerCache = new ConcurrentHashMap/*<String, Transformer>*/(8);
78      protected ConcurrentHashMap/*Map<String, List<Transformer>>*/ transformerListCache = new ConcurrentHashMap/*<String, List<Transformer>>*/(8);
79  
80      private MuleContext muleContext;
81  
82      public MuleRegistryHelper(DefaultRegistryBroker registry, MuleContext muleContext)
83      {
84          this.registry = registry;
85          this.muleContext = muleContext;
86      }
87  
88      /**
89       * {@inheritDoc}
90       */
91      public void initialise() throws InitialisationException
92      {
93          //no-op
94  
95          //This is called when the MuleContext starts up, and should only do initialisation for any state on this class, the lifecycle
96          //for the registries will be handled by the LifecycleManager on the registry that this class wraps
97      }
98  
99      /**
100      * {@inheritDoc}
101      */
102     public void dispose()
103     {
104         transformerListCache.clear();
105         exactTransformerCache.clear();
106     }
107 
108     public void fireLifecycle(String phase) throws LifecycleException
109     {
110         if(Initialisable.PHASE_NAME.equals(phase))
111         {
112             registry.initialise();
113         }
114         else if(Disposable.PHASE_NAME.equals(phase))
115         {
116             registry.dispose();
117         }
118         else
119         {
120             registry.fireLifecycle(phase);
121         }
122     }
123 
124     /**
125      * {@inheritDoc}
126      */
127     public Connector lookupConnector(String name)
128     {
129         return (Connector) registry.lookupObject(name);
130     }
131 
132     /**
133      * Removed this method from {@link Registry} API as it should only be used
134      * internally and may confuse users. The {@link EndpointFactory} should be used
135      * for creating endpoints.<br/><br/> Looks up an returns endpoints registered in the
136      * registry by their identifier (currently endpoint name)<br/><br/ <b>NOTE:
137      * This method does not create new endpoint instances, but rather returns
138      * existing endpoint instances that have been registered. This lookup method
139      * should be avoided and the intelligent, role specific endpoint lookup methods
140      * should be used instead.<br/><br/>
141      *
142      * @param name the idendtifer/name used to register endpoint in registry
143      * @return foo
144      */
145     /*public ImmutableEndpoint lookupEndpoint(String name)
146     {
147         Object obj = registry.lookupObject(name);
148         if (obj instanceof ImmutableEndpoint)
149         {
150             return (ImmutableEndpoint) obj;
151         }
152         else
153         {
154             logger.debug("No endpoint with the name: "
155                     + name
156                     + "found.  If "
157                     + name
158                     + " is a global endpoint you should use the EndpointFactory to create endpoint instances from global endpoints.");
159             return null;
160         }
161     }*/
162 
163     /**
164      * {@inheritDoc}
165      */
166     public EndpointBuilder lookupEndpointBuilder(String name)
167     {
168         Object o = registry.lookupObject(name);
169         if (o instanceof EndpointBuilder)
170         {
171             logger.debug("Global endpoint EndpointBuilder for name: " + name + " found");
172             return (EndpointBuilder) o;
173         }
174         else
175         {
176             logger.debug("No endpoint builder with the name: " + name + " found.");
177             return null;
178         }
179     }
180 
181     /**
182      * {@inheritDoc}
183      */
184     public EndpointFactory lookupEndpointFactory()
185     {
186         return (EndpointFactory) registry.lookupObject(MuleProperties.OBJECT_MULE_ENDPOINT_FACTORY);
187     }
188 
189     /**
190      * {@inheritDoc}
191      */
192     public Transformer lookupTransformer(String name)
193     {
194         return (Transformer) registry.lookupObject(name);
195     }
196 
197     /**
198      * {@inheritDoc}
199      *
200      * @deprecated use {@link #lookupTransformer(org.mule.api.transformer.DataType, org.mule.api.transformer.DataType)} instead.  This
201      * method should only be used internally to discover transformers, typically a user does not need ot do this
202      * directly
203      */
204     @Deprecated
205     public Transformer lookupTransformer(Class inputType, Class outputType) throws TransformerException
206     {
207         return lookupTransformer(new SimpleDataType(inputType), new SimpleDataType(outputType));
208     }
209 
210     /**
211      * {@inheritDoc}
212      *
213      * @deprecated use {@link #lookupTransformer(org.mule.api.transformer.DataType, org.mule.api.transformer.DataType)} instead.  This
214      * method should only be used internally to discover transformers, typically a user does not need ot do this
215      * directly
216      */
217     @Deprecated
218     public List<Transformer> lookupTransformers(Class input, Class output)
219     {
220         return lookupTransformers(new SimpleDataType(input), new SimpleDataType(output));
221     }
222 
223     /**
224      * {@inheritDoc}
225      */
226     public Transformer lookupTransformer(DataType source, DataType result) throws TransformerException
227     {
228         final String dataTypePairHash = getDataTypeSourceResultPairHash(source, result);
229         Transformer cachedTransformer = (Transformer) exactTransformerCache.get(dataTypePairHash);
230         if (cachedTransformer != null)
231         {
232             return cachedTransformer;
233         }
234 
235         Transformer trans = resolveTransformer(source, result);
236 
237         if (trans != null)
238         {
239             Transformer concurrentlyAddedTransformer = (Transformer) exactTransformerCache.putIfAbsent(
240                 dataTypePairHash, trans);
241             if (concurrentlyAddedTransformer != null)
242             {
243                 return concurrentlyAddedTransformer;
244             }
245             else
246             {
247                 return trans;
248             }
249         }
250         else
251         {
252             throw new TransformerException(CoreMessages.noTransformerFoundForMessage(source, result));
253         }
254     }
255 
256     protected Transformer resolveTransformer(DataType source, DataType result) throws TransformerException
257     {
258         List<TransformerResolver> resolvers = (List<TransformerResolver>) lookupObjects(TransformerResolver.class);
259         Collections.sort(resolvers, new TransformerResolverComparator());
260 
261         for (TransformerResolver resolver : resolvers)
262         {
263             try
264             {
265                 Transformer trans = resolver.resolve(source, result);
266                 if (trans != null)
267                 {
268                     return trans;
269                 }
270             }
271             catch (ResolverException e)
272             {
273                 throw new TransformerException(CoreMessages.noTransformerFoundForMessage(source, result), e);
274             }
275         }
276         return null;
277     }
278 
279     /**
280      * {@inheritDoc}
281      */
282     public List<Transformer> lookupTransformers(DataType source, DataType result)
283     {
284         final String dataTypePairHash = getDataTypeSourceResultPairHash(source, result);
285 
286         List<Transformer> results = (List<Transformer>) transformerListCache.get(dataTypePairHash);
287         if (results != null)
288         {
289             return results;
290         }
291 
292         results = new ArrayList<Transformer>(2);
293         Collection<Transformer> transformers = registry.lookupObjects(Transformer.class);
294         for (Transformer t : transformers)
295         {
296             // The transformer must have the DiscoveryTransformer interface if we are
297             // going to
298             // find it here
299             if (!(t instanceof DiscoverableTransformer))
300             {
301                 continue;
302             }
303             DataType dt = t.getReturnDataType();
304             if (result.isCompatibleWith(dt) && t.isSourceDataTypeSupported(source))
305             {
306                 results.add(t);
307             }
308         }
309 
310         List<Transformer> concurrentlyAddedTransformers = (List<Transformer>) transformerListCache.putIfAbsent(
311             dataTypePairHash, results);
312         if (concurrentlyAddedTransformers != null)
313         {
314             return concurrentlyAddedTransformers;
315         }
316         else
317         {
318             return results;
319         }
320     }
321 
322     /**
323      * {@inheritDoc}
324      */
325     public Model lookupModel(String name)
326     {
327         return (Model) registry.lookupObject(name);
328     }
329 
330     /**
331      * {@inheritDoc}
332      */
333     public Model lookupSystemModel()
334     {
335         return lookupModel(MuleProperties.OBJECT_SYSTEM_MODEL);
336     }
337 
338     /**
339      * {@inheritDoc}
340      */
341     public Collection<Model> getModels()
342     {
343         return registry.lookupObjects(Model.class);
344     }
345 
346     /**
347      * {@inheritDoc}
348      */
349     public Collection<Connector> getConnectors()
350     {
351         return registry.lookupObjects(Connector.class);
352     }
353 
354     /**
355      * {@inheritDoc}
356      */
357     public Collection<Agent> getAgents()
358     {
359         return registry.lookupObjects(Agent.class);
360     }
361 
362     /**
363      * {@inheritDoc}
364      */
365     public Collection<ImmutableEndpoint> getEndpoints()
366     {
367         return registry.lookupObjects(ImmutableEndpoint.class);
368     }
369 
370     /**
371      * {@inheritDoc}
372      */
373     public Collection<Transformer> getTransformers()
374     {
375         return registry.lookupObjects(Transformer.class);
376     }
377 
378     /**
379      * {@inheritDoc}
380      */
381     public Agent lookupAgent(String name)
382     {
383         return (Agent) registry.lookupObject(name);
384     }
385 
386     /**
387      * {@inheritDoc}
388      */
389     public Service lookupService(String name)
390     {
391         return (Service) registry.lookupObject(name);
392     }
393 
394     /**
395      * {@inheritDoc}
396      */
397     public Collection<Service> lookupServices()
398     {
399         return lookupObjects(Service.class);
400     }
401 
402     /**
403      * {@inheritDoc}
404      */
405     public Collection<Service> lookupServices(String model)
406     {
407         Collection<Service> services = lookupServices();
408         List<Service> modelServices = new ArrayList<Service>();
409         Iterator it = services.iterator();
410         Service service;
411         while (it.hasNext())
412         {
413             service = (Service) it.next();
414             if (model.equals(service.getModel().getName()))
415             {
416                 modelServices.add(service);
417             }
418         }
419         return modelServices;
420     }
421 
422     /**
423      * {@inheritDoc}
424      */
425     public FlowConstruct lookupFlowConstruct(String name)
426     {
427         return (FlowConstruct) registry.lookupObject(name);
428     }
429 
430     /**
431      * {@inheritDoc}
432      */
433     public Collection<FlowConstruct> lookupFlowConstructs()
434     {
435         return lookupObjects(FlowConstruct.class);
436     }
437 
438     /**
439      * {@inheritDoc}
440      */
441     public final void registerTransformer(Transformer transformer) throws MuleException
442     {
443         registry.registerObject(getName(transformer), transformer, Transformer.class);
444         notifyTransformerResolvers(transformer, TransformerResolver.RegistryAction.ADDED);
445     }
446 
447     protected void notifyTransformerResolvers(Transformer t, TransformerResolver.RegistryAction action)
448     {
449         if (t instanceof DiscoverableTransformer)
450         {
451             Collection<TransformerResolver> resolvers = lookupObjects(TransformerResolver.class);
452             for (TransformerResolver resolver : resolvers)
453             {
454                 resolver.transformerChange(t, action);
455             }
456             transformerListCache.clear();
457             exactTransformerCache.clear();
458         }
459     }
460 
461     /**
462      * Looks up the service descriptor from a singleton cache and creates a new one if not found.
463      */
464     public ServiceDescriptor lookupServiceDescriptor(ServiceType type, String name, Properties overrides) throws ServiceException
465     {
466         String key = new AbstractServiceDescriptor.Key(name, overrides).getKey();
467         // TODO If we want these descriptors loaded form Spring we need to change the key mechanism
468         // and the scope, and then deal with circular reference issues.
469         ServiceDescriptor sd = (ServiceDescriptor) registry.lookupObject(key);
470 
471         synchronized (this)
472         {
473             if (sd == null)
474             {
475                 sd = createServiceDescriptor(type, name, overrides);
476                 try
477                 {
478                     registry.registerObject(key, sd, ServiceDescriptor.class);
479                 }
480                 catch (RegistrationException e)
481                 {
482                     throw new ServiceException(e.getI18nMessage(), e);
483                 }
484             }
485         }
486         return sd;
487     }
488 
489     protected ServiceDescriptor createServiceDescriptor(ServiceType type, String name, Properties overrides) throws ServiceException
490     {
491         //Stripe off and use the meta-scheme if present
492         String scheme = name;
493         if (name.contains(":"))
494         {
495             scheme = name.substring(0, name.indexOf(":"));
496         }
497 
498         Properties props = SpiUtils.findServiceDescriptor(type, scheme);
499         if (props == null)
500         {
501             throw new ServiceException(CoreMessages.failedToLoad(type + " " + scheme));
502         }
503 
504         return ServiceDescriptorFactory.create(type, name, props, overrides, muleContext,
505                                                muleContext.getExecutionClassLoader());
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.NameableObject}, then
749      * {@link org.mule.api.NameableObject#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 NameableObject)
758         {
759             name = ((NameableObject) obj).getName();
760         }
761         else if (obj instanceof FlowConstruct)
762         {
763             name = ((FlowConstruct) obj).getName();
764         }
765         if (StringUtils.isBlank(name))
766         {
767             name = obj.getClass().getName() + ":" + UUID.getUUID();
768         }
769         return name;
770     }
771 
772     ////////////////////////////////////////////////////////////////////////////
773     // Registry Metadata
774     ////////////////////////////////////////////////////////////////////////////
775 
776     /**
777      * {@inheritDoc}
778      */
779     public String getRegistryId()
780     {
781         return this.toString();
782     }
783 
784     /**
785      * {@inheritDoc}
786      */
787     public boolean isReadOnly()
788     {
789         return false;
790     }
791 
792     /**
793      * {@inheritDoc}
794      */
795     public boolean isRemote()
796     {
797         return false;
798     }
799 
800     private String getDataTypeSourceResultPairHash(DataType<?> source, DataType<?> result)
801     {
802         return source.getClass().getName() + source.hashCode() + ":" + result.getClass().getName()
803                + result.hashCode();
804     }
805 
806     private class TransformerResolverComparator implements Comparator<TransformerResolver>
807     {
808         public int compare(TransformerResolver transformerResolver, TransformerResolver transformerResolver1)
809         {
810             if (transformerResolver.getClass().equals(TypeBasedTransformerResolver.class))
811             {
812                 return 1;
813             }
814 
815             if (transformerResolver1.getClass().equals(TypeBasedTransformerResolver.class))
816             {
817                 return -1;
818             }
819             return 0;
820         }
821     }
822 }
823 
824