You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@camel.apache.org by "Christian Mueller (JIRA)" <ji...@apache.org> on 2010/01/15 19:22:47 UTC

[jira] Issue Comment Edited: (CAMEL-1530) Upgrade camel-http to use httpclient 4.0

    [ https://issues.apache.org/activemq/browse/CAMEL-1530?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=56937#action_56937 ] 

Christian Mueller edited comment on CAMEL-1530 at 1/15/10 6:22 PM:
-------------------------------------------------------------------

@Oleg,
first of all, I will say thank you for the good documentation of httpclient you pointed out.

@Claus,
after studding the documentation and the tests from httpclient, I made the following plan:
1. Develop a abstract base class for all camel-http tests which starts and stops the local http test server from the httpclient project (called HttpServerTestSupport). Develop this with httpclient 4.0.1, so that we dosn't have to change the test if we migrate to 4.0.1 with camel-http. -> finished
2. Change the existing tests to subclass HttpServerTestSupport and send the requests to this server (instead of google search). -> in progress
3. Add tests for authentication, compression, using proxy, https, ... -> in progress
4. Migrate camel-http to httpclient 4.0.1.

For a better understanding, I post the HttpServerTestSupport, one migrated simple http GET test and one http handler which validate the request against our expectations and set the propper response:

{code:title=org.apache.camel.component.http.HttpServerTestSupport.java|borderStyle=solid}
public abstract class HttpServerTestSupport extends CamelTestSupport {

	protected LocalTestServer localServer;
	
    @Override
    public void setUp() throws Exception {
        localServer = new LocalTestServer(getBasicHttpProcessor(), getHttpParams());
        registerHandlers(localServer);
        localServer.start();
        
        super.setUp();
    }
	
	@Override
    public void tearDown() throws Exception {
    	super.tearDown();
    	
        if (localServer != null) {
            localServer.stop();
        }
    }
	
    protected BasicHttpProcessor getBasicHttpProcessor() {
		return null;
	}
    
	protected HttpParams getHttpParams() {
		return null;
	}
	
	protected void registerHandlers(LocalTestServer server) {
	}
	
	/**
	 * Obtains the host name of the local test server.
	 * 
	 * @return hostName
	 */
	protected String getHostName() {
		return localServer.getServiceHostName();
	}
	
	/**
	 * Obtains the port of the local test server.
	 * 
	 * @return port
	 */
	protected int getPort() {
		return localServer.getServicePort();
	}
}
{code}

I modified the existing test to subclass HttpServerTestSupport and added tree new header expectations:

{code:title=org.apache.camel.component.http.HttpGetTest.java|borderStyle=solid}
public class HttpGetTest extends HttpServerTestSupport {
    protected String expectedText = "activemq";
    
    @Test
    public void testHttpGet() throws Exception {
        MockEndpoint mockEndpoint = resolveMandatoryEndpoint("mock:results", MockEndpoint.class);
        mockEndpoint.expectedMessageCount(1);

        template.sendBody("direct:start", null);

        mockEndpoint.assertIsSatisfied();
        List<Exchange> list = mockEndpoint.getReceivedExchanges();
        Exchange exchange = list.get(0);
        assertNotNull("exchange", exchange);

        Message in = exchange.getIn();
        assertNotNull("in", in);

        Map<String, Object> headers = in.getHeaders();

        log.debug("Headers: " + headers);
        checkHeaders(headers);       

        String body = in.getBody(String.class);

        log.debug("Body: " + body);
        assertNotNull("Should have a body!", body);
        assertTrue("body should contain: " + expectedText, body.contains(expectedText));
    }

    protected void checkHeaders(Map<String, Object> headers) {
        assertTrue("Should be more than one header but was: " + headers, headers.size() > 0);
        
        assertEquals(HttpStatus.SC_OK, headers.get(Exchange.HTTP_RESPONSE_CODE));
        assertEquals("8", headers.get("Content-Length"));
        assertEquals("text/plain; charset=ASCII", headers.get("Content-Type"));
    }
    
    @Override
	protected void registerHandlers(LocalTestServer server) {
		server.register("/search", new SimpleValidationHandler("GET", "hl=en&q=activemq", null, expectedText));
	}

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            public void configure() {
                from("direct:start").setHeader(Exchange.HTTP_QUERY, constant("hl=en&q=activemq"))
                    .to("http://" + getHostName() + ":" + getPort() + "/search").to("mock:results");
            }
        };
    }
}
{code}

