View Javadoc

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