/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.component.jetty; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.Filter; import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.ResolveEndpointFailedException; import org.apache.camel.http.common.HttpCommonEndpoint; import org.apache.camel.http.common.HttpConsumer; import org.apache.camel.http.common.cookie.CookieHandler; import org.apache.camel.impl.SynchronousDelegateProducer; import org.apache.camel.spi.UriParam; import org.apache.camel.util.IntrospectionSupport; import org.apache.camel.util.jsse.SSLContextParameters; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.server.Handler; /** * @version */ public abstract class JettyHttpEndpoint extends HttpCommonEndpoint { @UriParam(label = "producer,advanced", description = "Sets a shared HttpClient to use for all producers created by this endpoint. By default each producer will" + " use a new http client, and not share. Important: Make sure to handle the lifecycle of the shared" + " client, such as stopping the client, when it is no longer in use. Camel will call the start method on the client to ensure" + " its started when this endpoint creates a producer. This options should only be used in special circumstances.") private HttpClient httpClient; @UriParam(label = "consumer", description = "Specifies whether to enable the session manager on the server side of Jetty.") private boolean sessionSupport; @UriParam(label = "producer", defaultValue = "8", description = "To set a value for minimum number of threads in HttpClient thread pool." + " This setting override any setting configured on component level." + " Notice that both a min and max size must be configured. If not set it default to min 8 threads used in Jettys thread pool.") private Integer httpClientMinThreads; @UriParam(label = "producer", defaultValue = "254", description = "To set a value for maximum number of threads in HttpClient thread pool." + " This setting override any setting configured on component level." + " Notice that both a min and max size must be configured. If not set it default to max 254 threads used in Jettys thread pool.") private Integer httpClientMaxThreads; @UriParam(label = "consumer", description = "If this option is true, Jetty JMX support will be enabled for this endpoint. See Jetty JMX support for more details.") private boolean enableJmx; @UriParam(description = "Whether Jetty org.eclipse.jetty.servlets.MultiPartFilter is enabled or not." + " You should set this value to false when bridging endpoints, to ensure multipart requests is proxied/bridged as well.") private boolean enableMultipartFilter; @UriParam(label = "consumer", defaultValue = "true", description = "If the option is true, jetty will send the server header with the jetty version information to the client which sends the request." + " NOTE please make sure there is no any other camel-jetty endpoint is share the same port, otherwise this option may not work as expected.") private boolean sendServerVersion = true; @UriParam(label = "consumer", description = "If the option is true, jetty server will send the date header to the client which sends the request." + " NOTE please make sure there is no any other camel-jetty endpoint is share the same port, otherwise this option may not work as expected.") private boolean sendDateHeader; @UriParam(label = "consumer", defaultValue = "30000", description = "Allows to set a timeout in millis when using Jetty as consumer (server)." + " By default Jetty uses 30000. You can use a value of <= 0 to never expire." + " If a timeout occurs then the request will be expired and Jetty will return back a http error 503 to the client." + " This option is only in use when using Jetty with the Asynchronous Routing Engine.") private Long continuationTimeout; @UriParam(label = "consumer", description = "Whether or not to use Jetty continuations for the Jetty Server.") private Boolean useContinuation; @UriParam(label = "consumer", description = "If the option is true, Jetty server will setup the CrossOriginFilter which supports the CORS out of box.") private boolean enableCORS; @UriParam(label = "producer,advanced", prefix = "httpClient.", multiValue = true, description = "Configuration of Jetty's HttpClient. For example, setting httpClient.idleTimeout=30000 sets the idle timeout to 30 seconds." + " And httpClient.timeout=30000 sets the request timeout to 30 seconds, in case you want to timeout sooner if you have long running request/response calls.") private Map<String, Object> httpClientParameters; @UriParam(label = "consumer,advanced", javaType = "java.lang.String", description = "Specifies a comma-delimited set of Handler instances to lookup in your Registry." + " These handlers are added to the Jetty servlet context (for example, to add security)." + " Important: You can not use different handlers with different Jetty endpoints using the same port number." + " The handlers is associated to the port number. If you need different handlers, then use different port numbers.") private List<Handler> handlers; @UriParam(label = "consumer,advanced", javaType = "java.lang.String", name = "filtersRef", description = "Allows using a custom filters which is putted into a list and can be find in the Registry." + " Multiple values can be separated by comma.") private List<Filter> filters; @UriParam(label = "consumer,advanced", prefix = "filter.", multiValue = true, description = "Configuration of the filter init parameters. These parameters will be applied to the filter list before starting the jetty server.") private Map<String, String> filterInitParameters; @UriParam(label = "producer,advanced", description = "To use a custom JettyHttpBinding which be used to customize how a response should be written for the producer.") private JettyHttpBinding jettyBinding; @UriParam(label = "producer,advanced", description = "To use a custom JettyHttpBinding which be used to customize how a response should be written for the producer.") @Deprecated private String jettyBindingRef; @UriParam(label = "consumer,advanced", description = "Option to disable throwing the HttpOperationFailedException in case of failed responses from the remote server." + " This allows you to get all responses regardless of the HTTP status code.") @Deprecated private String httpBindingRef; @UriParam(label = "consumer,advanced", description = "Allows using a custom multipart filter. Note: setting multipartFilterRef forces the value of enableMultipartFilter to true.") private Filter multipartFilter; @UriParam(label = "consumer,advanced", description = "Allows using a custom multipart filter. Note: setting multipartFilterRef forces the value of enableMultipartFilter to true.") @Deprecated private String multipartFilterRef; @UriParam(label = "security", description = "To configure security using SSLContextParameters") private SSLContextParameters sslContextParameters; @UriParam(label = "producer", description = "Configure a cookie handler to maintain a HTTP session") private CookieHandler cookieHandler; public JettyHttpEndpoint(JettyHttpComponent component, String uri, URI httpURL) throws URISyntaxException { super(uri, component, httpURL); } @Override public JettyHttpComponent getComponent() { return (JettyHttpComponent) super.getComponent(); } @Override public Producer createProducer() throws Exception { JettyHttpProducer answer = new JettyHttpProducer(this); if (httpClient != null) { // use shared client, and ensure its started so we can use it httpClient.start(); answer.setSharedClient(httpClient); answer.setBinding(getJettyBinding(httpClient)); } else { HttpClient httpClient = createJettyHttpClient(); answer.setClient(httpClient); answer.setBinding(getJettyBinding(httpClient)); } if (isSynchronous()) { return new SynchronousDelegateProducer(answer); } else { return answer; } } protected HttpClient createJettyHttpClient() throws Exception { // create a new client // thread pool min/max from endpoint take precedence over from component Integer min = httpClientMinThreads != null ? httpClientMinThreads : getComponent().getHttpClientMinThreads(); Integer max = httpClientMaxThreads != null ? httpClientMaxThreads : getComponent().getHttpClientMaxThreads(); HttpClient httpClient = getComponent().createHttpClient(this, min, max, sslContextParameters); // set optional http client parameters if (httpClientParameters != null) { // copy parameters as we need to re-use them again if creating a new producer later Map<String, Object> params = new HashMap<String, Object>(httpClientParameters); // Can not be set on httpClient for jetty 9 params.remove("timeout"); IntrospectionSupport.setProperties(httpClient, params); // validate we could set all parameters if (params.size() > 0) { throw new ResolveEndpointFailedException(getEndpointUri(), "There are " + params.size() + " parameters that couldn't be set on the endpoint." + " Check the uri if the parameters are spelt correctly and that they are properties of the endpoint." + " Unknown parameters=[" + params + "]"); } } return httpClient; } @Override public Consumer createConsumer(Processor processor) throws Exception { HttpConsumer answer = new HttpConsumer(this, processor); configureConsumer(answer); return answer; } /** * Specifies whether to enable the session manager on the server side of Jetty. */ public void setSessionSupport(boolean support) { sessionSupport = support; } public boolean isSessionSupport() { return sessionSupport; } public List<Handler> getHandlers() { return handlers; } /** * Specifies a comma-delimited set of org.mortbay.jetty.Handler instances in your Registry (such as your Spring ApplicationContext). * These handlers are added to the Jetty servlet context (for example, to add security). * Important: You can not use different handlers with different Jetty endpoints using the same port number. * The handlers is associated to the port number. If you need different handlers, then use different port numbers. */ public void setHandlers(List<Handler> handlers) { this.handlers = handlers; } public HttpClient getHttpClient() throws Exception { return httpClient; } /** * Sets a shared {@link HttpClient} to use for all producers * created by this endpoint. By default each producer will * use a new http client, and not share. * <p/> * <b>Important: </b> Make sure to handle the lifecycle of the shared * client, such as stopping the client, when it is no longer in use. * Camel will call the <tt>start</tt> method on the client to ensure * its started when this endpoint creates a producer. * <p/> * This options should only be used in special circumstances. */ public void setHttpClient(HttpClient httpClient) { this.httpClient = httpClient; } public synchronized JettyHttpBinding getJettyBinding(HttpClient httpClient) { if (jettyBinding == null) { jettyBinding = new DefaultJettyHttpBinding(); jettyBinding.setHeaderFilterStrategy(getHeaderFilterStrategy()); jettyBinding.setThrowExceptionOnFailure(isThrowExceptionOnFailure()); jettyBinding.setTransferException(isTransferException()); if (getComponent() != null) { jettyBinding.setAllowJavaSerializedObject(getComponent().isAllowJavaSerializedObject()); } jettyBinding.setOkStatusCodeRange(getOkStatusCodeRange()); } return jettyBinding; } /** * To use a custom JettyHttpBinding which be used to customize how a response should be written for the producer. */ public void setJettyBinding(JettyHttpBinding jettyBinding) { this.jettyBinding = jettyBinding; } public boolean isEnableJmx() { return this.enableJmx; } /** * If this option is true, Jetty JMX support will be enabled for this endpoint. See Jetty JMX support for more details. */ public void setEnableJmx(boolean enableJmx) { this.enableJmx = enableJmx; } public boolean isSendServerVersion() { return sendServerVersion; } /** * If the option is true, jetty will send the server header with the jetty version information to the client which sends the request. * NOTE please make sure there is no any other camel-jetty endpoint is share the same port, otherwise this option may not work as expected. */ public void setSendServerVersion(boolean sendServerVersion) { this.sendServerVersion = sendServerVersion; } public boolean isSendDateHeader() { return sendDateHeader; } /** * If the option is true, jetty server will send the date header to the client which sends the request. * NOTE please make sure there is no any other camel-jetty endpoint is share the same port, otherwise this option may not work as expected. */ public void setSendDateHeader(boolean sendDateHeader) { this.sendDateHeader = sendDateHeader; } public boolean isEnableMultipartFilter() { return enableMultipartFilter; } /** * Whether Jetty org.eclipse.jetty.servlets.MultiPartFilter is enabled or not. * You should set this value to false when bridging endpoints, to ensure multipart requests is proxied/bridged as well. */ public void setEnableMultipartFilter(boolean enableMultipartFilter) { this.enableMultipartFilter = enableMultipartFilter; } /** * Allows using a custom multipart filter. Note: setting multipartFilter forces the value of enableMultipartFilter to true. */ public void setMultipartFilter(Filter filter) { this.multipartFilter = filter; } public Filter getMultipartFilter() { return multipartFilter; } /** * Allows using a custom filters which is putted into a list and can be find in the Registry. * Multiple values can be separated by comma. */ public void setFilters(List<Filter> filterList) { this.filters = filterList; } public List<Filter> getFilters() { return filters; } public Long getContinuationTimeout() { return continuationTimeout; } /** * Allows to set a timeout in millis when using Jetty as consumer (server). * By default Jetty uses 30000. You can use a value of <= 0 to never expire. * If a timeout occurs then the request will be expired and Jetty will return back a http error 503 to the client. * This option is only in use when using Jetty with the Asynchronous Routing Engine. */ public void setContinuationTimeout(Long continuationTimeout) { this.continuationTimeout = continuationTimeout; } public Boolean getUseContinuation() { return useContinuation; } /** * Whether or not to use Jetty continuations for the Jetty Server. */ public void setUseContinuation(Boolean useContinuation) { this.useContinuation = useContinuation; } public SSLContextParameters getSslContextParameters() { return sslContextParameters; } /** * To configure security using SSLContextParameters */ public void setSslContextParameters(SSLContextParameters sslContextParameters) { this.sslContextParameters = sslContextParameters; } public Integer getHttpClientMinThreads() { return httpClientMinThreads; } /** * To set a value for minimum number of threads in HttpClient thread pool. * This setting override any setting configured on component level. * Notice that both a min and max size must be configured. If not set it default to min 8 threads used in Jettys thread pool. */ public void setHttpClientMinThreads(Integer httpClientMinThreads) { this.httpClientMinThreads = httpClientMinThreads; } public Integer getHttpClientMaxThreads() { return httpClientMaxThreads; } /** * To set a value for maximum number of threads in HttpClient thread pool. * This setting override any setting configured on component level. * Notice that both a min and max size must be configured. If not set it default to max 254 threads used in Jettys thread pool. */ public void setHttpClientMaxThreads(Integer httpClientMaxThreads) { this.httpClientMaxThreads = httpClientMaxThreads; } public Map<String, Object> getHttpClientParameters() { return httpClientParameters; } /** * Configuration of Jetty's HttpClient. For example, setting httpClient.idleTimeout=30000 sets the idle timeout to 30 seconds. * And httpClient.timeout=30000 sets the request timeout to 30 seconds, in case you want to timeout sooner if you have long running request/response calls. */ public void setHttpClientParameters(Map<String, Object> httpClientParameters) { this.httpClientParameters = httpClientParameters; } public Map<String, String> getFilterInitParameters() { return filterInitParameters; } /** * Configuration of the filter init parameters. These parameters will be applied to the filter list before starting the jetty server. */ public void setFilterInitParameters(Map<String, String> filterInitParameters) { this.filterInitParameters = filterInitParameters; } public boolean isEnableCORS() { return enableCORS; } /** * If the option is true, Jetty server will setup the CrossOriginFilter which supports the CORS out of box. */ public void setEnableCORS(boolean enableCORS) { this.enableCORS = enableCORS; } public CookieHandler getCookieHandler() { return cookieHandler; } /** * Configure a cookie handler to maintain a HTTP session */ public void setCookieHandler(CookieHandler cookieHandler) { this.cookieHandler = cookieHandler; } public abstract JettyContentExchange createContentExchange(); }