001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.impl;
018
019 import java.lang.reflect.ParameterizedType;
020 import java.lang.reflect.Type;
021 import java.util.Map;
022 import java.util.regex.Pattern;
023
024 import org.apache.camel.CamelContext;
025 import org.apache.camel.CamelContextAware;
026 import org.apache.camel.Component;
027 import org.apache.camel.Endpoint;
028 import org.apache.camel.Exchange;
029 import org.apache.camel.ExchangePattern;
030 import org.apache.camel.PollingConsumer;
031 import org.apache.camel.spi.HasId;
032 import org.apache.camel.util.EndpointHelper;
033 import org.apache.camel.util.ObjectHelper;
034
035 /**
036 * A default endpoint useful for implementation inheritance.
037 * <p/>
038 * Components which leverages <a href="http://camel.apache.org/asynchronous-routing-engine.html">asynchronous processing model</a>
039 * should check the {@link #isSynchronous()} to determine if asynchronous processing is allowed.
040 * The <tt>synchronous</tt> option on the endpoint allows Camel end users to dictate whether they want the asynchronous model or not.
041 * The option is default <tt>false</tt> which means asynchronous processing is allowed.
042 *
043 * @version $Revision: 21168 $
044 */
045 public abstract class DefaultEndpoint implements Endpoint, HasId, CamelContextAware {
046
047 //Match any key-value pair in the URI query string whose key contains "passphrase" or "password" (case-insensitive).
048 //First capture group is the key, second is the value.
049 private static final Pattern SECRETS = Pattern.compile("([?&][^=]*(?:passphrase|password)[^=]*)=([^&]*)", Pattern.CASE_INSENSITIVE);
050
051 private String endpointUri;
052 private CamelContext camelContext;
053 private Component component;
054 private ExchangePattern exchangePattern = ExchangePattern.InOnly;
055 // option to allow end user to dictate whether async processing should be used or not (if possible)
056 private boolean synchronous;
057 private final String id = EndpointHelper.createEndpointId();
058
059 protected DefaultEndpoint(String endpointUri, Component component) {
060 this(endpointUri, component.getCamelContext());
061 this.component = component;
062 }
063
064 protected DefaultEndpoint(String endpointUri, CamelContext camelContext) {
065 this(endpointUri);
066 this.camelContext = camelContext;
067 }
068
069 protected DefaultEndpoint(String endpointUri) {
070 this.setEndpointUri(endpointUri);
071 }
072
073 protected DefaultEndpoint() {
074 super();
075 }
076
077 public int hashCode() {
078 return getEndpointUri().hashCode() * 37 + 1;
079 }
080
081 @Override
082 public boolean equals(Object object) {
083 if (object instanceof DefaultEndpoint) {
084 DefaultEndpoint that = (DefaultEndpoint) object;
085 return ObjectHelper.equal(this.getEndpointUri(), that.getEndpointUri());
086 }
087 return false;
088 }
089
090 @Override
091 public String toString() {
092 return String.format("Endpoint[%s]", sanitizeUri(getEndpointUri()));
093 }
094
095 /**
096 * Returns a unique String ID which can be used for aliasing without having to use the whole URI which
097 * is not unique
098 */
099 public String getId() {
100 return id;
101 }
102
103 public String getEndpointUri() {
104 if (endpointUri == null) {
105 endpointUri = createEndpointUri();
106 if (endpointUri == null) {
107 throw new IllegalArgumentException("endpointUri is not specified and " + getClass().getName()
108 + " does not implement createEndpointUri() to create a default value");
109 }
110 }
111 return endpointUri;
112 }
113
114 public String getEndpointKey() {
115 if (isLenientProperties()) {
116 // only use the endpoint uri without parameters as the properties is lenient
117 String uri = getEndpointUri();
118 if (uri.indexOf('?') != -1) {
119 return ObjectHelper.before(uri, "?");
120 } else {
121 return uri;
122 }
123 } else {
124 // use the full endpoint uri
125 return getEndpointUri();
126 }
127 }
128
129 public CamelContext getCamelContext() {
130 return camelContext;
131 }
132
133 public Component getComponent() {
134 return component;
135 }
136
137 public void setCamelContext(CamelContext camelContext) {
138 this.camelContext = camelContext;
139 }
140
141 public PollingConsumer createPollingConsumer() throws Exception {
142 return new EventDrivenPollingConsumer(this);
143 }
144
145 public Exchange createExchange(Exchange exchange) {
146 Class<Exchange> exchangeType = getExchangeType();
147 if (exchangeType != null) {
148 if (exchangeType.isInstance(exchange)) {
149 return exchangeType.cast(exchange);
150 }
151 }
152 return exchange.copy();
153 }
154
155 /**
156 * Returns the type of the exchange which is generated by this component
157 */
158 @SuppressWarnings("unchecked")
159 public Class<Exchange> getExchangeType() {
160 Type type = getClass().getGenericSuperclass();
161 if (type instanceof ParameterizedType) {
162 ParameterizedType parameterizedType = (ParameterizedType) type;
163 Type[] arguments = parameterizedType.getActualTypeArguments();
164 if (arguments.length > 0) {
165 Type argumentType = arguments[0];
166 if (argumentType instanceof Class) {
167 return (Class<Exchange>) argumentType;
168 }
169 }
170 }
171 return null;
172 }
173
174 public Exchange createExchange() {
175 return createExchange(getExchangePattern());
176 }
177
178 public Exchange createExchange(ExchangePattern pattern) {
179 return new DefaultExchange(this, pattern);
180 }
181
182 public ExchangePattern getExchangePattern() {
183 return exchangePattern;
184 }
185
186 public void setExchangePattern(ExchangePattern exchangePattern) {
187 this.exchangePattern = exchangePattern;
188 }
189
190 public boolean isSynchronous() {
191 return synchronous;
192 }
193
194 /**
195 * Sets whether synchronous processing should be strictly used, or Camel is allowed to use
196 * asynchronous processing (if supported).
197 *
198 * @param synchronous <tt>true</tt> to enforce synchronous processing
199 */
200 public void setSynchronous(boolean synchronous) {
201 this.synchronous = synchronous;
202 }
203
204 public void configureProperties(Map<String, Object> options) {
205 // do nothing by default
206 }
207
208 /**
209 * A factory method to lazily create the endpointUri if none is specified
210 */
211 protected String createEndpointUri() {
212 return null;
213 }
214
215 /**
216 * Sets the endpointUri if it has not been specified yet via some kind of dependency injection mechanism.
217 * This allows dependency injection frameworks such as Spring or Guice to set the default endpoint URI in cases
218 * where it has not been explicitly configured using the name/context in which an Endpoint is created.
219 */
220 public void setEndpointUriIfNotSpecified(String value) {
221 if (endpointUri == null) {
222 setEndpointUri(value);
223 }
224 }
225
226 protected void setEndpointUri(String endpointUri) {
227 this.endpointUri = endpointUri;
228 }
229
230 public boolean isLenientProperties() {
231 // default should be false for most components
232 return false;
233 }
234
235 public void start() throws Exception {
236 // noop
237 }
238
239 public void stop() throws Exception {
240 // noop
241 }
242
243 public static String sanitizeUri(String uri) {
244 return uri == null ? null : SECRETS.matcher(uri).replaceAll("$1=******");
245 }
246
247 }