View Javadoc

1   /*
2    * $Id: AbstractEndpoint.java 11319 2008-03-12 00:54:21Z aperepel $
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.endpoint;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.endpoint.EndpointURI;
15  import org.mule.api.endpoint.ImmutableEndpoint;
16  import org.mule.api.routing.filter.Filter;
17  import org.mule.api.security.EndpointSecurityFilter;
18  import org.mule.api.transaction.TransactionConfig;
19  import org.mule.api.transformer.Transformer;
20  import org.mule.api.transport.ConnectionStrategy;
21  import org.mule.api.transport.Connector;
22  import org.mule.util.ClassUtils;
23  
24  import java.net.URI;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.regex.Matcher;
30  import java.util.regex.Pattern;
31  
32  import edu.emory.mathcs.backport.java.util.Collections;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  /**
37   * <code>ImmutableMuleEndpoint</code> describes a Provider in the Mule Server. A
38   * endpoint is a grouping of an endpoint, an endpointUri and a transformer.
39   */
40  public abstract class AbstractEndpoint implements ImmutableEndpoint
41  {
42  
43      private static final long serialVersionUID = -1650380871293160973L;
44  
45      /**
46       * logger used by this class
47       */
48      protected static final Log logger = LogFactory.getLog(AbstractEndpoint.class);
49  
50      /**
51       * The endpoint used to communicate with the external system
52       */
53      private final Connector connector;
54  
55      /**
56       * The endpointUri on which to send or receive information
57       */
58      private final EndpointURI endpointUri;
59  
60      /**
61       * The transformers used to transform the incoming or outgoing data
62       */
63      private final List transformers;
64  
65      /**
66       * The transformers used to transform the incoming or outgoing data
67       */
68      private final List responseTransformers;
69  
70      /**
71       * The name for the endpoint
72       */
73      private final String name;
74  
75      /**
76       * Any additional properties for the endpoint 
77       * // TODO This should be final. See MULE-3105
78       * // TODO Shouldn't this be guarded from concurrent writes?
79       */
80      private Map properties = new HashMap();
81  
82      /**
83       * The transaction configuration for this endpoint
84       */
85      private final TransactionConfig transactionConfig;
86  
87      /**
88       * event filter for this endpoint
89       */
90      private final Filter filter;
91  
92      /**
93       * determines whether unaccepted filtered events should be removed from the
94       * source. If they are not removed its up to the Message receiver to handle
95       * recieving the same message again
96       */
97      private final boolean deleteUnacceptedMessages;
98  
99      /**
100      * The security filter to apply to this endpoint
101      */
102     private final EndpointSecurityFilter securityFilter;
103 
104     /**
105      * whether events received by this endpoint should execute in a single thread
106      */
107     private final boolean synchronous;
108 
109     /**
110      * Determines whether a synchronous call should block to obtain a response from a
111      * remote server (if the transport supports it). For example for Jms endpoints,
112      * setting remote sync will cause a temporary destination to be set up as a
113      * replyTo destination and will send the message a wait for a response on the
114      * replyTo destination. If the JMSReplyTo is already set on the message that
115      * destination will be used instead.
116      */
117     private final boolean remoteSync;
118 
119     /**
120      * How long to block when performing a remote synchronisation to a remote host.
121      * This property is optional and will be set to the default Synchonous MuleEvent
122      * time out value if not set
123      */
124     private final int remoteSyncTimeout;
125 
126     /**
127      * The state that the endpoint is initialised in such as started or stopped
128      */
129     private final String initialState;
130 
131     private final String endpointEncoding;
132 
133     private final MuleContext muleContext;
134 
135     private final ConnectionStrategy connectionStrategy;
136 
137     public AbstractEndpoint(Connector connector,
138                             EndpointURI endpointUri,
139                             List transformers,
140                             List responseTransformers,
141                             String name,
142                             Map properties,
143                             TransactionConfig transactionConfig,
144                             Filter filter,
145                             boolean deleteUnacceptedMessages,
146                             EndpointSecurityFilter securityFilter,
147                             boolean synchronous,
148                             boolean remoteSync,
149                             int remoteSyncTimeout,
150                             String initialState,
151                             String endpointEncoding,
152                             MuleContext muleContext,
153                             ConnectionStrategy connectionStrategy)
154     {
155         this.connector = connector;
156         this.endpointUri = endpointUri;
157         if (transformers == null)
158         {
159             this.transformers = Collections.unmodifiableList(java.util.Collections.EMPTY_LIST);
160         }
161         else
162         {
163             updateTransformerEndpoints(transformers);
164             this.transformers = Collections.unmodifiableList(transformers);
165         }
166         if (responseTransformers == null)
167         {
168             this.responseTransformers = Collections.unmodifiableList(java.util.Collections.EMPTY_LIST);
169         }
170         else
171         {
172             updateTransformerEndpoints(responseTransformers);
173             this.responseTransformers = Collections.unmodifiableList(responseTransformers);
174         }
175         this.name = name;
176         // TODO Properties should be immutable. See MULE-3105
177         // this.properties = Collections.unmodifiableMap(properties);
178         this.properties.putAll(properties);
179         this.transactionConfig = transactionConfig;
180         this.filter = filter;
181         this.deleteUnacceptedMessages = deleteUnacceptedMessages;
182         this.securityFilter = securityFilter;
183         if (this.securityFilter != null)
184         {
185             this.securityFilter.setEndpoint(this);
186         }
187         this.synchronous = synchronous;
188         this.remoteSync = remoteSync;
189         this.remoteSyncTimeout = remoteSyncTimeout;
190         this.initialState = initialState;
191         this.endpointEncoding = endpointEncoding;
192         this.muleContext = muleContext;
193         this.connectionStrategy = connectionStrategy;
194     }
195 
196     public EndpointURI getEndpointURI()
197     {
198         return endpointUri;
199     }
200 
201     public String getEncoding()
202     {
203         return endpointEncoding;
204     }
205 
206     public Connector getConnector()
207     {
208         return connector;
209     }
210 
211     public String getName()
212     {
213         return name;
214     }
215 
216     public List getTransformers()
217     {
218         return transformers;
219     }
220 
221     public Map getProperties()
222     {
223         return properties;
224     }
225 
226     public boolean isReadOnly()
227     {
228         return true;
229     }
230 
231     public String toString()
232     {
233         // Use the interface to retrieve the string and set
234         // the endpoint uri to a default value
235         String sanitizedEndPointUri = null;
236         URI uri = null;
237         if (endpointUri != null)
238         {
239             sanitizedEndPointUri = endpointUri.toString();
240             uri = endpointUri.getUri();
241         }
242         // The following will further sanitize the endpointuri by removing
243         // the embedded password. This will only remove the password if the
244         // uri contains all the necessary information to successfully rebuild the url
245         if (uri != null && (uri.getRawUserInfo() != null) && (uri.getScheme() != null) && (uri.getHost() != null)
246             && (uri.getRawPath() != null))
247         {
248             // build a pattern up that matches what we need tp strip out the password
249             Pattern sanitizerPattern = Pattern.compile("(.*):.*");
250             Matcher sanitizerMatcher = sanitizerPattern.matcher(uri.getRawUserInfo());
251             if (sanitizerMatcher.matches())
252             {
253                 sanitizedEndPointUri = new StringBuffer(uri.getScheme()).append("://")
254                     .append(sanitizerMatcher.group(1))
255                     .append(":<password>")
256                     .append("@")
257                     .append(uri.getHost())
258                     .append(uri.getRawPath())
259                     .toString();
260             }
261             if (uri.getRawQuery() != null)
262             {
263                 sanitizedEndPointUri = sanitizedEndPointUri + "?" + uri.getRawQuery();
264             }
265 
266         }
267 
268         return ClassUtils.getClassName(getClass()) + "{endpointUri=" + sanitizedEndPointUri + ", connector="
269                + connector + ", transformer=" + transformers + ", name='" + name + "'" + ", properties=" + properties
270                + ", transactionConfig=" + transactionConfig + ", filter=" + filter + ", deleteUnacceptedMessages="
271                + deleteUnacceptedMessages + ", securityFilter=" + securityFilter + ", synchronous=" + synchronous
272                + ", initialState=" + initialState + ", remoteSync=" + remoteSync + ", remoteSyncTimeout="
273                + remoteSyncTimeout + ", endpointEncoding=" + endpointEncoding + "}";
274     }
275 
276     public String getProtocol()
277     {
278         return connector.getProtocol();
279     }
280 
281     public TransactionConfig getTransactionConfig()
282     {
283         return transactionConfig;
284     }
285 
286     protected static boolean equal(Object a, Object b)
287     {
288         return ClassUtils.equal(a, b);
289     }
290 
291     public boolean equals(Object obj)
292     {
293         if (this == obj) return true;
294         if (obj == null || getClass() != obj.getClass()) return false;
295 
296         final AbstractEndpoint other = (AbstractEndpoint) obj;
297         return equal(connectionStrategy, other.connectionStrategy)
298                && equal(connector, other.connector)
299                && deleteUnacceptedMessages == other.deleteUnacceptedMessages
300                && equal(endpointEncoding, other.endpointEncoding)
301                && equal(endpointUri, other.endpointUri)
302                && equal(filter, other.filter)
303                && equal(initialState, other.initialState)
304                // don't include lifecycle state as lifecycle code includes hashing
305                // && equal(initialised, other.initialised)
306                && equal(name, other.name) && equal(properties, other.properties) && remoteSync == other.remoteSync
307                && remoteSyncTimeout == other.remoteSyncTimeout
308                && equal(responseTransformers, other.responseTransformers)
309                && equal(securityFilter, other.securityFilter) && synchronous == other.synchronous
310                && equal(transactionConfig, other.transactionConfig) && equal(transformers, other.transformers);
311     }
312 
313     public int hashCode()
314     {
315         return ClassUtils.hash(new Object[]{this.getClass(), connectionStrategy, connector,
316             deleteUnacceptedMessages ? Boolean.TRUE : Boolean.FALSE,
317             endpointEncoding,
318             endpointUri,
319             filter,
320             initialState,
321             // don't include lifecycle state as lifecycle code includes hashing
322             // initialised,
323             name, properties, remoteSync ? Boolean.TRUE : Boolean.FALSE, new Integer(remoteSyncTimeout),
324             responseTransformers, securityFilter, synchronous ? Boolean.TRUE : Boolean.FALSE, transactionConfig,
325             transformers});
326     }
327 
328     public Filter getFilter()
329     {
330         return filter;
331     }
332 
333     public boolean isDeleteUnacceptedMessages()
334     {
335         return deleteUnacceptedMessages;
336     }
337 
338     // TODO - remove (or fix)
339     protected void updateTransformerEndpoints(List transformers)
340     {
341         Iterator transformer = transformers.iterator();
342         while (transformer.hasNext())
343         {
344             ((Transformer) transformer.next()).setEndpoint(this);
345         }
346     }
347 
348     /**
349      * Returns an EndpointSecurityFilter for this endpoint. If one is not set, there
350      * will be no authentication on events sent via this endpoint
351      * 
352      * @return EndpointSecurityFilter responsible for authenticating message flow via
353      *         this endpoint.
354      * @see org.mule.api.security.EndpointSecurityFilter
355      */
356     public EndpointSecurityFilter getSecurityFilter()
357     {
358         return securityFilter;
359     }
360 
361     /**
362      * Determines if requests originating from this endpoint should be synchronous
363      * i.e. execute in a single thread and possibly return an result. This property
364      * is only used when the endpoint is of type 'receiver'
365      * 
366      * @return whether requests on this endpoint should execute in a single thread.
367      *         This property is only used when the endpoint is of type 'receiver'
368      */
369     public boolean isSynchronous()
370     {
371         return synchronous;
372     }
373 
374     /**
375      * For certain providers that support the notion of a backchannel such as sockets
376      * (outputStream) or Jms (ReplyTo) Mule can automatically wait for a response
377      * from a backchannel when dispatching over these protocols. This is different
378      * for synchronous as synchronous behavior only applies to in
379      * 
380      * @return
381      */
382     public boolean isRemoteSync()
383     {
384         return remoteSync;
385     }
386 
387     /**
388      * The timeout value for remoteSync invocations
389      * 
390      * @return the timeout in milliseconds
391      */
392     public int getRemoteSyncTimeout()
393     {
394         return remoteSyncTimeout;
395     }
396 
397     /**
398      * Sets the state the endpoint will be loaded in. The States are 'stopped' and
399      * 'started' (default)
400      * 
401      * @return the endpoint starting state
402      */
403     public String getInitialState()
404     {
405         return initialState;
406     }
407 
408     public List getResponseTransformers()
409     {
410         return responseTransformers;
411     }
412 
413     public Object getProperty(Object key)
414     {
415         return properties.get(key);
416     }
417 
418     public MuleContext getMuleContext()
419     {
420         return muleContext;
421     }
422 
423     /**
424      * Getter for property 'connectionStrategy'.
425      * 
426      * @return Value for property 'connectionStrategy'.
427      */
428     public ConnectionStrategy getConnectionStrategy()
429     {
430         return connectionStrategy;
431     }
432 
433 }