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.endpoint;
8   
9   import org.mule.api.MuleContext;
10  import org.mule.api.endpoint.EndpointException;
11  import org.mule.api.endpoint.EndpointURI;
12  import org.mule.api.endpoint.EndpointURIBuilder;
13  import org.mule.api.endpoint.MalformedEndpointException;
14  import org.mule.api.lifecycle.InitialisationException;
15  import org.mule.api.registry.ServiceException;
16  import org.mule.api.registry.ServiceType;
17  import org.mule.config.i18n.CoreMessages;
18  import org.mule.transport.service.TransportServiceDescriptor;
19  import org.mule.util.ClassUtils;
20  import org.mule.util.PropertiesUtils;
21  import org.mule.util.StringUtils;
22  
23  import java.net.URI;
24  import java.net.URISyntaxException;
25  import java.util.Properties;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  
30  /**
31   * <code>MuleEndpointURI</code> is used to determine how a message is sent or received. The url
32   * defines the protocol, the endpointUri destination of the message and optionally the endpoint to
33   * use when dispatching the event. Mule urls take the form of -
34   * protocol://[host]:[port]/[provider]/endpointUri or
35   * protocol://[host]:[port]/endpointUri i.e. vm:///my.object
36   * <br/>
37   * The protocol can be any of any connector registered with Mule. The endpoint name if specified
38   * must be the name of a registered global endpoint. The endpointUri can be any endpointUri
39   * recognized by the endpoint type.
40   */
41  public class MuleEndpointURI implements EndpointURI
42  {
43      /**
44       * Serial version
45       */
46      private static final long serialVersionUID = 3906735768171252877L;
47  
48      /**
49       * logger used by this class
50       */
51      protected static final Log logger = LogFactory.getLog(MuleEndpointURI.class);
52  
53      public static boolean isMuleUri(String url)
54      {
55          return url.indexOf(":/") != -1;
56      }
57  
58      private String address;
59      private String filterAddress;
60      private String endpointName;
61      private String connectorName;
62      private String transformers;
63      private String responseTransformers;
64      private Properties params = new Properties();
65      private URI uri;
66      private String userInfo;
67      private String schemeMetaInfo;
68      private String resourceInfo;
69      private boolean dynamic;
70      private transient MuleContext muleContext;
71      private Properties serviceOverrides;
72  
73      MuleEndpointURI(String address,
74                      String endpointName,
75                      String connectorName,
76                      String transformers,
77                      String responseTransformers,
78                      Properties properties,
79                      URI uri,
80                      String userInfo, MuleContext muleContext)
81      {
82          this(address, endpointName, connectorName, transformers, responseTransformers,
83                  properties, uri, muleContext);
84          if (userInfo != null)
85          {
86              this.userInfo = userInfo;
87          }
88      }
89  
90      public MuleEndpointURI(String address,
91                             String endpointName,
92                             String connectorName,
93                             String transformers,
94                             String responseTransformers,
95                             Properties properties,
96                             URI uri, MuleContext muleContext)
97      {
98          this.address = address;
99          this.endpointName = endpointName;
100         this.connectorName = connectorName;
101         this.transformers = transformers;
102         this.responseTransformers = responseTransformers;
103         this.params = properties;
104         this.uri = uri;
105         this.userInfo = uri.getUserInfo();
106         this.muleContext = muleContext;
107         if (properties != null)
108         {
109             resourceInfo = (String) properties.remove("resourceInfo");
110         }
111     }
112 
113     public MuleEndpointURI(EndpointURI endpointUri)
114     {
115         initialise(endpointUri);
116     }
117 
118     public MuleEndpointURI(EndpointURI endpointUri, String filterAddress)
119     {
120         initialise(endpointUri);
121         this.filterAddress = filterAddress;
122     }
123 
124     public MuleEndpointURI(String uri, MuleContext muleContext) throws EndpointException
125     {
126         this(uri, null, muleContext);
127     }
128 
129     public MuleEndpointURI(String uri, MuleContext muleContext, Properties serviceOverrides) throws EndpointException
130     {
131         this(uri, null, muleContext);
132         this.serviceOverrides = serviceOverrides;
133     }
134 
135     /**
136      * Creates but does not initialize the endpoint URI.  It is up to the caller
137      * to call initialise() at some point.
138      */
139     public MuleEndpointURI(String uri, String encodedUri, MuleContext muleContext) throws EndpointException
140     {
141         this.muleContext = muleContext;
142         uri = preprocessUri(uri);
143         String startUri = uri;
144         uri = convertExpressionDelimiters(uri, "#");
145         uri = convertExpressionDelimiters(uri, "$");
146 
147         if (uri.indexOf("#[") >= 0)
148         {
149             address = uri;
150             dynamic = true;
151         }
152         else
153         {
154             try
155             {
156                 this.uri = new URI((encodedUri != null && uri.equals(startUri)) ? preprocessUri(encodedUri) : uri);
157             }
158             catch (URISyntaxException e)
159             {
160                 throw new MalformedEndpointException(uri, e);
161             }
162             this.userInfo = this.uri.getRawUserInfo();
163         }
164     }
165 
166     private String convertExpressionDelimiters(String uriString, String startChar)
167     {
168         //Allow Expressions to be embedded
169         int uriLength = uriString.length();
170         for (int index = 0; index < uriLength; )
171         {
172             index = uriString.indexOf(startChar + "{", index);
173             if (index < 0)
174             {
175                 break;
176             }
177             int braceCount = 1;
178             for (int seek = index + 2; seek < uriLength; seek++)
179             {
180                 char c = uriString.charAt(seek);
181                 if (c == '{')
182                 {
183                     braceCount++;
184                 }
185                 else if (c == '}')
186                 {
187                     if (--braceCount == 0)
188                     {
189                         uriString = uriString.substring(0, index) + startChar + "[" + uriString.substring(index + 2, seek) + "]" + uriString.substring(seek+1);
190                         break;
191                     }
192                 }
193             }
194             index += 2;
195         }
196         return uriString;
197     }
198 
199     protected String preprocessUri(String uriString) throws MalformedEndpointException
200     {
201         uriString = uriString.trim().replaceAll(" ", "%20");
202         if (!validateUrl(uriString))
203         {
204             throw new MalformedEndpointException(uriString);
205         }
206         schemeMetaInfo = retrieveSchemeMetaInfo(uriString);
207         if (schemeMetaInfo != null)
208         {
209             uriString = uriString.replaceFirst(schemeMetaInfo + ":", "");
210         }
211         return uriString;
212     }
213 
214     public void initialise() throws InitialisationException
215     {
216         try
217         {
218             String scheme = getFullScheme();
219             TransportServiceDescriptor sd;
220             sd = (TransportServiceDescriptor) muleContext.getRegistry().lookupServiceDescriptor(ServiceType.TRANSPORT, scheme, serviceOverrides);
221             if (sd == null)
222             {
223                 throw new ServiceException(CoreMessages.noServiceTransportDescriptor(scheme));
224             }
225             EndpointURIBuilder builder = sd.createEndpointURIBuilder();
226             EndpointURI built = builder.build(this.uri, muleContext);
227             initialise(built);
228         }
229         catch (Exception e)
230         {
231             throw new InitialisationException(e, this);
232         }
233     }
234 
235     private String retrieveSchemeMetaInfo(String url)
236     {
237         int i = url.indexOf(':');
238         if (i == -1)
239         {
240             return null;
241         }
242         if (url.charAt(i + 1) == '/')
243         {
244             return null;
245         }
246         else
247         {
248             return url.substring(0, i);
249         }
250     }
251 
252     protected boolean validateUrl(String url)
253     {
254         return (url.indexOf(":/") > 0);
255     }
256 
257     private void initialise(EndpointURI endpointUri)
258     {
259         this.address = endpointUri.getAddress();
260         if (this.endpointName == null)
261         {
262             this.endpointName = endpointUri.getEndpointName();
263         }
264         this.connectorName = endpointUri.getConnectorName();
265         this.transformers = endpointUri.getTransformers();
266         this.responseTransformers = endpointUri.getResponseTransformers();
267         this.params = endpointUri.getParams();
268         this.uri = endpointUri.getUri();
269         this.resourceInfo = endpointUri.getResourceInfo();
270         this.userInfo = endpointUri.getUserInfo();
271     }
272 
273     public String getAddress()
274     {
275         return address;
276     }
277 
278     public String getEndpointName()
279     {
280         return (StringUtils.isEmpty(endpointName) ? null : endpointName);
281     }
282 
283     public Properties getParams()
284     {
285         // TODO fix this so that the query string properties are not lost.
286         // not sure whats causing this at the moment
287         if (params.size() == 0 && getQuery() != null)
288         {
289             params = PropertiesUtils.getPropertiesFromQueryString(getQuery());
290         }
291         return params;
292     }
293 
294     public Properties getUserParams()
295     {
296         Properties p = new Properties();
297         p.putAll(getParams());
298         p.remove(PROPERTY_ENDPOINT_NAME);
299         p.remove(PROPERTY_ENDPOINT_URI);
300         p.remove(PROPERTY_TRANSFORMERS);
301         return p;
302     }
303 
304     public URI parseServerAuthority() throws URISyntaxException
305     {
306         return uri.parseServerAuthority();
307     }
308 
309     public URI normalize()
310     {
311         return uri.normalize();
312     }
313 
314     public URI resolve(URI uri)
315     {
316         return uri.resolve(uri);
317     }
318 
319     public URI resolve(String str)
320     {
321         return uri.resolve(str);
322     }
323 
324     public URI relativize(URI uri)
325     {
326         return uri.relativize(uri);
327     }
328 
329     public String getScheme()
330     {
331         return uri.getScheme();
332     }
333 
334     public String getFullScheme()
335     {
336         String scheme;
337         if (dynamic)
338         {
339             int colon = address.indexOf(':');
340             scheme = address.substring(0, colon);
341         }
342         else
343         {
344             scheme = uri.getScheme();
345         }
346         return (schemeMetaInfo == null ? scheme : schemeMetaInfo + ':' + scheme);
347     }
348 
349     public boolean isAbsolute()
350     {
351         return uri.isAbsolute();
352     }
353 
354     public boolean isOpaque()
355     {
356         return uri.isOpaque();
357     }
358 
359     public String getRawSchemeSpecificPart()
360     {
361         return uri.getRawSchemeSpecificPart();
362     }
363 
364     public String getSchemeSpecificPart()
365     {
366         return uri.getSchemeSpecificPart();
367     }
368 
369     public String getRawAuthority()
370     {
371         return uri.getRawAuthority();
372     }
373 
374     public String getAuthority()
375     {
376         return uri.getAuthority();
377     }
378 
379     public String getRawUserInfo()
380     {
381         return uri.getRawUserInfo();
382     }
383 
384     public String getUserInfo()
385     {
386         return userInfo;
387     }
388 
389     public String getHost()
390     {
391         return uri.getHost();
392     }
393 
394     public int getPort()
395     {
396         return uri.getPort();
397     }
398 
399     public String getRawPath()
400     {
401         return uri.getRawPath();
402     }
403 
404     public String getPath()
405     {
406         return uri.getPath();
407     }
408 
409     public String getRawQuery()
410     {
411         return uri.getRawQuery();
412     }
413 
414     public String getQuery()
415     {
416         return uri.getQuery();
417     }
418 
419     public String getRawFragment()
420     {
421         return uri.getRawFragment();
422     }
423 
424     public String getFragment()
425     {
426         return uri.getFragment();
427     }
428 
429     @Override
430     public String toString()
431     {
432         if (StringUtils.isNotEmpty(userInfo) && (userInfo.indexOf(":") > 0))
433         {
434             return createUriStringWithPasswordMasked();
435         }
436         return uri.toASCIIString();
437     }
438 
439     protected String createUriStringWithPasswordMasked()
440     {
441         String rawUserInfo =  uri.getRawUserInfo();
442         // uri.getRawUserInfo() returns null for JMS endpoints with passwords, so use the userInfo
443         // from this instance instead
444         if (StringUtils.isBlank(rawUserInfo))
445         {
446             rawUserInfo = userInfo;
447         }
448 
449         String maskedUserInfo = null;
450         int index = rawUserInfo.indexOf(":");
451         if (index > -1)
452         {
453             maskedUserInfo = rawUserInfo.substring(0, index);
454         }
455 
456         maskedUserInfo = maskedUserInfo + ":****";
457         return uri.toASCIIString().replace(rawUserInfo, maskedUserInfo);
458     }
459 
460     public String getTransformers()
461     {
462         return transformers;
463     }
464 
465     public URI getUri()
466     {
467         return uri;
468     }
469 
470     public String getConnectorName()
471     {
472         return connectorName;
473     }
474 
475     public String getSchemeMetaInfo()
476     {
477         return (schemeMetaInfo == null ? uri.getScheme() : schemeMetaInfo);
478     }
479 
480     public String getResourceInfo()
481     {
482         return resourceInfo;
483     }
484 
485     public String getFilterAddress()
486     {
487         return filterAddress;
488     }
489 
490     public String getUser()
491     {
492         if (StringUtils.isNotBlank(userInfo))
493         {
494             int i = userInfo.indexOf(':');
495             if (i == -1)
496             {
497                 return userInfo;
498             }
499             else
500             {
501                 return userInfo.substring(0, i);
502             }
503         }
504         return null;
505     }
506 
507     public String getResponseTransformers()
508     {
509         return responseTransformers;
510     }
511 
512     public String getPassword()
513     {
514         if (StringUtils.isNotBlank(userInfo))
515         {
516             int i = userInfo.indexOf(':');
517             if (i > -1)
518             {
519                 return userInfo.substring(i + 1);
520             }
521         }
522         return null;
523     }
524 
525     public MuleContext getMuleContext()
526     {
527         return muleContext;
528     }
529 
530     public boolean isDynamic()
531     {
532         return dynamic;
533     }
534 
535     @Override
536     public boolean equals(Object o)
537     {
538         if (this == o)
539         {
540             return true;
541         }
542         if (!(o instanceof MuleEndpointURI))
543         {
544             return false;
545         }
546         MuleEndpointURI muleEndpointURI = (MuleEndpointURI) o;
547         return ClassUtils.equal(address, muleEndpointURI.address) &&
548                 ClassUtils.equal(connectorName, muleEndpointURI.connectorName) &&
549                 ClassUtils.equal(endpointName, muleEndpointURI.endpointName) &&
550                 ClassUtils.equal(filterAddress, muleEndpointURI.filterAddress) &&
551                 ClassUtils.equal(params, muleEndpointURI.params) &&
552                 ClassUtils.equal(resourceInfo, muleEndpointURI.resourceInfo) &&
553                 ClassUtils.equal(schemeMetaInfo, muleEndpointURI.schemeMetaInfo) &&
554                 ClassUtils.equal(transformers, muleEndpointURI.transformers) &&
555                 ClassUtils.equal(responseTransformers, muleEndpointURI.responseTransformers) &&
556                 ClassUtils.equal(uri, muleEndpointURI.uri);
557     }
558 
559     @Override
560     public int hashCode()
561     {
562         return ClassUtils.hash(new Object[]{
563                 address,
564                 filterAddress,
565                 endpointName,
566                 connectorName,
567                 transformers,
568                 responseTransformers,
569                 params,
570                 uri,
571                 schemeMetaInfo,
572                 resourceInfo
573         });
574     }
575 }