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.net.URI; 020 import java.util.Map; 021 import java.util.concurrent.ScheduledExecutorService; 022 import java.util.concurrent.ScheduledThreadPoolExecutor; 023 import java.util.concurrent.ThreadFactory; 024 025 import org.apache.camel.CamelContext; 026 import org.apache.camel.Component; 027 import org.apache.camel.Endpoint; 028 import org.apache.camel.Exchange; 029 import org.apache.camel.ResolveEndpointFailedException; 030 import org.apache.camel.spi.Injector; 031 import org.apache.camel.spi.Registry; 032 import org.apache.camel.util.CamelContextHelper; 033 import org.apache.camel.util.IntrospectionSupport; 034 import org.apache.camel.util.ObjectHelper; 035 import org.apache.camel.util.URISupport; 036 import org.apache.camel.util.UnsafeUriCharactersEncoder; 037 import org.apache.commons.logging.Log; 038 import org.apache.commons.logging.LogFactory; 039 040 041 /** 042 * Default component to use for base for components implementations. 043 * 044 * @version $Revision: 54154 $ 045 */ 046 public abstract class DefaultComponent<E extends Exchange> extends ServiceSupport implements Component<E> { 047 private static final transient Log LOG = LogFactory.getLog(DefaultComponent.class); 048 049 private int defaultThreadPoolSize = 5; 050 private CamelContext camelContext; 051 private ScheduledExecutorService executorService; 052 053 public DefaultComponent() { 054 } 055 056 public DefaultComponent(CamelContext context) { 057 this.camelContext = context; 058 } 059 060 public Endpoint<E> createEndpoint(String uri) throws Exception { 061 ObjectHelper.notNull(getCamelContext(), "camelContext"); 062 //encode URI string to the unsafe URI characters 063 URI u = new URI(UnsafeUriCharactersEncoder.encode(uri)); 064 String path = u.getSchemeSpecificPart(); 065 066 // lets trim off any query arguments 067 if (path.startsWith("//")) { 068 path = path.substring(2); 069 } 070 int idx = path.indexOf('?'); 071 if (idx > 0) { 072 path = path.substring(0, idx); 073 } 074 Map parameters = URISupport.parseParameters(u); 075 076 validateURI(uri, path, parameters); 077 078 if (LOG.isDebugEnabled()) { 079 LOG.debug("Creating endpoint uri=[" + uri + "], path=[" + path + "], parameters=[" + parameters + "]"); 080 } 081 Endpoint<E> endpoint = createEndpoint(uri, path, parameters); 082 if (endpoint == null) { 083 return null; 084 } 085 086 if (parameters != null) { 087 endpoint.configureProperties(parameters); 088 if (useIntrospectionOnEndpoint()) { 089 setProperties(endpoint, parameters); 090 } 091 092 // if endpoint is strict (not lenient) and we have unknown parameters configured then 093 // fail if there are parameters that could not be set, then they are probably miss spelt or not supported at all 094 if (!endpoint.isLenientProperties() && parameters.size() > 0) { 095 throw new ResolveEndpointFailedException(uri, "There are " + parameters.size() 096 + " parameters that couldn't be set on the endpoint." 097 + " Check the uri if the parameters are spelt correctly and that they are properties of the endpoint." 098 + " Unknown parameters=[" + parameters + "]"); 099 } 100 } 101 102 return endpoint; 103 } 104 105 /** 106 * Strategy for validation of the uri when creating the endpoint. 107 * 108 * @param uri the uri - the uri the end user provided untouched 109 * @param path the path - part after the scheme 110 * @param parameters the parameters, an empty map if no parameters given 111 * @throws ResolveEndpointFailedException should be thrown if the URI validation failed 112 */ 113 protected void validateURI(String uri, String path, Map parameters) throws ResolveEndpointFailedException { 114 // check for uri containing & but no ? marker 115 if (uri.contains("&") && !uri.contains("?")) { 116 throw new ResolveEndpointFailedException(uri, "Invalid uri syntax: no ? marker however the uri " 117 + "has & parameter separators. Check the uri if its missing a ? marker."); 118 } 119 120 // check for uri containing double && markers 121 if (uri.contains("&&")) { 122 throw new ResolveEndpointFailedException(uri, "Invalid uri syntax: Double && marker found. " 123 + "Check the uri and remove the duplicate & marker."); 124 } 125 } 126 127 public CamelContext getCamelContext() { 128 return camelContext; 129 } 130 131 public void setCamelContext(CamelContext context) { 132 this.camelContext = context; 133 } 134 135 public ScheduledExecutorService getExecutorService() { 136 if (executorService == null) { 137 executorService = createExecutorService(); 138 } 139 return executorService; 140 } 141 142 public void setExecutorService(ScheduledExecutorService executorService) { 143 this.executorService = executorService; 144 } 145 146 /** 147 * A factory method to create a default thread pool and executor 148 */ 149 protected ScheduledExecutorService createExecutorService() { 150 return new ScheduledThreadPoolExecutor(defaultThreadPoolSize, new ThreadFactory() { 151 int counter; 152 153 public synchronized Thread newThread(Runnable runnable) { 154 Thread thread = new Thread(runnable); 155 thread.setName("Thread: " + (++counter) + " " + DefaultComponent.this.toString()); 156 return thread; 157 } 158 }); 159 } 160 161 protected void doStart() throws Exception { 162 ObjectHelper.notNull(getCamelContext(), "camelContext"); 163 } 164 165 protected void doStop() throws Exception { 166 if (executorService != null) { 167 executorService.shutdown(); 168 } 169 } 170 171 /** 172 * A factory method allowing derived components to create a new endpoint 173 * from the given URI, remaining path and optional parameters 174 * 175 * @param uri the full URI of the endpoint 176 * @param remaining the remaining part of the URI without the query 177 * parameters or component prefix 178 * @param parameters the optional parameters passed in 179 * @return a newly created endpoint or null if the endpoint cannot be 180 * created based on the inputs 181 */ 182 protected abstract Endpoint<E> createEndpoint(String uri, String remaining, Map parameters) 183 throws Exception; 184 185 /** 186 * Sets the bean properties on the given bean 187 */ 188 protected void setProperties(Object bean, Map parameters) throws Exception { 189 IntrospectionSupport.setProperties(getCamelContext().getTypeConverter(), bean, parameters); 190 } 191 192 /** 193 * Derived classes may wish to overload this to prevent the default introspection of URI parameters 194 * on the created Endpoint instance 195 */ 196 protected boolean useIntrospectionOnEndpoint() { 197 return true; 198 } 199 200 201 // Some helper methods 202 //------------------------------------------------------------------------- 203 204 /** 205 * Converts the given value to the requested type 206 */ 207 public <T> T convertTo(Class<T> type, Object value) { 208 return CamelContextHelper.convertTo(getCamelContext(), type, value); 209 } 210 211 /** 212 * Converts the given value to the specified type throwing an {@link IllegalArgumentException} 213 * if the value could not be converted to a non null value 214 */ 215 public <T> T mandatoryConvertTo(Class<T> type, Object value) { 216 return CamelContextHelper.mandatoryConvertTo(getCamelContext(), type, value); 217 } 218 219 /** 220 * Creates a new instance of the given type using the {@link Injector} on the given 221 * {@link CamelContext} 222 */ 223 public <T> T newInstance(Class<T> beanType) { 224 return getCamelContext().getInjector().newInstance(beanType); 225 } 226 227 /** 228 * Look up the given named bean in the {@link Registry} on the 229 * {@link CamelContext} 230 */ 231 public Object lookup(String name) { 232 return getCamelContext().getRegistry().lookup(name); 233 } 234 235 /** 236 * Look up the given named bean of the given type in the {@link Registry} on the 237 * {@link CamelContext} 238 */ 239 public <T> T lookup(String name, Class<T> beanType) { 240 return getCamelContext().getRegistry().lookup(name, beanType); 241 } 242 243 /** 244 * Look up the given named bean in the {@link Registry} on the 245 * {@link CamelContext} or throws 246 */ 247 public Object mandatoryLookup(String name) { 248 return CamelContextHelper.mandatoryLookup(getCamelContext(), name); 249 } 250 251 /** 252 * Look up the given named bean of the given type in the {@link Registry} on the 253 * {@link CamelContext} 254 */ 255 public <T> T mandatoryLookup(String name, Class<T> beanType) { 256 return CamelContextHelper.mandatoryLookup(getCamelContext(), name, beanType); 257 } 258 259 /** 260 * Gets the parameter and remove it from the parameter map. 261 * 262 * @param parameters the parameters 263 * @param key the key 264 * @param type the requested type to convert the value from the parameter 265 * @return the converted value parameter, <tt>null</tt> if parameter does not exists. 266 */ 267 public <T> T getAndRemoveParameter(Map parameters, String key, Class<T> type) { 268 return getAndRemoveParameter(parameters, key, type, null); 269 } 270 271 /** 272 * Gets the parameter and remove it from the parameter map. 273 * 274 * @param parameters the parameters 275 * @param key the key 276 * @param type the requested type to convert the value from the parameter 277 * @param defaultValue use this default value if the parameter does not contain the key 278 * @return the converted value parameter 279 */ 280 public <T> T getAndRemoveParameter(Map parameters, String key, Class<T> type, T defaultValue) { 281 Object value = parameters.remove(key); 282 if (value == null) { 283 value = defaultValue; 284 } 285 if (value == null) { 286 return null; 287 } 288 return convertTo(type, value); 289 } 290 291 }