001: /*
002: * $Id: AbstractEndpoint.java 11319 2008-03-12 00:54:21Z aperepel $
003: * --------------------------------------------------------------------------------------
004: * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
005: *
006: * The software in this package is published under the terms of the CPAL v1.0
007: * license, a copy of which has been included with this distribution in the
008: * LICENSE.txt file.
009: */
010:
011: package org.mule.endpoint;
012:
013: import org.mule.api.MuleContext;
014: import org.mule.api.endpoint.EndpointURI;
015: import org.mule.api.endpoint.ImmutableEndpoint;
016: import org.mule.api.routing.filter.Filter;
017: import org.mule.api.security.EndpointSecurityFilter;
018: import org.mule.api.transaction.TransactionConfig;
019: import org.mule.api.transformer.Transformer;
020: import org.mule.api.transport.ConnectionStrategy;
021: import org.mule.api.transport.Connector;
022: import org.mule.util.ClassUtils;
023:
024: import java.net.URI;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029: import java.util.regex.Matcher;
030: import java.util.regex.Pattern;
031:
032: import edu.emory.mathcs.backport.java.util.Collections;
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035:
036: /**
037: * <code>ImmutableMuleEndpoint</code> describes a Provider in the Mule Server. A
038: * endpoint is a grouping of an endpoint, an endpointUri and a transformer.
039: */
040: public abstract class AbstractEndpoint implements ImmutableEndpoint {
041:
042: private static final long serialVersionUID = -1650380871293160973L;
043:
044: /**
045: * logger used by this class
046: */
047: protected static final Log logger = LogFactory
048: .getLog(AbstractEndpoint.class);
049:
050: /**
051: * The endpoint used to communicate with the external system
052: */
053: private final Connector connector;
054:
055: /**
056: * The endpointUri on which to send or receive information
057: */
058: private final EndpointURI endpointUri;
059:
060: /**
061: * The transformers used to transform the incoming or outgoing data
062: */
063: private final List transformers;
064:
065: /**
066: * The transformers used to transform the incoming or outgoing data
067: */
068: private final List responseTransformers;
069:
070: /**
071: * The name for the endpoint
072: */
073: private final String name;
074:
075: /**
076: * Any additional properties for the endpoint
077: * // TODO This should be final. See MULE-3105
078: * // TODO Shouldn't this be guarded from concurrent writes?
079: */
080: private Map properties = new HashMap();
081:
082: /**
083: * The transaction configuration for this endpoint
084: */
085: private final TransactionConfig transactionConfig;
086:
087: /**
088: * event filter for this endpoint
089: */
090: private final Filter filter;
091:
092: /**
093: * determines whether unaccepted filtered events should be removed from the
094: * source. If they are not removed its up to the Message receiver to handle
095: * recieving the same message again
096: */
097: private final boolean deleteUnacceptedMessages;
098:
099: /**
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, List transformers,
139: List responseTransformers, String name, Map properties,
140: TransactionConfig transactionConfig, Filter filter,
141: boolean deleteUnacceptedMessages,
142: EndpointSecurityFilter securityFilter, boolean synchronous,
143: boolean remoteSync, int remoteSyncTimeout,
144: String initialState, String endpointEncoding,
145: MuleContext muleContext,
146: ConnectionStrategy connectionStrategy) {
147: this .connector = connector;
148: this .endpointUri = endpointUri;
149: if (transformers == null) {
150: this .transformers = Collections
151: .unmodifiableList(java.util.Collections.EMPTY_LIST);
152: } else {
153: updateTransformerEndpoints(transformers);
154: this .transformers = Collections
155: .unmodifiableList(transformers);
156: }
157: if (responseTransformers == null) {
158: this .responseTransformers = Collections
159: .unmodifiableList(java.util.Collections.EMPTY_LIST);
160: } else {
161: updateTransformerEndpoints(responseTransformers);
162: this .responseTransformers = Collections
163: .unmodifiableList(responseTransformers);
164: }
165: this .name = name;
166: // TODO Properties should be immutable. See MULE-3105
167: // this.properties = Collections.unmodifiableMap(properties);
168: this .properties.putAll(properties);
169: this .transactionConfig = transactionConfig;
170: this .filter = filter;
171: this .deleteUnacceptedMessages = deleteUnacceptedMessages;
172: this .securityFilter = securityFilter;
173: if (this .securityFilter != null) {
174: this .securityFilter.setEndpoint(this );
175: }
176: this .synchronous = synchronous;
177: this .remoteSync = remoteSync;
178: this .remoteSyncTimeout = remoteSyncTimeout;
179: this .initialState = initialState;
180: this .endpointEncoding = endpointEncoding;
181: this .muleContext = muleContext;
182: this .connectionStrategy = connectionStrategy;
183: }
184:
185: public EndpointURI getEndpointURI() {
186: return endpointUri;
187: }
188:
189: public String getEncoding() {
190: return endpointEncoding;
191: }
192:
193: public Connector getConnector() {
194: return connector;
195: }
196:
197: public String getName() {
198: return name;
199: }
200:
201: public List getTransformers() {
202: return transformers;
203: }
204:
205: public Map getProperties() {
206: return properties;
207: }
208:
209: public boolean isReadOnly() {
210: return true;
211: }
212:
213: public String toString() {
214: // Use the interface to retrieve the string and set
215: // the endpoint uri to a default value
216: String sanitizedEndPointUri = null;
217: URI uri = null;
218: if (endpointUri != null) {
219: sanitizedEndPointUri = endpointUri.toString();
220: uri = endpointUri.getUri();
221: }
222: // The following will further sanitize the endpointuri by removing
223: // the embedded password. This will only remove the password if the
224: // uri contains all the necessary information to successfully rebuild the url
225: if (uri != null && (uri.getRawUserInfo() != null)
226: && (uri.getScheme() != null) && (uri.getHost() != null)
227: && (uri.getRawPath() != null)) {
228: // build a pattern up that matches what we need tp strip out the password
229: Pattern sanitizerPattern = Pattern.compile("(.*):.*");
230: Matcher sanitizerMatcher = sanitizerPattern.matcher(uri
231: .getRawUserInfo());
232: if (sanitizerMatcher.matches()) {
233: sanitizedEndPointUri = new StringBuffer(uri.getScheme())
234: .append("://")
235: .append(sanitizerMatcher.group(1)).append(
236: ":<password>").append("@").append(
237: uri.getHost()).append(uri.getRawPath())
238: .toString();
239: }
240: if (uri.getRawQuery() != null) {
241: sanitizedEndPointUri = sanitizedEndPointUri + "?"
242: + uri.getRawQuery();
243: }
244:
245: }
246:
247: return ClassUtils.getClassName(getClass()) + "{endpointUri="
248: + sanitizedEndPointUri + ", connector=" + connector
249: + ", transformer=" + transformers + ", name='" + name
250: + "'" + ", properties=" + properties
251: + ", transactionConfig=" + transactionConfig
252: + ", filter=" + filter + ", deleteUnacceptedMessages="
253: + deleteUnacceptedMessages + ", securityFilter="
254: + securityFilter + ", synchronous=" + synchronous
255: + ", initialState=" + initialState + ", remoteSync="
256: + remoteSync + ", remoteSyncTimeout="
257: + remoteSyncTimeout + ", endpointEncoding="
258: + endpointEncoding + "}";
259: }
260:
261: public String getProtocol() {
262: return connector.getProtocol();
263: }
264:
265: public TransactionConfig getTransactionConfig() {
266: return transactionConfig;
267: }
268:
269: protected static boolean equal(Object a, Object b) {
270: return ClassUtils.equal(a, b);
271: }
272:
273: public boolean equals(Object obj) {
274: if (this == obj)
275: return true;
276: if (obj == null || getClass() != obj.getClass())
277: return false;
278:
279: final AbstractEndpoint other = (AbstractEndpoint) obj;
280: return equal(connectionStrategy, other.connectionStrategy)
281: && equal(connector, other.connector)
282: && deleteUnacceptedMessages == other.deleteUnacceptedMessages
283: && equal(endpointEncoding, other.endpointEncoding)
284: && equal(endpointUri, other.endpointUri)
285: && equal(filter, other.filter)
286: && equal(initialState, other.initialState)
287: // don't include lifecycle state as lifecycle code includes hashing
288: // && equal(initialised, other.initialised)
289: && equal(name, other.name)
290: && equal(properties, other.properties)
291: && remoteSync == other.remoteSync
292: && remoteSyncTimeout == other.remoteSyncTimeout
293: && equal(responseTransformers,
294: other.responseTransformers)
295: && equal(securityFilter, other.securityFilter)
296: && synchronous == other.synchronous
297: && equal(transactionConfig, other.transactionConfig)
298: && equal(transformers, other.transformers);
299: }
300:
301: public int hashCode() {
302: return ClassUtils
303: .hash(new Object[] {
304: this .getClass(),
305: connectionStrategy,
306: connector,
307: deleteUnacceptedMessages ? Boolean.TRUE
308: : Boolean.FALSE,
309: endpointEncoding,
310: endpointUri,
311: filter,
312: initialState,
313: // don't include lifecycle state as lifecycle code includes hashing
314: // initialised,
315: name, properties,
316: remoteSync ? Boolean.TRUE : Boolean.FALSE,
317: new Integer(remoteSyncTimeout),
318: responseTransformers, securityFilter,
319: synchronous ? Boolean.TRUE : Boolean.FALSE,
320: transactionConfig, transformers });
321: }
322:
323: public Filter getFilter() {
324: return filter;
325: }
326:
327: public boolean isDeleteUnacceptedMessages() {
328: return deleteUnacceptedMessages;
329: }
330:
331: // TODO - remove (or fix)
332: protected void updateTransformerEndpoints(List transformers) {
333: Iterator transformer = transformers.iterator();
334: while (transformer.hasNext()) {
335: ((Transformer) transformer.next()).setEndpoint(this );
336: }
337: }
338:
339: /**
340: * Returns an EndpointSecurityFilter for this endpoint. If one is not set, there
341: * will be no authentication on events sent via this endpoint
342: *
343: * @return EndpointSecurityFilter responsible for authenticating message flow via
344: * this endpoint.
345: * @see org.mule.api.security.EndpointSecurityFilter
346: */
347: public EndpointSecurityFilter getSecurityFilter() {
348: return securityFilter;
349: }
350:
351: /**
352: * Determines if requests originating from this endpoint should be synchronous
353: * i.e. execute in a single thread and possibly return an result. This property
354: * is only used when the endpoint is of type 'receiver'
355: *
356: * @return whether requests on this endpoint should execute in a single thread.
357: * This property is only used when the endpoint is of type 'receiver'
358: */
359: public boolean isSynchronous() {
360: return synchronous;
361: }
362:
363: /**
364: * For certain providers that support the notion of a backchannel such as sockets
365: * (outputStream) or Jms (ReplyTo) Mule can automatically wait for a response
366: * from a backchannel when dispatching over these protocols. This is different
367: * for synchronous as synchronous behavior only applies to in
368: *
369: * @return
370: */
371: public boolean isRemoteSync() {
372: return remoteSync;
373: }
374:
375: /**
376: * The timeout value for remoteSync invocations
377: *
378: * @return the timeout in milliseconds
379: */
380: public int getRemoteSyncTimeout() {
381: return remoteSyncTimeout;
382: }
383:
384: /**
385: * Sets the state the endpoint will be loaded in. The States are 'stopped' and
386: * 'started' (default)
387: *
388: * @return the endpoint starting state
389: */
390: public String getInitialState() {
391: return initialState;
392: }
393:
394: public List getResponseTransformers() {
395: return responseTransformers;
396: }
397:
398: public Object getProperty(Object key) {
399: return properties.get(key);
400: }
401:
402: public MuleContext getMuleContext() {
403: return muleContext;
404: }
405:
406: /**
407: * Getter for property 'connectionStrategy'.
408: *
409: * @return Value for property 'connectionStrategy'.
410: */
411: public ConnectionStrategy getConnectionStrategy() {
412: return connectionStrategy;
413: }
414:
415: }
|