View Javadoc

1   /*
2    * $Id: AbstractEndpoint.java 20781 2010-12-16 13:19:09Z 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.endpoint;
12  
13  import org.mule.MessageExchangePattern;
14  import org.mule.api.MuleContext;
15  import org.mule.api.MuleException;
16  import org.mule.api.construct.FlowConstruct;
17  import org.mule.api.endpoint.EndpointMessageProcessorChainFactory;
18  import org.mule.api.endpoint.EndpointURI;
19  import org.mule.api.endpoint.ImmutableEndpoint;
20  import org.mule.api.lifecycle.Disposable;
21  import org.mule.api.processor.MessageProcessor;
22  import org.mule.api.processor.MessageProcessorChain;
23  import org.mule.api.retry.RetryPolicyTemplate;
24  import org.mule.api.routing.filter.Filter;
25  import org.mule.api.security.EndpointSecurityFilter;
26  import org.mule.api.transaction.TransactionConfig;
27  import org.mule.api.transformer.Transformer;
28  import org.mule.api.transport.Connector;
29  import org.mule.processor.SecurityFilterMessageProcessor;
30  import org.mule.routing.MessageFilter;
31  import org.mule.util.ClassUtils;
32  
33  import java.net.URI;
34  import java.util.HashMap;
35  import java.util.LinkedList;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.regex.Matcher;
39  import java.util.regex.Pattern;
40  
41  import edu.emory.mathcs.backport.java.util.Collections;
42  
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  
46  /**
47   * <code>ImmutableMuleEndpoint</code> describes a Provider in the Mule Server. A
48   * endpoint is a grouping of an endpoint, an endpointUri and a transformer.
49   */
50  public abstract class AbstractEndpoint implements ImmutableEndpoint, Disposable
51  {
52  
53      private static final long serialVersionUID = -1650380871293160973L;
54  
55      public static final String PROPERTY_PROCESS_SYNCHRONOUSLY = "processSynchronously";
56  
57      /**
58       * logger used by this class
59       */
60      protected static final Log logger = LogFactory.getLog(AbstractEndpoint.class);
61  
62      /**
63       * The endpoint used to communicate with the external system
64       */
65      private final Connector connector;
66  
67      /**
68       * The endpointUri on which to send or receive information
69       */
70      private final EndpointURI endpointUri;
71  
72      private final EndpointMessageProcessorChainFactory messageProcessorsFactory;
73  
74      private final List <MessageProcessor> messageProcessors;
75  
76      private final List <MessageProcessor> responseMessageProcessors;
77      
78      private MessageProcessor messageProcessorChain;
79  
80      /**
81       * The name for the endpoint
82       */
83      private final String name;
84  
85      /**
86       * Any additional properties for the endpoint
87       * // TODO This should be final. See MULE-3105
88       * // TODO Shouldn't this be guarded from concurrent writes?
89       */
90      private Map properties = new HashMap();
91  
92      /**
93       * The transaction configuration for this endpoint
94       */
95      private final TransactionConfig transactionConfig;
96  
97      /**
98       * determines whether unaccepted filtered events should be removed from the
99       * source. If they are not removed its up to the Message receiver to handle
100      * recieving the same message again
101      */
102     private final boolean deleteUnacceptedMessages;
103 
104     private final MessageExchangePattern messageExchangePattern;
105     
106     /**
107      * How long to block when performing a remote synchronisation to a remote host.
108      * This property is optional and will be set to the default Synchonous MuleEvent
109      * time out value if not set
110      */
111     private final int responseTimeout;
112 
113     /**
114      * The state that the endpoint is initialised in such as started or stopped
115      */
116     private final String initialState;
117 
118     private final String endpointEncoding;
119 
120     private MuleContext muleContext;
121 
122     protected RetryPolicyTemplate retryPolicyTemplate;
123 
124     private String endpointBuilderName;
125 
126     private final String endpointMimeType;
127 
128     private boolean disableTransportTransformer = false;
129 
130     public AbstractEndpoint(Connector connector,
131                             EndpointURI endpointUri,
132                             String name,
133                             Map properties,
134                             TransactionConfig transactionConfig,
135                             boolean deleteUnacceptedMessages,
136                             MessageExchangePattern messageExchangePattern,
137                             int responseTimeout,
138                             String initialState,
139                             String endpointEncoding,
140                             String endpointBuilderName,
141                             MuleContext muleContext,
142                             RetryPolicyTemplate retryPolicyTemplate,
143                             EndpointMessageProcessorChainFactory messageProcessorsFactory,
144                             List <MessageProcessor> messageProcessors,
145                             List <MessageProcessor> responseMessageProcessors,
146                             boolean disableTransportTransformer,
147                             String endpointMimeType)
148     {
149         this.connector = connector;
150         this.endpointUri = endpointUri;
151         this.name = name;
152         // TODO Properties should be immutable. See MULE-3105
153         // this.properties = Collections.unmodifiableMap(properties);
154         this.properties.putAll(properties);
155         this.transactionConfig = transactionConfig;
156         this.deleteUnacceptedMessages = deleteUnacceptedMessages;
157 
158         this.responseTimeout = responseTimeout;
159         this.initialState = initialState;
160         this.endpointEncoding = endpointEncoding;
161         this.endpointBuilderName = endpointBuilderName;
162         this.muleContext = muleContext;
163         this.retryPolicyTemplate = retryPolicyTemplate;
164         this.endpointMimeType = endpointMimeType;
165         this.disableTransportTransformer = disableTransportTransformer;
166 
167         if (transactionConfig != null && transactionConfig.getFactory() != null &&
168             transactionConfig.getAction() != TransactionConfig.ACTION_NONE &&
169             transactionConfig.getAction() != TransactionConfig.ACTION_NEVER)
170         {
171             if (logger.isDebugEnabled())
172             {
173                 logger.debug("Endpoint has a transaction configuration. Defaulting to REQUEST_RESPONSE. Endpoint is: " + toString());
174             }
175             this.messageExchangePattern = MessageExchangePattern.REQUEST_RESPONSE;
176         }
177         else
178         {
179             this.messageExchangePattern = messageExchangePattern;
180         }
181 
182         this.messageProcessorsFactory = messageProcessorsFactory;
183         if (messageProcessors == null)
184         {
185             this.messageProcessors = Collections.emptyList();
186         }
187         else
188         {
189             this.messageProcessors = messageProcessors;
190         }
191         if (responseMessageProcessors == null)
192         {
193             this.responseMessageProcessors = Collections.emptyList();
194         }
195         else
196         {
197             this.responseMessageProcessors = responseMessageProcessors;
198         }
199     }
200 
201     public EndpointURI getEndpointURI()
202     {
203         return endpointUri;
204     }
205 
206     public String getAddress()
207     {
208         EndpointURI uri = getEndpointURI();
209         if (uri != null)
210         {
211             return uri.getUri().toString();
212         }
213         else
214         {
215             return null;
216         }
217     }
218 
219     public String getEncoding()
220     {
221         return endpointEncoding;
222     }
223 
224     public String getMimeType()
225     {
226         return endpointMimeType;
227     }
228 
229     public Connector getConnector()
230     {
231         return connector;
232     }
233 
234     public String getName()
235     {
236         return name;
237     }
238 
239     public EndpointMessageProcessorChainFactory getMessageProcessorsFactory()
240     {
241         return messageProcessorsFactory;
242     }
243 
244     public List <MessageProcessor> getMessageProcessors()
245     {
246         return messageProcessors;
247     }
248 
249     public List <MessageProcessor> getResponseMessageProcessors()
250     {
251         return responseMessageProcessors;
252     }
253 
254     /** @deprecated use getMessageProcessors() */
255     public List<Transformer> getTransformers()
256     {
257         return getTransformersFromProcessorList(messageProcessors);
258     }
259 
260     public Map getProperties()
261     {
262         return properties;
263     }
264 
265     public boolean isReadOnly()
266     {
267         return true;
268     }
269 
270     @Override
271     public String toString()
272     {
273         // Use the interface to retrieve the string and set
274         // the endpoint uri to a default value
275         String sanitizedEndPointUri = null;
276         URI uri = null;
277         if (endpointUri != null)
278         {
279             sanitizedEndPointUri = endpointUri.toString();
280             uri = endpointUri.getUri();
281         }
282         // The following will further sanitize the endpointuri by removing
283         // the embedded password. This will only remove the password if the
284         // uri contains all the necessary information to successfully rebuild the url
285         if (uri != null && (uri.getRawUserInfo() != null) && (uri.getScheme() != null) && (uri.getHost() != null)
286                 && (uri.getRawPath() != null))
287         {
288             // build a pattern up that matches what we need tp strip out the password
289             Pattern sanitizerPattern = Pattern.compile("(.*):.*");
290             Matcher sanitizerMatcher = sanitizerPattern.matcher(uri.getRawUserInfo());
291             if (sanitizerMatcher.matches())
292             {
293                 sanitizedEndPointUri = new StringBuffer(uri.getScheme()).append("://")
294                         .append(sanitizerMatcher.group(1))
295                         .append(":<password>")
296                         .append("@")
297                         .append(uri.getHost())
298                         .append(uri.getRawPath())
299                         .toString();
300             }
301             if (uri.getRawQuery() != null)
302             {
303                 sanitizedEndPointUri = sanitizedEndPointUri + "?" + uri.getRawQuery();
304             }
305 
306         }
307 
308         return ClassUtils.getClassName(getClass()) + "{endpointUri=" + sanitizedEndPointUri + ", connector="
309                 + connector + ",  name='" + name + "', mep=" + messageExchangePattern + ", properties=" + properties
310                 + ", transactionConfig=" + transactionConfig + ", deleteUnacceptedMessages=" + deleteUnacceptedMessages
311                 + ", initialState=" + initialState + ", responseTimeout="
312                 + responseTimeout + ", endpointEncoding=" + endpointEncoding + ", disableTransportTransformer="
313                 + disableTransportTransformer + "}";
314     }
315 
316     public String getProtocol()
317     {
318         return connector.getProtocol();
319     }
320 
321     public TransactionConfig getTransactionConfig()
322     {
323         return transactionConfig;
324     }
325 
326     protected static boolean equal(Object a, Object b)
327     {
328         return ClassUtils.equal(a, b);
329     }
330 
331     @Override
332     public boolean equals(Object obj)
333     {
334         if (this == obj)
335         {
336             return true;
337         }
338         if (obj == null || getClass() != obj.getClass())
339         {
340             return false;
341         }
342 
343         final AbstractEndpoint other = (AbstractEndpoint) obj;
344         return equal(retryPolicyTemplate, other.retryPolicyTemplate)
345                 && equal(connector, other.connector)
346                 && deleteUnacceptedMessages == other.deleteUnacceptedMessages
347                 && equal(endpointEncoding, other.endpointEncoding)
348                 && equal(endpointUri, other.endpointUri)
349                 && equal(initialState, other.initialState)
350                 // don't include lifecycle state as lifecycle code includes hashing
351                 // && equal(initialised, other.initialised)
352                 && equal(messageExchangePattern, other.messageExchangePattern)
353                 && equal(name, other.name) 
354                 && equal(properties, other.properties)
355                 && responseTimeout == other.responseTimeout
356                 && equal(messageProcessors, other.messageProcessors)
357                 && equal(responseMessageProcessors, other.responseMessageProcessors)
358                 && equal(transactionConfig, other.transactionConfig)
359                 && disableTransportTransformer == other.disableTransportTransformer;
360     }
361 
362     @Override
363     public int hashCode()
364     {
365         return ClassUtils.hash(new Object[]{this.getClass(), retryPolicyTemplate, connector,
366                 deleteUnacceptedMessages ? Boolean.TRUE : Boolean.FALSE,
367                 endpointEncoding,
368                 endpointUri,
369                 initialState,
370                 // don't include lifecycle state as lifecycle code includes hashing
371                 // initialised,
372                 messageExchangePattern,
373                 name,
374                 properties, 
375                 Integer.valueOf(responseTimeout),
376                 responseMessageProcessors,
377                 transactionConfig,
378                 messageProcessors,
379                 disableTransportTransformer ? Boolean.TRUE : Boolean.FALSE});
380     }
381 
382     public Filter getFilter()
383     {
384         // Call the first MessageFilter in the chain "the filter".
385         for (MessageProcessor mp : messageProcessors)
386         {
387             if (mp instanceof MessageFilter)
388             {
389                 return ((MessageFilter) mp).getFilter();
390             }
391         }
392         return null;
393     }
394 
395     public boolean isDeleteUnacceptedMessages()
396     {
397         return deleteUnacceptedMessages;
398     }
399 
400     /**
401      * Returns an EndpointSecurityFilter for this endpoint. If one is not set, there
402      * will be no authentication on events sent via this endpoint
403      *
404      * @return EndpointSecurityFilter responsible for authenticating message flow via
405      *         this endpoint.
406      * @see org.mule.api.security.EndpointSecurityFilter
407      */
408     public EndpointSecurityFilter getSecurityFilter()
409     {
410         for (MessageProcessor mp : messageProcessors)
411         {
412             if (mp instanceof SecurityFilterMessageProcessor)
413             {
414                 return ((SecurityFilterMessageProcessor)mp).getFilter();
415             }
416         }
417 
418         return null;
419     }
420 
421     public MessageExchangePattern getExchangePattern()
422     {
423         return messageExchangePattern;
424     }
425 
426     /**
427      * The timeout value for remoteSync invocations
428      *
429      * @return the timeout in milliseconds
430      */
431     public int getResponseTimeout()
432     {
433         return responseTimeout;
434     }
435 
436     /**
437      * Sets the state the endpoint will be loaded in. The States are 'stopped' and
438      * 'started' (default)
439      *
440      * @return the endpoint starting state
441      */
442     public String getInitialState()
443     {
444         return initialState;
445     }
446 
447     /** @deprecated use getResponseMessageProcessors() */
448     public List<Transformer> getResponseTransformers()
449     {
450         return getTransformersFromProcessorList(responseMessageProcessors);
451     }
452 
453     private List<Transformer> getTransformersFromProcessorList(List<MessageProcessor> processors)
454     {
455         List<Transformer> transformers = new LinkedList<Transformer>();
456         for (MessageProcessor processor : processors)
457         {
458             if (processor instanceof Transformer)
459             {
460                 transformers.add((Transformer) processor);
461             }
462             else if (processor instanceof MessageProcessorChain)
463             {
464                 transformers.addAll(getTransformersFromProcessorList(((MessageProcessorChain) processor).getMessageProcessors()));
465             }
466         }
467         return transformers;
468     }
469 
470     public Object getProperty(Object key)
471     {
472         return properties.get(key);
473     }
474 
475     public MuleContext getMuleContext()
476     {
477         return muleContext;
478     }
479 
480     public RetryPolicyTemplate getRetryPolicyTemplate()
481     {
482         return retryPolicyTemplate;
483     }
484 
485     public String getEndpointBuilderName()
486     {
487         return endpointBuilderName;
488     }
489 
490     public boolean isProtocolSupported(String protocol)
491     {
492         return connector.supportsProtocol(protocol);
493     }
494     
495     public boolean isDisableTransportTransformer() 
496     {
497         return disableTransportTransformer;
498     }
499 
500     public void dispose()
501     {
502         this.muleContext = null;
503         this.messageProcessors.clear();
504         this.messageProcessorChain = null;
505     }
506 
507     public MessageProcessor getMessageProcessorChain(FlowConstruct flowContruct) throws MuleException
508     {
509         if (messageProcessorChain == null)
510         {
511             messageProcessorChain = createMessageProcessorChain(flowContruct);
512         }
513         return messageProcessorChain;
514     }
515 
516     abstract protected MessageProcessor createMessageProcessorChain(FlowConstruct flowContruct) throws MuleException;
517 }