You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2008/11/21 19:09:19 UTC
svn commit: r719662 - in /activemq/camel/trunk/components:
camel-http/src/main/java/org/apache/camel/component/http/
camel-jetty/src/main/java/org/apache/camel/component/jetty/
camel-jetty/src/test/data/
camel-jetty/src/test/java/org/apache/camel/compo...
Author: davsclaus
Date: Fri Nov 21 10:09:17 2008
New Revision: 719662
URL: http://svn.apache.org/viewvc?rev=719662&view=rev
Log:
CAMEL-1107, CAMEL-1083, CAMEL-1095, CAMEL-1093: Major improvements to camel-jetty and camel-http.
camel-jetty: Now properly returns fault and exception
camel-http: repsonse body is avaiable on HttpOperationFailedException
camel-jetty: introduce HttpBinding as interface and to be referenced in Registry for end users to customize how response should be written
camel-jetty: now returns content-type and content-length if possible to calculate
both: minor URI parsing so internal Camel options is not exposed
Added:
activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/DefaultHttpBinding.java (contents, props changed)
- copied, changed from r719340, activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpBinding.java
activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpBinding.java
activemq/camel/trunk/components/camel-jetty/src/test/data/
activemq/camel/trunk/components/camel-jetty/src/test/data/logo.jpeg (with props)
activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyContentTypeTest.java
activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpBindingRefTest.java
activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpClientOptionsTest.java
activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyImageFileTest.java
activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyResponseBodyWhenErrorTest.java (contents, props changed)
- copied, changed from r714221, activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyRouteTest.java
Modified:
activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpEndpoint.java
activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpMessage.java
activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpOperationFailedException.java
activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
activemq/camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
Copied: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/DefaultHttpBinding.java (from r719340, activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpBinding.java)
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/DefaultHttpBinding.java?p2=activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/DefaultHttpBinding.java&p1=activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpBinding.java&r1=719340&r2=719662&rev=719662&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpBinding.java (original)
+++ activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/DefaultHttpBinding.java Fri Nov 21 10:09:17 2008
@@ -18,82 +18,124 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
+import java.io.PrintWriter;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.camel.Message;
-import org.apache.camel.impl.DefaultHeaderFilterStrategy;
import org.apache.camel.spi.HeaderFilterStrategy;
/**
+ * Binding between {@link HttpMessage} and {@link HttpServletResponse}.
+ *
* @version $Revision$
*/
-public class HttpBinding {
+public class DefaultHttpBinding implements HttpBinding {
private boolean useReaderForPayload;
private HeaderFilterStrategy headerFilterStrategy = new HttpHeaderFilterStrategy();
- public HttpBinding(HeaderFilterStrategy headerFilterStrategy) {
+ public DefaultHttpBinding() {
+ }
+
+ public DefaultHttpBinding(HeaderFilterStrategy headerFilterStrategy) {
this.headerFilterStrategy = headerFilterStrategy;
}
- /**
- * Writes the exchange to the servlet response
- */
+ public void readRequest(HttpServletRequest request, HttpMessage message) {
+ // lets force a parse of the body and headers
+ message.getBody();
+ message.getHeaders();
+ }
+
public void writeResponse(HttpExchange exchange, HttpServletResponse response) throws IOException {
- Message out = exchange.getOut();
- if (out != null) {
- // Set the status code in the response. Default is 200.
- if (out.getHeader(HttpProducer.HTTP_RESPONSE_CODE) != null) {
- int code = out.getHeader(HttpProducer.HTTP_RESPONSE_CODE, Integer.class);
- response.setStatus(code);
+ if (exchange.isFailed()) {
+ Message fault = exchange.getFault(false);
+ if (fault != null) {
+ doWriteFaultResponse(fault, response);
+ } else {
+ doWriteExceptionResponse(exchange.getException(), response);
}
-
- // Write out the headers
- for (String key : out.getHeaders().keySet()) {
- String value = out.getHeader(key, String.class);
- if (headerFilterStrategy != null
- && !headerFilterStrategy.applyFilterToCamelHeaders(key, value)) {
- response.setHeader(key, value);
- }
+ } else {
+ Message out = exchange.getOut();
+ if (out != null) {
+ doWriteResponse(out, response);
}
+ }
+ }
- // Write out the body.
- if (out.getBody() != null) {
+ public void doWriteExceptionResponse(Throwable exception, HttpServletResponse response) throws IOException {
+ response.setStatus(500); // 500 for internal server error
+ response.setContentType("text/plain");
+
+ // append the stacktrace as response
+ PrintWriter pw = response.getWriter();
+ exception.printStackTrace(pw);
- // Try to stream the body since that would be the most efficient
- InputStream is = out.getBody(InputStream.class);
- if (is != null) {
- ServletOutputStream os = null;
- try {
- os = response.getOutputStream();
- int c;
- while ((c = is.read()) >= 0) {
- os.write(c);
- }
- os.flush();
- } finally {
- os.close();
- is.close();
- }
- } else {
- String data = out.getBody(String.class);
- if (data != null) {
- response.getWriter().print(data);
+ pw.flush();
+ }
+
+ public void doWriteFaultResponse(Message message, HttpServletResponse response) throws IOException {
+ doWriteResponse(message, response);
+ }
+
+ public void doWriteResponse(Message message, HttpServletResponse response) throws IOException {
+ // set the status code in the response. Default is 200.
+ if (message.getHeader(HttpProducer.HTTP_RESPONSE_CODE) != null) {
+ int code = message.getHeader(HttpProducer.HTTP_RESPONSE_CODE, Integer.class);
+ response.setStatus(code);
+ }
+ // set the content type in the response.
+ if (message.getHeader("Content-Type") != null) {
+ String contentType = message.getHeader("Content-Type", String.class);
+ response.setContentType(contentType);
+ }
+
+ // append headers
+ for (String key : message.getHeaders().keySet()) {
+ String value = message.getHeader(key, String.class);
+ if (headerFilterStrategy != null
+ && !headerFilterStrategy.applyFilterToCamelHeaders(key, value)) {
+ response.setHeader(key, value);
+ }
+ }
+
+ // write the body.
+ if (message.getBody() != null) {
+ // try to stream the body since that would be the most efficient
+ InputStream is = message.getBody(InputStream.class);
+ int length = 0;
+ if (is != null) {
+ ServletOutputStream os = null;
+ try {
+ os = response.getOutputStream();
+ int c;
+ while ((c = is.read()) >= 0) {
+ os.write(c);
+ length++;
}
+ // set content length before we flush
+ response.setContentLength(length);
+ os.flush();
+ } finally {
+ os.close();
+ is.close();
+ }
+ } else {
+ String data = message.getBody(String.class);
+ if (data != null) {
+ // set content length before we write data
+ response.setContentLength(data.length());
+ response.getWriter().print(data);
+ response.getWriter().flush();
}
}
+
}
}
- /**
- * Parses the body from a HTTP message
- */
public Object parseBody(HttpMessage httpMessage) throws IOException {
// lets assume the body is a reader
HttpServletRequest request = httpMessage.getRequest();
@@ -108,12 +150,15 @@
return useReaderForPayload;
}
- /**
- * Should the {@link HttpServletRequest#getReader()} be exposed as the payload of input messages in the Camel
- * {@link Message#getBody()} or not. If false then the {@link HttpServletRequest#getInputStream()} will be exposed.
- */
public void setUseReaderForPayload(boolean useReaderForPayload) {
this.useReaderForPayload = useReaderForPayload;
}
+ public HeaderFilterStrategy getHeaderFilterStrategy() {
+ return headerFilterStrategy;
+ }
+
+ public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) {
+ this.headerFilterStrategy = headerFilterStrategy;
+ }
}
Propchange: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/DefaultHttpBinding.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/DefaultHttpBinding.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Propchange: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/DefaultHttpBinding.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpBinding.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpBinding.java?rev=719662&view=auto
==============================================================================
--- activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpBinding.java (added)
+++ activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpBinding.java Fri Nov 21 10:09:17 2008
@@ -0,0 +1,97 @@
+package org.apache.camel.component.http;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.Message;
+import org.apache.camel.spi.HeaderFilterStrategy;
+
+/**
+ * A plugable strategy for configuring the http binding so reading request and writing response
+ * can be customized using the Java Servlet API.
+ * <p/>
+ * This is used by the camel-jetty.
+ *
+ * @version $Revision$
+ */
+public interface HttpBinding {
+
+ /**
+ * Startegy to read the given request and bindings it to the given message.
+ *
+ * @param request the request
+ * @param message the message to populate with data from request
+ */
+ void readRequest(HttpServletRequest request, HttpMessage message);
+
+ /**
+ * Parses the body from a {@link org.apache.camel.component.http.HttpMessage}
+ *
+ * @return the parsed body returned as either a {@link java.io.InputStream} or a {@link java.io.Reader}
+ * depending on the {@link #setUseReaderForPayload(boolean)} property.
+ * @throws java.io.IOException can be thrown
+ */
+ Object parseBody(HttpMessage httpMessage) throws IOException;
+
+ /**
+ * Writes the exchange to the servlet response.
+ * <p/>
+ * Default implementation will delegate to the following methods depending on the status of the exchange
+ * <ul>
+ * <li>doWriteResponse - processing returns a OUT message </li>
+ * <li>doWriteFaultResponse - processing returns a fault message</li>
+ * <li>doWriteResponse - processing returns an exception and status code 500</li>
+ * </ul>
+ *
+ * @param exchange the exchange
+ * @param response the http response
+ * @throws java.io.IOException can be thrown from http response
+ */
+ void writeResponse(HttpExchange exchange, HttpServletResponse response) throws IOException;
+
+ /**
+ * Strategy method that writes the response to the http response stream when an exception occuerd
+ *
+ * @param exception the exception occured
+ * @param response the http response
+ * @throws java.io.IOException can be thrown from http response
+ */
+ void doWriteExceptionResponse(Throwable exception, HttpServletResponse response) throws IOException;
+
+ /**
+ * Strategy method that writes the response to the http response stream for a fault message
+ *
+ * @param message the fault message
+ * @param response the http response
+ * @throws java.io.IOException can be thrown from http response
+ */
+ void doWriteFaultResponse(Message message, HttpServletResponse response) throws IOException;
+
+ /**
+ * Strategy method that writes the response to the http response stream for an OUT message
+ *
+ * @param message the OUT message
+ * @param response the http response
+ * @throws java.io.IOException can be thrown from http response
+ */
+ void doWriteResponse(Message message, HttpServletResponse response) throws IOException;
+
+ boolean isUseReaderForPayload();
+
+ /**
+ * Should the {@link javax.servlet.http.HttpServletRequest#getReader()} be exposed as the payload of input messages in the Camel
+ * {@link org.apache.camel.Message#getBody()} or not. If false then the {@link javax.servlet.http.HttpServletRequest#getInputStream()} will be exposed.
+ */
+ void setUseReaderForPayload(boolean useReaderForPayload);
+
+ HeaderFilterStrategy getHeaderFilterStrategy();
+
+ /**
+ * Sets the header filter stratety to use.
+ * <p/>
+ * Will default use {@link org.apache.camel.component.http.HttpHeaderFilterStrategy}
+ */
+ void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy);
+
+}
Modified: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java?rev=719662&r1=719661&r2=719662&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java (original)
+++ activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java Fri Nov 21 10:09:17 2008
@@ -24,7 +24,9 @@
import org.apache.camel.ResolveEndpointFailedException;
import org.apache.camel.impl.DefaultComponent;
import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.util.CamelContextHelper;
import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.URISupport;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.params.HttpClientParams;
@@ -36,10 +38,10 @@
* @version $Revision$
*/
public class HttpComponent extends DefaultComponent implements HeaderFilterStrategyAware {
-
- private HttpClientConfigurer httpClientConfigurer;
- private HttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
- private HeaderFilterStrategy headerFilterStrategy;
+ protected HttpClientConfigurer httpClientConfigurer;
+ protected HttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
+ protected HeaderFilterStrategy headerFilterStrategy;
+ protected HttpBinding httpBinding;
public HttpComponent() {
this.setHeaderFilterStrategy(new HttpHeaderFilterStrategy());
@@ -47,51 +49,55 @@
/**
* Connects the URL specified on the endpoint to the specified processor.
+ *
+ * @param consumer the consumer
+ * @throws Exception can be thrown
*/
public void connect(HttpConsumer consumer) throws Exception {
}
/**
- * Disconnects the URL specified on the endpoint from the specified
- * processor.
+ * Disconnects the URL specified on the endpoint from the specified processor.
+ *
+ * @param consumer the consumer
+ * @throws Exception can be thrown
*/
public void disconnect(HttpConsumer consumer) throws Exception {
}
- public HttpClientConfigurer getHttpClientConfigurer() {
- return httpClientConfigurer;
- }
-
- public void setHttpClientConfigurer(HttpClientConfigurer httpClientConfigurer) {
- this.httpClientConfigurer = httpClientConfigurer;
- }
-
- public HttpConnectionManager getHttpConnectionManager() {
- return httpConnectionManager;
- }
-
- public void setHttpConnectionManager(HttpConnectionManager httpConnectionManager) {
- this.httpConnectionManager = httpConnectionManager;
- }
-
@Override
protected Endpoint createEndpoint(String uri, String remaining, Map parameters)
throws Exception {
+
+ // http client can be configured from URI options
HttpClientParams params = new HttpClientParams();
IntrospectionSupport.setProperties(params, parameters, "httpClient.");
+ // lookup http binding in registry if provided
+ String ref = getAndRemoveParameter(parameters, "httpBindingRef", String.class);
+ if (ref != null) {
+ httpBinding = CamelContextHelper.mandatoryLookup(getCamelContext(), ref, HttpBinding.class);
+ }
+
+ // restructure uri to be based on the parameters left as we dont want to include the Camel internal options
+ URI httpUri = URISupport.createRemainingURI(new URI(uri), parameters);
+ uri = httpUri.toString();
+
// validate http uri that end-user did not duplicate the http part that can be a common error
- URI httpUri = new URI(uri);
String part = httpUri.getSchemeSpecificPart();
if (part != null) {
part = part.toLowerCase();
- if (part.startsWith("//http://") || part.startsWith("//https://")) {
+ if (part.startsWith("//http//") || part.startsWith("//https//")) {
throw new ResolveEndpointFailedException(uri,
- "The uri part is not configured correctly. You have duplicated the http(s) protocol.");
+ "The uri part is not configured correctly. You have duplicated the http(s) protocol.");
}
}
- return new HttpEndpoint(uri, this, httpUri, params, httpConnectionManager, httpClientConfigurer);
+ HttpEndpoint endpoint = new HttpEndpoint(uri, this, httpUri, params, httpConnectionManager, httpClientConfigurer);
+ if (httpBinding != null) {
+ endpoint.setBinding(httpBinding);
+ }
+ return endpoint;
}
@Override
@@ -99,6 +105,22 @@
return false;
}
+ public HttpClientConfigurer getHttpClientConfigurer() {
+ return httpClientConfigurer;
+ }
+
+ public void setHttpClientConfigurer(HttpClientConfigurer httpClientConfigurer) {
+ this.httpClientConfigurer = httpClientConfigurer;
+ }
+
+ public HttpConnectionManager getHttpConnectionManager() {
+ return httpConnectionManager;
+ }
+
+ public void setHttpConnectionManager(HttpConnectionManager httpConnectionManager) {
+ this.httpConnectionManager = httpConnectionManager;
+ }
+
public HeaderFilterStrategy getHeaderFilterStrategy() {
return headerFilterStrategy;
}
@@ -106,4 +128,12 @@
public void setHeaderFilterStrategy(HeaderFilterStrategy strategy) {
headerFilterStrategy = strategy;
}
+
+ public HttpBinding getHttpBinding() {
+ return httpBinding;
+ }
+
+ public void setHttpBinding(HttpBinding httpBinding) {
+ this.httpBinding = httpBinding;
+ }
}
Modified: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpEndpoint.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpEndpoint.java?rev=719662&r1=719661&r2=719662&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpEndpoint.java (original)
+++ activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpEndpoint.java Fri Nov 21 10:09:17 2008
@@ -139,7 +139,7 @@
public HttpBinding getBinding() {
if (binding == null) {
- binding = new HttpBinding(getHeaderFilterStrategy());
+ binding = new DefaultHttpBinding(getHeaderFilterStrategy());
}
return binding;
}
Modified: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpMessage.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpMessage.java?rev=719662&r1=719661&r2=719662&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpMessage.java (original)
+++ activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpMessage.java Fri Nov 21 10:09:17 2008
@@ -35,9 +35,9 @@
setExchange(exchange);
this.request = request;
- // lets force a parse of the body and headers
- getBody();
- getHeaders();
+ // use binding to read the request allowing end users to use their
+ // implementation of the binding
+ getExchange().getEndpoint().getBinding().readRequest(request, this);
}
@Override
Modified: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpOperationFailedException.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpOperationFailedException.java?rev=719662&r1=719661&r2=719662&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpOperationFailedException.java (original)
+++ activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpOperationFailedException.java Fri Nov 21 10:09:17 2008
@@ -16,6 +16,8 @@
*/
package org.apache.camel.component.http;
+import java.io.InputStream;
+
import org.apache.camel.CamelException;
import org.apache.camel.util.ObjectHelper;
import org.apache.commons.httpclient.StatusLine;
@@ -24,6 +26,7 @@
private final String redirectLocation;
private final int statusCode;
private final StatusLine statusLine;
+ private InputStream responseBody;
public HttpOperationFailedException(int statusCode, StatusLine statusLine, String location) {
super("HTTP operation failed with statusCode: " + statusCode + ", status: " + statusLine + (location != null ? ", redirectLocation: " + location : ""));
@@ -56,4 +59,11 @@
return statusCode;
}
+ public InputStream getResponseBody() {
+ return responseBody;
+ }
+
+ public void setResponseBody(InputStream responseBody) {
+ this.responseBody = responseBody;
+ }
}
\ No newline at end of file
Modified: activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java?rev=719662&r1=719661&r2=719662&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java (original)
+++ activemq/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java Fri Nov 21 10:09:17 2008
@@ -19,9 +19,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
@@ -42,6 +39,7 @@
import org.apache.commons.logging.LogFactory;
import static org.apache.camel.component.http.HttpMethods.HTTP_METHOD;
+
/**
* @version $Revision$
*/
@@ -98,18 +96,24 @@
}
} else {
HttpOperationFailedException exception = null;
- if (responseCode < 400 && responseCode >= 300) {
+ if (responseCode >= 300 && responseCode < 400) {
String redirectLocation;
Header locationHeader = method.getResponseHeader("location");
if (locationHeader != null) {
redirectLocation = locationHeader.getValue();
exception = new HttpOperationFailedException(responseCode, method.getStatusLine(), redirectLocation);
+ } else {
+ // no redirect location
+ exception = new HttpOperationFailedException(responseCode, method.getStatusLine());
}
} else {
+ // internal server error (error code 500)
exception = new HttpOperationFailedException(responseCode, method.getStatusLine());
}
if (exception != null) {
+ // set also the response body as well
+ exception.setResponseBody(extractResponseBody(method));
throw exception;
}
}
@@ -119,14 +123,6 @@
}
}
- public HttpClient getHttpClient() {
- return httpClient;
- }
-
- public void setHttpClient(HttpClient httpClient) {
- this.httpClient = httpClient;
- }
-
/**
* Strategy when executing the method (calling the remote server).
*
@@ -138,12 +134,23 @@
return httpClient.executeMethod(method);
}
+ /**
+ * Extracts the response from the method as a InputStream.
+ *
+ * @param method the method that was executed
+ * @return the response as a stream
+ * @throws IOException can be thrown
+ */
protected static InputStream extractResponseBody(HttpMethod method) throws IOException {
LoadingByteArrayOutputStream bos = null;
InputStream is = null;
try {
bos = new LoadingByteArrayOutputStream();
is = method.getResponseBodyAsStream();
+ // in case of no response stream
+ if (is == null) {
+ return null;
+ }
IOUtils.copy(is, bos);
bos.flush();
return bos.createInputStream();
@@ -153,6 +160,12 @@
}
}
+ /**
+ * Creates the HttpMethod to use to call the remote server, either its GET or POST.
+ *
+ * @param exchange the exchange
+ * @return the created method as either GET or POST
+ */
protected HttpMethod createMethod(Exchange exchange) {
// is a query string provided in the endpoint URI or in a header (header overrules endpoint)
String queryString = exchange.getIn().getHeader(QUERY, String.class);
@@ -179,7 +192,7 @@
if (uri == null) {
uri = ((HttpEndpoint)getEndpoint()).getHttpUri().toString();
}
-
+
HttpMethod method = methodToUse.createMethod(uri);
if (queryString != null) {
@@ -192,6 +205,12 @@
return method;
}
+ /**
+ * Creates a holder object for the data to send to the remote server.
+ *
+ * @param exchange the exchange with the IN message with data to send
+ * @return the data holder
+ */
protected RequestEntity createRequestEntity(Exchange exchange) {
Message in = exchange.getIn();
if (in.getBody() == null) {
@@ -215,4 +234,12 @@
}
}
}
+
+ public HttpClient getHttpClient() {
+ return httpClient;
+ }
+
+ public void setHttpClient(HttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
}
Modified: activemq/camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java?rev=719662&r1=719661&r2=719662&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java (original)
+++ activemq/camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java Fri Nov 21 10:09:17 2008
@@ -22,9 +22,13 @@
import org.apache.camel.Endpoint;
import org.apache.camel.component.http.CamelServlet;
+import org.apache.camel.component.http.HttpBinding;
import org.apache.camel.component.http.HttpComponent;
import org.apache.camel.component.http.HttpConsumer;
import org.apache.camel.component.http.HttpEndpoint;
+import org.apache.camel.util.CamelContextHelper;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.URISupport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mortbay.jetty.Connector;
@@ -65,20 +69,40 @@
}
}
- private static final Log LOGGER = LogFactory.getLog(JettyHttpComponent.class);
+ private static final transient Log LOG = LogFactory.getLog(JettyHttpComponent.class);
- private Server server;
- private HashMap<String, ConnectorRef> connectors = new HashMap<String, ConnectorRef>();
- private HttpClient httpClient;
- private String sslKeyPassword;
- private String sslPassword;
- private String sslKeystore;
- private SslSocketConnector sslSocketConnector;
+ protected Server server;
+ protected HashMap<String, ConnectorRef> connectors = new HashMap<String, ConnectorRef>();
+ protected HttpClient httpClient;
+ protected String sslKeyPassword;
+ protected String sslPassword;
+ protected String sslKeystore;
+ protected SslSocketConnector sslSocketConnector;
@Override
protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception {
- URI httpURL = uri.startsWith("jetty:") ? new URI(remaining) : new URI(uri);
- JettyHttpEndpoint result = new JettyHttpEndpoint(this, uri, httpURL, getHttpConnectionManager());
+ uri = uri.startsWith("jetty:") ? remaining : uri;
+
+ // http client can be configured from URI options
+ if (httpClient == null) {
+ httpClient = createHttpClient();
+ }
+ IntrospectionSupport.setProperties(httpClient, parameters, "httpClient.");
+
+ // lookup http binding in registry if provided
+ String ref = getAndRemoveParameter(parameters, "httpBindingRef", String.class);
+ if (ref != null) {
+ httpBinding = CamelContextHelper.mandatoryLookup(getCamelContext(), ref, HttpBinding.class);
+ }
+
+ // restructure uri to be based on the parameters left as we dont want to include the Camel internal options
+ URI httpUri = URISupport.createRemainingURI(new URI(uri), parameters);
+ uri = httpUri.toString();
+
+ JettyHttpEndpoint result = new JettyHttpEndpoint(this, uri, httpUri, getHttpConnectionManager());
+ if (httpBinding != null) {
+ result.setBinding(httpBinding);
+ }
setProperties(result, parameters);
return result;
}
@@ -90,7 +114,6 @@
*/
@Override
public void connect(HttpConsumer consumer) throws Exception {
-
// Make sure that there is a connector for the requested endpoint.
JettyHttpEndpoint endpoint = (JettyHttpEndpoint)consumer.getEndpoint();
String connectorKey = endpoint.getProtocol() + ":" + endpoint.getHttpUri().getHost() + ":" + endpoint.getPort();
@@ -107,7 +130,7 @@
connector.setPort(endpoint.getPort());
connector.setHost(endpoint.getHttpUri().getHost());
if ("localhost".equalsIgnoreCase(endpoint.getHttpUri().getHost())) {
- LOGGER.warn("You use localhost interface! It means that no external connections will be available. Don't you want to use 0.0.0.0 instead (all network interfaces)?");
+ LOG.warn("You use localhost interface! It means that no external connections will be available. Don't you want to use 0.0.0.0 instead (all network interfaces)?");
}
getServer().addConnector(connector);
Added: activemq/camel/trunk/components/camel-jetty/src/test/data/logo.jpeg
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-jetty/src/test/data/logo.jpeg?rev=719662&view=auto
==============================================================================
Binary file - no diff available.
Propchange: activemq/camel/trunk/components/camel-jetty/src/test/data/logo.jpeg
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyContentTypeTest.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyContentTypeTest.java?rev=719662&view=auto
==============================================================================
--- activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyContentTypeTest.java (added)
+++ activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyContentTypeTest.java Fri Nov 21 10:09:17 2008
@@ -0,0 +1,75 @@
+/**
+ * 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 org.apache.camel.ContextTestSupport;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+
+/**
+ * Unit test for content-type
+ */
+public class JettyContentTypeTest extends ContextTestSupport {
+
+ public void testSameContentType() throws Exception {
+ Endpoint endpoint = context.getEndpoint("http://localhost:8080/myapp/myservice");
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setBody("<order>123</order>");
+ exchange.getIn().setHeader("user", "Claus");
+ exchange.getIn().setHeader("content-type", "text/xml");
+ template.send(endpoint, exchange);
+
+ String body = exchange.getOut().getBody(String.class);
+ assertEquals("<order>OK</order>", body);
+ assertOutMessageHeader(exchange, "content-type", "text/xml");
+ }
+
+ public void testMixedContentType() throws Exception {
+ Endpoint endpoint = context.getEndpoint("http://localhost:8080/myapp/myservice");
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setBody("<order>123</order>");
+ exchange.getIn().setHeader("Content-Type", "text/xml");
+ template.send(endpoint, exchange);
+
+ String body = exchange.getOut().getBody(String.class);
+ assertEquals("FAIL", body);
+ assertOutMessageHeader(exchange, "Content-Type", "text/plain");
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ public void configure() throws Exception {
+ from("jetty:http://localhost:8080/myapp/myservice").process(new MyBookService());
+ }
+ };
+ }
+
+ public class MyBookService implements Processor {
+ public void process(Exchange exchange) throws Exception {
+ if (exchange.getIn().getHeader("user") != null) {
+ exchange.getOut().setBody("<order>OK</order>");
+ } else {
+ exchange.getOut().setBody("FAIL");
+ exchange.getOut().setHeader("Content-Type", "text/plain");
+ }
+ }
+ }
+
+}
\ No newline at end of file
Added: activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpBindingRefTest.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpBindingRefTest.java?rev=719662&view=auto
==============================================================================
--- activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpBindingRefTest.java (added)
+++ activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpBindingRefTest.java Fri Nov 21 10:09:17 2008
@@ -0,0 +1,71 @@
+package org.apache.camel.component.jetty;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.http.DefaultHttpBinding;
+import org.apache.camel.impl.JndiRegistry;
+
+/**
+ * Unit test for http binding ref option.
+ */
+public class JettyHttpBindingRefTest extends ContextTestSupport {
+
+ public void testDefaultHttpBinding() throws Exception {
+ Object out = template.requestBody("http://localhost:8080/myapp/myservice", "Hello World");
+ assertEquals("Bye World", context.getTypeConverter().convertTo(String.class, out));
+ }
+
+ public void testCustomHttpBinding() throws Exception {
+ Object out = template.requestBody("http://localhost:8081/myapp/myotherservice", "Hello World");
+ assertEquals("Something went wrong but we dont care", context.getTypeConverter().convertTo(String.class, out));
+ }
+
+ @Override
+ protected JndiRegistry createRegistry() throws Exception {
+ JndiRegistry jndi = super.createRegistry();
+ jndi.bind("default", new DefaultHttpBinding());
+ jndi.bind("myownbinder", new MyHttpBinding());
+ return jndi;
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ errorHandler(noErrorHandler());
+
+ from("jetty:http://localhost:8080/myapp/myservice?httpBindingRef=default").transform().constant("Bye World");
+
+ from("jetty:http://localhost:8081/myapp/myotherservice?httpBindingRef=myownbinder").process(new Processor() {
+ public void process(Exchange exchange) throws Exception {
+ throw new IllegalStateException("Not implemented");
+ }
+ });
+ }
+ };
+ }
+
+ // START SNIPPET: e1
+ public class MyHttpBinding extends DefaultHttpBinding {
+
+ @Override
+ public void doWriteExceptionResponse(Throwable exception, HttpServletResponse response) throws IOException {
+ // we override the doWriteExceptionResponse as we only want to alter the binding how exceptions is
+ // written back to the client.
+
+ // we just return HTTP 200 so the client thinks its okay
+ response.setStatus(200);
+ // and we return this fixed text
+ response.getWriter().write("Something went wrong but we dont care");
+ }
+ }
+ // END SNIPPET: e1
+
+}
+
Added: activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpClientOptionsTest.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpClientOptionsTest.java?rev=719662&view=auto
==============================================================================
--- activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpClientOptionsTest.java (added)
+++ activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyHttpClientOptionsTest.java Fri Nov 21 10:09:17 2008
@@ -0,0 +1,32 @@
+package org.apache.camel.component.jetty;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+
+/**
+ * Unit test for http client options.
+ */
+public class JettyHttpClientOptionsTest extends ContextTestSupport {
+
+ public void testCustomHttpBinding() throws Exception {
+ // assert jetty was configured with our timeout
+ JettyHttpComponent jetty = context.getComponent("jetty", JettyHttpComponent.class);
+ assertNotNull(jetty);
+ assertEquals(5555, jetty.getHttpClient().getIdleTimeout());
+
+ // send and receive
+ Object out = template.requestBody("http://localhost:8080/myapp/myservice", "Hello World");
+ assertEquals("Bye World", context.getTypeConverter().convertTo(String.class, out));
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("jetty:http://localhost:8080/myapp/myservice?httpClient.idleTimeout=5555").transform().constant("Bye World");
+ }
+ };
+ }
+
+}
\ No newline at end of file
Added: activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyImageFileTest.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyImageFileTest.java?rev=719662&view=auto
==============================================================================
--- activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyImageFileTest.java (added)
+++ activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyImageFileTest.java Fri Nov 21 10:09:17 2008
@@ -0,0 +1,57 @@
+/**
+ * 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.io.File;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+
+/**
+ * Unit test for exposing a http server that returns images
+ */
+public class JettyImageFileTest extends ContextTestSupport {
+
+ public void testImageContentType() throws Exception {
+ Endpoint endpoint = context.getEndpoint("http://localhost:8080/myapp/myservice");
+ Exchange exchange = endpoint.createExchange();
+ template.send(endpoint, exchange);
+
+ assertNotNull(exchange.getOut().getBody());
+ assertOutMessageHeader(exchange, "Content-Type", "image/jpeg");
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ public void configure() throws Exception {
+ from("jetty:http://localhost:8080/myapp/myservice").process(new MyImageService());
+ }
+ };
+ }
+
+ public class MyImageService implements Processor {
+ public void process(Exchange exchange) throws Exception {
+ exchange.getOut().setBody(new File("src/test/data/logo.jpeg"));
+ exchange.getOut().setHeader("Content-Type", "image/jpeg");
+ }
+ }
+
+}
\ No newline at end of file
Copied: activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyResponseBodyWhenErrorTest.java (from r714221, activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyRouteTest.java)
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyResponseBodyWhenErrorTest.java?p2=activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyResponseBodyWhenErrorTest.java&p1=activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyRouteTest.java&r1=714221&r2=719662&rev=719662&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyRouteTest.java (original)
+++ activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyResponseBodyWhenErrorTest.java Fri Nov 21 10:09:17 2008
@@ -16,53 +16,45 @@
*/
package org.apache.camel.component.jetty;
-import javax.servlet.http.HttpServletRequest;
-
import org.apache.camel.ContextTestSupport;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
+import org.apache.camel.RuntimeCamelException;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.http.HttpOperationFailedException;
/**
- * Unit test for wiki demonstration.
+ * Unit test for HttpOperationFailedException should contain reponse body
*/
-public class JettyRouteTest extends ContextTestSupport {
+public class JettyResponseBodyWhenErrorTest extends ContextTestSupport {
- public void testSendToJetty() throws Exception {
- Object response = template.requestBody("http://localhost:8080/myapp/myservice", "bookid=123");
- // convert the response to a String
- String body = context.getTypeConverter().convertTo(String.class, response);
- assertEquals("<html><body>Book 123 is Camel in Action</body></html>", body);
+ public void testResponseBodyWhenError() throws Exception {
+ try {
+ template.sendBody("http://localhost:8080/myapp/myservice", "bookid=123");
+ fail("Should have thrown an exception");
+ } catch (RuntimeCamelException e) {
+ HttpOperationFailedException cause = (HttpOperationFailedException) e.getCause();
+ assertEquals(500, cause.getStatusCode());
+ String body = context.getTypeConverter().convertTo(String.class, cause.getResponseBody());
+ assertTrue(body.indexOf("Damm") > -1);
+ assertTrue(body.indexOf("IllegalArgumentException") > -1);
+ }
}
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
public void configure() throws Exception {
- // START SNIPPET: e1
+ errorHandler(noErrorHandler());
from("jetty:http://localhost:8080/myapp/myservice").process(new MyBookService());
- // END SNIPPET: e1
}
};
}
- // START SNIPPET: e2
public class MyBookService implements Processor {
public void process(Exchange exchange) throws Exception {
- // just get the body as a string
- String body = exchange.getIn().getBody(String.class);
-
- // we have access to the HttpServletRequest here and we can grab it if we need it
- HttpServletRequest req = exchange.getIn().getBody(HttpServletRequest.class);
- assertNotNull(req);
-
- // for unit testing
- assertEquals("bookid=123", body);
-
- // send a html response
- exchange.getOut(true).setBody("<html><body>Book 123 is Camel in Action</body></html>");
+ throw new IllegalArgumentException("Damm");
}
}
- // END SNIPPET: e2
-}
+}
\ No newline at end of file
Propchange: activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyResponseBodyWhenErrorTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyResponseBodyWhenErrorTest.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Propchange: activemq/camel/trunk/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/JettyResponseBodyWhenErrorTest.java
------------------------------------------------------------------------------
svn:mergeinfo =