The org.apache.http.protocol.HttpRequestHandler, which is responsible for processing the request (and validation against our expectations):

{code:title=org.apache.camel.component.http.handler.SimpleValidationHandler.java|borderStyle=solid}
public class SimpleValidationHandler implements HttpRequestHandler {
	
	private String expectedMethod;
	private String expectedQuery;
	private Object expectedContent;
	private String responseContent;
	
	public SimpleValidationHandler(String expectedMethod, String expectedQuery, Object expectedContent, String responseContent) {
		this.expectedMethod = expectedMethod;
		this.expectedQuery = expectedQuery;
		this.expectedContent = expectedContent;
		this.responseContent = responseContent;
	}

    public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException {
    	if (expectedMethod != null && !expectedMethod.equals(request.getRequestLine().getMethod())) {
    		response.setStatusCode(HttpStatus.SC_METHOD_FAILURE);
    		return;
    	}
    	
        try {
			if (expectedQuery != null && !expectedQuery.equals(new URI(request.getRequestLine().getUri()).getQuery())) {
			    response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
			    return;
			}
		} catch (URISyntaxException e) {
			throw new IOException(e);
		}
		
		if (expectedContent != null) {
			RequestEntity entity = ((EntityEnclosingMethod) request).getRequestEntity();
			if (entity instanceof StringRequestEntity) {
				String content = ((StringRequestEntity) entity).getContent();
				if (!expectedContent.equals(content)) {
					response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
				}
			} else {
				response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
			}
		}
        
        response.setStatusCode(HttpStatus.SC_OK);
        response.setEntity(new StringEntity(responseContent, HTTP.ASCII));
    }
}
{code}

Analog to this, I have ready the authentication test and authentication handler.

What do you think?

Regards,
Christian

      was (Author: muellerc):
    @Oleg,
first of all, I will say thank you for the good documentation of httpclient you pointed out.

@Claus,
after studding the documentation and the tests from httpclient, I made the following plan:
1. Develop a abstract base class for all camel-http tests which starts and stops the local http test server from the httpclient project (called HttpServerTestSupport). Develop this with httpclient 4.0.1, so that we dosn't have to change the test if we migrate to 4.0.1 with camel-http. -> finished
2. Change the existing tests to subclass HttpServerTestSupport and send the requests to this server (instead of google search). -> in progress
3. Add tests for authentication, compression, using proxy, https, ... -> in progress
4. Migrate camel-http to httpclient 4.0.1.

For a better understanding, I post the HttpServerTestSupport, one migrated simple http GET test and one http handler which validate the request against our expectations and set the propper response:

{code:title=org.apache.camel.component.http.HttpServerTestSupport.java|borderStyle=solid}
public abstract class HttpServerTestSupport extends CamelTestSupport {

	protected LocalTestServer localServer;
	
    @Override
    public void setUp() throws Exception {
        localServer = new LocalTestServer(getBasicHttpProcessor(), getHttpParams());
        registerHandlers(localServer);
        localServer.start();
        
        super.setUp();
    }
	
	@Override
    public void tearDown() throws Exception {
    	super.tearDown();
    	
        if (localServer != null) {
            localServer.stop();
        }
    }
	
    protected BasicHttpProcessor getBasicHttpProcessor() {
		return null;
	}
    
	protected HttpParams getHttpParams() {
		return null;
	}
	
	protected void registerHandlers(LocalTestServer server) {
	}
	
	/**
	 * Obtains the host name of the local test server.
	 * 
	 * @return hostName
	 */
	protected String getHostName() {
		return localServer.getServiceHostName();
	}
	
	/**
	 * Obtains the port of the local test server.
	 * 
	 * @return port
	 */
	protected int getPort() {
		return localServer.getServicePort();
	}
}
{code}

I modified the existing test to subclass HttpServerTestSupport and added two new header expectations:

{code:title=org.apache.camel.component.http.HttpGetTest.java|borderStyle=solid}
public class HttpGetTest extends HttpServerTestSupport {
    protected String expectedText = "activemq";
    
