View Javadoc

1   /*
2    * $Id: TransportFactory.java 7976 2007-08-21 14:26:13Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.providers.service;
12  
13  import org.mule.MuleException;
14  import org.mule.MuleManager;
15  import org.mule.config.i18n.CoreMessages;
16  import org.mule.config.i18n.Message;
17  import org.mule.config.i18n.MessageFactory;
18  import org.mule.impl.endpoint.MuleEndpoint;
19  import org.mule.providers.AbstractConnector;
20  import org.mule.umo.endpoint.EndpointException;
21  import org.mule.umo.endpoint.UMOEndpoint;
22  import org.mule.umo.endpoint.UMOEndpointURI;
23  import org.mule.umo.endpoint.UMOImmutableEndpoint;
24  import org.mule.umo.provider.UMOConnector;
25  import org.mule.umo.transformer.UMOTransformer;
26  import org.mule.util.BeanUtils;
27  import org.mule.util.ClassUtils;
28  import org.mule.util.MuleObjectHelper;
29  import org.mule.util.ObjectFactory;
30  import org.mule.util.ObjectNameHelper;
31  import org.mule.util.PropertiesUtils;
32  import org.mule.util.SpiUtils;
33  
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.util.HashMap;
37  import java.util.Iterator;
38  import java.util.Map;
39  import java.util.Properties;
40  
41  import org.apache.commons.logging.Log;
42  import org.apache.commons.logging.LogFactory;
43  
44  /**
45   * <code>TransportFactory</code> can be used for generically creating endpoints
46   * from an url. Note that for some endpoints, the url alone is not enough to create
47   * the endpoint if a connector for the endpoint has not already been configured with
48   * the Mule Manager.
49   * 
50   */
51  
52  public final class TransportFactory
53  {
54      public static final String PROVIDER_SERVICES_PATH = "org/mule/providers";
55  
56      /**
57       * logger used by this class
58       */
59      protected static final Log logger = LogFactory.getLog(TransportFactory.class);
60  
61      public static final int GET_OR_CREATE_CONNECTOR = 0;
62      public static final int ALWAYS_CREATE_CONNECTOR = 1;
63      public static final int NEVER_CREATE_CONNECTOR = 2;
64      public static final int USE_CONNECTOR = 3;
65  
66      // @GuardedBy("TransportFactory.class")
67      private static Map csdCache = new HashMap();
68  
69      /** Do not instanciate. */
70      private TransportFactory ()
71      {
72          // no-op
73      }
74  
75      public static UMOEndpoint createEndpoint(UMOEndpointURI uri, String type) throws EndpointException
76      {
77          String scheme = uri.getFullScheme();
78          UMOConnector connector;
79          try
80          {
81              if (uri.getCreateConnector() == ALWAYS_CREATE_CONNECTOR)
82              {
83                  connector = createConnector(uri);
84                  MuleManager.getInstance().registerConnector(connector);
85              }
86              else if (uri.getCreateConnector() == NEVER_CREATE_CONNECTOR)
87              {
88                  connector = getConnectorByProtocol(scheme);
89              }
90              else if (uri.getConnectorName() != null)
91              {
92                  connector = MuleManager.getInstance().lookupConnector(uri.getConnectorName());
93                  if (connector == null)
94                  {
95                      throw new TransportFactoryException(
96                          CoreMessages.objectNotRegisteredWithManager("Connector: " + uri.getConnectorName()));
97                  }
98              }
99              else
100             {
101                 connector = getConnectorByProtocol(scheme);
102                 if (connector == null)
103                 {
104                     connector = createConnector(uri);
105                     MuleManager.getInstance().registerConnector(connector);
106                 }
107             }
108         }
109         catch (Exception e)
110         {
111             throw new TransportFactoryException(e);
112         }
113 
114         if (connector == null)
115         {
116             Message m = CoreMessages.failedToCreateObjectWith("Endpoint", "Uri: " + uri);
117             m.setNextMessage(CoreMessages.objectIsNull("connector"));
118             throw new TransportFactoryException(m);
119 
120         }
121 
122         UMOEndpoint endpoint = new MuleEndpoint();
123         endpoint.setConnector(connector);
124         endpoint.setEndpointURI(uri);
125         if (uri.getEndpointName() != null)
126         {
127             endpoint.setName(uri.getEndpointName());
128         }
129         String name = ObjectNameHelper.getEndpointName(endpoint);
130 
131         endpoint.setName(name);
132 
133         if (type != null)
134         {
135             endpoint.setType(type);
136             UMOTransformer trans = getTransformer(uri, connector,
137                 (UMOEndpoint.ENDPOINT_TYPE_RECEIVER.equals(type) ? 0 : 1));
138             endpoint.setTransformer(trans);
139             if (UMOEndpoint.ENDPOINT_TYPE_RECEIVER.equals(type))
140             {
141                 // set the response transformer
142                 trans = getTransformer(uri, connector, 2);
143                 endpoint.setResponseTransformer(trans);
144             }
145         }
146         return endpoint;
147     }
148 
149     /**
150      * @param url
151      * @param cnn
152      * @param type 0=inbound, 1=outbound, 2=response
153      * @return
154      * @throws TransportFactoryException
155      */
156     private static UMOTransformer getTransformer(UMOEndpointURI url, UMOConnector cnn, int type)
157         throws TransportFactoryException
158     {
159         UMOTransformer trans = null;
160         String transId;
161         if (type == 2)
162         {
163             transId = url.getResponseTransformers();
164         }
165         else
166         {
167             transId = url.getTransformers();
168         }
169 
170         if (transId != null)
171         {
172             try
173             {
174                 trans = MuleObjectHelper.getTransformer(transId, ",");
175             }
176             catch (MuleException e)
177             {
178                 throw new TransportFactoryException(e);
179             }
180         }
181         else
182         {
183             // Get connector specific overrides to set on the descriptor
184             Properties overrides = new Properties();
185             if (cnn instanceof AbstractConnector)
186             {
187                 Map so = ((AbstractConnector) cnn).getServiceOverrides();
188                 if (so != null)
189                 {
190                     overrides.putAll(so);
191                 }
192             }
193 
194             String scheme = url.getSchemeMetaInfo();
195 
196             //check if there is a transformer associated with connector allready...
197             //if not, get it from the ServiceDescriptor
198             if (cnn instanceof AbstractConnector)
199             {
200                 AbstractConnector aconn = (AbstractConnector) cnn;
201                 // TODO MCR use the constants for the type, there should be on already
202                 if (type == 0)
203                 {
204                     trans = aconn.getDefaultInboundTransformer();
205                 }
206                 else if (type == 1)
207                 {
208                     trans = aconn.getDefaultOutboundTransformer();
209                 }
210                 else
211                 {
212                     trans = aconn.getDefaultResponseTransformer();
213                 }
214             }
215 
216             if (trans == null)
217             {
218                 TransportServiceDescriptor csd = getServiceDescriptor(scheme, overrides);
219                 if (type == 0)
220                 {
221                     trans = csd.createInboundTransformer();
222                 }
223                 else if (type == 1)
224                 {
225                     trans = csd.createOutboundTransformer();
226                 }
227                 else
228                 {
229                     trans = csd.createResponseTransformer();
230                 }
231             }
232         }
233         return trans;
234     }
235 
236     /**
237      * Creates an uninitialied connector from the provided MuleEndpointURI. The
238      * scheme is used to determine what kind of connector to create. Any params set
239      * on the uri can be used to initialise bean properties on the created connector.
240      * <p/> Note that the initalise method will need to be called on the connector
241      * returned. This is so that developers can control when the connector
242      * initialisation takes place as this is likely to initialse all connecotr
243      * resources.
244      * 
245      * @param url the MuleEndpointURI url to create the connector with
246      * @return a new Connector
247      * @throws TransportFactoryException
248      */
249     public static UMOConnector createConnector(UMOEndpointURI url) throws TransportFactoryException
250     {
251         String scheme = url.getSchemeMetaInfo();
252 
253         UMOConnector connector;
254         TransportServiceDescriptor csd = getServiceDescriptor(scheme);
255         // Make sure we can create the endpoint/connector using this service
256         // method
257         if (csd.getServiceError() != null)
258         {
259             throw new TransportServiceException(MessageFactory.createStaticMessage(csd.getServiceError()));
260         }
261 
262         // If this is a fineder service, lets find it before trying to create it
263         if (csd.getServiceFinder() != null)
264         {
265             csd = csd.createServiceFinder().findService(scheme, csd);
266         }
267         // if there is a factory, use it
268         try
269         {
270             if (csd.getConnectorFactory() != null)
271             {
272                 ObjectFactory factory = (ObjectFactory) ClassUtils.loadClass(csd.getConnectorFactory(),
273                                                                              TransportFactory.class).newInstance();
274                 connector = (UMOConnector) factory.create();
275             }
276             else
277             {
278                 if (csd.getConnector() != null)
279                 {
280                     connector = (UMOConnector) ClassUtils.loadClass(csd.getConnector(), TransportFactory.class)
281                         .newInstance();
282                     if (connector instanceof AbstractConnector)
283                     {
284                         ((AbstractConnector) connector).initialiseFromUrl(url);
285                     }
286                 }
287                 else
288                 {
289                     throw new TransportFactoryException(
290                         CoreMessages.objectNotSetInService("Connector", scheme));
291                 }
292             }
293         }
294         catch (TransportFactoryException e)
295         {
296             throw e;
297         }
298         catch (Exception e)
299         {
300             throw new TransportFactoryException(
301                 CoreMessages.failedToCreateObjectWith("Endpoint", url), e);
302         }
303 
304         connector.setName(ObjectNameHelper.getConnectorName(connector));
305 
306         // set any manager default properties for the connector
307         // these are set on the Manager with a protocol i.e.
308         // jms.specification=1.1
309         Map props = new HashMap();
310         PropertiesUtils.getPropertiesWithPrefix(MuleManager.getInstance().getProperties(),
311             connector.getProtocol().toLowerCase(), props);
312         if (props.size() > 0)
313         {
314             props = PropertiesUtils.removeNamespaces(props);
315             BeanUtils.populateWithoutFail(connector, props, true);
316         }
317 
318         return connector;
319     }
320 
321     public static TransportServiceDescriptor getServiceDescriptor(String protocol)
322         throws TransportFactoryException
323     {
324         return getServiceDescriptor(protocol, null);
325     }
326 
327     public static synchronized TransportServiceDescriptor getServiceDescriptor(String protocol, Properties overrides)
328         throws TransportFactoryException
329     {
330         TransportServiceDescriptor csd = (TransportServiceDescriptor) csdCache.get(new CSDKey(protocol, overrides));
331         if (csd == null)
332         {
333             String location = SpiUtils.SERVICE_ROOT + PROVIDER_SERVICES_PATH;
334             InputStream is = SpiUtils.findServiceDescriptor(PROVIDER_SERVICES_PATH, protocol + ".properties",
335                 TransportFactory.class);
336 
337             // TODO RM: this can be removed in Mule 2.0
338             if (is == null)
339             {
340                 //The legacy connector decriptors did did not use file extensions
341                 is = SpiUtils.findServiceDescriptor(PROVIDER_SERVICES_PATH, protocol,
342                 TransportFactory.class);
343                 if (is != null)
344                 {
345                     logger.warn("The transport " + protocol + " is using a legacy style descriptor."
346                                     + " This needs to be updated."
347                                     + " Future versions of Mule will not work with this descriptor.");
348                 }
349             }
350             try
351             {
352                 if (is != null)
353                 {
354                     Properties props = new Properties();
355                     props.load(is);
356                     csd = new TransportServiceDescriptor(protocol, location, props);
357                     // set any overides on the descriptor
358                     csd.setOverrides(overrides);
359                     if (csd.getServiceFinder() != null)
360                     {
361                         TransportServiceFinder finder = csd.createServiceFinder();
362                         csd = finder.findService(protocol, csd);
363                     }
364                     csdCache.put(new CSDKey(csd.getProtocol(), overrides), csd);
365                 }
366                 else
367                 {
368                     throw new TransportServiceNotFoundException(location + "/" + protocol);
369                 }
370             }
371             catch (IOException e)
372             {
373                 throw new TransportFactoryException(
374                     CoreMessages.failedToCreateEndpointFromLocation(location + "/" + protocol), e);
375             }
376         }
377         return csd;
378     }
379 
380     public static UMOConnector getOrCreateConnectorByProtocol(UMOEndpointURI uri)
381         throws TransportFactoryException
382     {
383         return getOrCreateConnectorByProtocol(uri, uri.getCreateConnector());
384     }
385 
386     public static UMOConnector getOrCreateConnectorByProtocol(UMOImmutableEndpoint endpoint)
387         throws TransportFactoryException
388     {
389         return getOrCreateConnectorByProtocol(endpoint.getEndpointURI(), endpoint.getCreateConnector());
390     }
391 
392     private static UMOConnector getOrCreateConnectorByProtocol(UMOEndpointURI uri, int create)
393         throws TransportFactoryException
394     {
395         final String connectorName = uri.getConnectorName();
396         UMOConnector connector = MuleManager.getInstance().lookupConnector(connectorName);
397         if (connector != null)
398         {
399             return connector;
400         }
401 
402         connector = getConnectorByProtocol(uri.getFullScheme());
403         if (ALWAYS_CREATE_CONNECTOR == create
404             || (connector == null && create == GET_OR_CREATE_CONNECTOR))
405         {
406             connector = createConnector(uri);
407             try
408             {
409                 BeanUtils.populate(connector, uri.getParams());
410                 MuleManager.getInstance().registerConnector(connector);
411 
412             }
413             catch (Exception e)
414             {
415                 throw new TransportFactoryException(
416                     CoreMessages.failedToSetPropertiesOn("Connector"), e);
417             }
418         }
419         else if (create == NEVER_CREATE_CONNECTOR && connector == null)
420         {
421             logger.warn("There is no connector for protocol: " + uri.getScheme()
422                         + " and 'createConnector' is set to NEVER.  Returning null");
423         }
424         return connector;
425     }
426 
427     public static UMOConnector getConnectorByProtocol(String protocol)
428     {
429         UMOConnector connector;
430         UMOConnector resultConnector = null;
431         Map connectors = MuleManager.getInstance().getConnectors();
432         for (Iterator iterator = connectors.values().iterator(); iterator.hasNext();)
433         {
434             connector = (UMOConnector) iterator.next();
435             if (connector.supportsProtocol(protocol))
436             {
437                 if (resultConnector == null)
438                 {
439                     resultConnector = connector;
440                 }
441                 else
442                 {
443                     throw new IllegalStateException(
444                         CoreMessages.moreThanOneConnectorWithProtocol(protocol).getMessage());
445                 }
446             }
447         }
448         return resultConnector;
449     }
450 
451     private static class CSDKey
452     {
453         private final Map overrides;
454         private final String protocol;
455 
456         public CSDKey(String protocol, Map overrides)
457         {
458             this.overrides = overrides;
459             this.protocol = protocol;
460         }
461 
462         // @Override
463         public boolean equals(Object o)
464         {
465             if (this == o)
466             {
467                 return true;
468             }
469             if (!(o instanceof CSDKey))
470             {
471                 return false;
472             }
473 
474             final CSDKey csdKey = (CSDKey) o;
475 
476             if (overrides != null ? !overrides.equals(csdKey.overrides) : csdKey.overrides != null)
477             {
478                 return false;
479             }
480             return protocol.equals(csdKey.protocol);
481 
482         }
483 
484         // @Override
485         public int hashCode()
486         {
487             return 29 * (overrides != null ? overrides.hashCode() : 0) + protocol.hashCode();
488         }
489     }
490 }