    @Test
    public void testHttpGet() throws Exception {
        MockEndpoint mockEndpoint = resolveMandatoryEndpoint("mock:results", MockEndpoint.class);
        mockEndpoint.expectedMessageCount(1);

        template.sendBody("direct:start", null);

        mockEndpoint.assertIsSatisfied();
        List<Exchange> list = mockEndpoint.getReceivedExchanges();
        Exchange exchange = list.get(0);
        assertNotNull("exchange", exchange);

        Message in = exchange.getIn();
        assertNotNull("in", in);

        Map<String, Object> headers = in.getHeaders();

        log.debug("Headers: " + headers);
        checkHeaders(headers);       

        String body = in.getBody(String.class);

        log.debug("Body: " + body);
        assertNotNull("Should have a body!", body);
        assertTrue("body should contain: " + expectedText, body.contains(expectedText));
    }

    protected void checkHeaders(Map<String, Object> headers) {
        assertTrue("Should be more than one header but was: " + headers, headers.size() > 0);
        
        assertEquals(HttpStatus.SC_OK, headers.get(Exchange.HTTP_RESPONSE_CODE));
        assertEquals("8", headers.get("Content-Length"));
        assertEquals("text/plain; charset=ASCII", headers.get("Content-Type"));
    }
    
    @Override
	protected void registerHandlers(LocalTestServer server) {
		server.register("/search", new SimpleValidationHandler("GET", "hl=en&q=activemq", null, expectedText));
	}

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            public void configure() {
                from("direct:start").setHeader(Exchange.HTTP_QUERY, constant("hl=en&q=activemq"))
                    .to("http://" + getHostName() + ":" + getPort() + "/search").to("mock:results");
            }
        };
    }
}
{code}

The org.apache.http.protocol.HttpRequestHandler, which is responsible for processing the request (and validation against our expectations):

{code:title=org.apache.camel.component.http.handler.SimpleValidationHandler.java|borderStyle=solid}
public class SimpleValidationHandler implements HttpRequestHandler {
	
	private String expectedMethod;
	private String expectedQuery;
	private Object expectedContent;
	private String responseContent;
	
	public SimpleValidationHandler(String expectedMethod, String expectedQuery, Object expectedContent, String responseContent) {
		this.expectedMethod = expectedMethod;
		this.expectedQuery = expectedQuery;
		this.expectedContent = expectedContent;
		this.responseContent = responseContent;
	}

    public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException {
    	if (expectedMethod != null && !expectedMethod.equals(request.getRequestLine().getMethod())) {
    		response.setStatusCode(HttpStatus.SC_METHOD_FAILURE);
    		return;
    	}
    	
        try {
			if (expectedQuery != null && !expectedQuery.equals(new URI(request.getRequestLine().getUri()).getQuery())) {
			    response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
			    return;
			}
		} catch (URISyntaxException e) {
			throw new IOException(e);
		}
		
		if (expectedContent != null) {
			RequestEntity entity = ((EntityEnclosingMethod) request).getRequestEntity();
			if (entity instanceof StringRequestEntity) {
				String content = ((StringRequestEntity) entity).getContent();
				if (!expectedContent.equals(content)) {
					response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
				}
			} else {
				response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
			}
		}
        
        response.setStatusCode(HttpStatus.SC_OK);
        response.setEntity(new StringEntity(responseContent, HTTP.ASCII));
    }
}
{code}

Analog to this, I have ready the authentication test and authentication handler.

What do you think?

Regards,
Christian
  
> Upgrade camel-http to use httpclient 4.0
> ----------------------------------------
>
>                 Key: CAMEL-1530
>                 URL: https://issues.apache.org/activemq/browse/CAMEL-1530
>             Project: Apache Camel
>          Issue Type: Improvement
>          Components: camel-http
>    Affects Versions: 2.0-M1
>            Reporter: Claus Ibsen
>            Assignee: Christian Mueller
>             Fix For: 2.3.0
>
>         Attachments: camel-http-test.patch, camel-http.patch
>
>
> Upgrading httpclient from 3.1 to 4.0 requires changes in the camel-http code as the API has change quite a lot.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.