Hi Raul,
To start off I have inspected the headers received at the target server,
and the only difference between AHC and Http4, was that AHC enabled
compression by default.
So I have set that up via "clientConfig.compressionEnabled=true" and I can
confirm that the headers now match line-by-line.
However, I'm still obtaining the same result, the body is not received at
the target server when using AHC.
Moving on from that, I have set the logger to TRACE for both components and
compared the results (full AHC trace at the bottom of this email)
Some thoughts from the trace
- [http-bio-8080-exec-13] DefaultStreamCachingStrategy DEBUG Should spool
cache 98 -> false
98 is the length of the JSON payload that I'm sending
- [http-bio-8080-exec-13] route4 INFO
{'HostName':'DEVSERVER','IpAddress':'192.168.1.42','x64':true,'OperatingSystem':'Windows
Host'}
this is the explicit call to log that I make with the ${body} content
- These traced calls would lead me to believe that the AHC is at lest
attempting to parse the content
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
org.apache.camel.converter.stream.InputStreamCache ->
com.ning.http.client.BodyGenerator with value:
org.apache.camel.converter.stream.InputStreamCache@4ee3990b
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
org.apache.camel.component.http.HttpMessage ->
com.ning.http.client.BodyGenerator with value: Message: [Body is instance
of org.apache.camel.StreamCache]
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Setting body
com.ning.http.client.generators.InputStreamBodyGenerator@7255cf3f
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Setting
Content-Type application/json
I am also using 2.13.2 for camel-core and AHC, would you recommend to
attempt this with any other versions of the library?
Or should I maybe consider debugging AHC to see what happens internally?
Any other ideas to share?
Thanks,
Jaume
ps: here's the full trace.
[http-bio-8080-exec-13] CamelHttpTransportServlet TRACE Service:
org.apache.catalina.connector.RequestFacade@40bbc1f6
[http-bio-8080-exec-13] DefaultHttpBinding TRACE readRequest
org.apache.catalina.connector.RequestFacade@40bbc1f6
[http-bio-8080-exec-13] IOHelper TRACE Copying
InputStream: org.apache.catalina.connector.CoyoteInputStream@4a0cc3e8 ->
OutputStream: CachedOutputStream[size: 0] with buffer: 4096 and flush on
each write false
[http-bio-8080-exec-13] DefaultStreamCachingStrategy DEBUG Should spool
cache 98 -> false
[http-bio-8080-exec-13] DefaultHttpBinding TRACE HTTP parameter
address = [localhost:58100/api/servers]
[http-bio-8080-exec-13] DefaultHttpBinding TRACE HTTP method
POST with Content-Type application/json
[http-bio-8080-exec-13] DefaultHttpBinding TRACE HTTP method
POST
[http-bio-8080-exec-13] DefaultHttpBinding TRACE HTTP query
address=localhost:58100/api/servers
[http-bio-8080-exec-13] DefaultHttpBinding TRACE HTTP url
http://localhost:8080/camelstubs/camel/tinyproxy2
[http-bio-8080-exec-13] DefaultHttpBinding TRACE HTTP uri
/camelstubs/camel/tinyproxy2
[http-bio-8080-exec-13] DefaultHttpBinding TRACE HTTP path
/tinyproxy2
[http-bio-8080-exec-13] DefaultHttpBinding TRACE HTTP
content-type application/json
[http-bio-8080-exec-13] DefaultUnitOfWork TRACE UnitOfWork
created for ExchangeId: ID-DEVSERVER-56006-1408531950289-0-15 with
Exchange[Message: [Body is instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] EventHelper TRACE Notification
of event is disabled: ID-DEVSERVER-56006-1408531950289-0-15 exchange
created: Exchange[Message: [Body is instance of
org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] DefaultUnitOfWork TRACE Adding
synchronization OnCompletion[CachedOutputStream]
[http-bio-8080-exec-13] CamelHttpTransportServlet TRACE Processing
request for exchangeId: ID-DEVSERVER-56006-1408531950289-0-15
[http-bio-8080-exec-13] CamelInternalProcessor TRACE Processing
exchange for exchangeId: ID-DEVSERVER-56006-1408531950289-0-15 ->
Exchange[Message: [Body is instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] Pipeline TRACE ExchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 should continue routing: true
[http-bio-8080-exec-13] Pipeline TRACE Processing
exchangeId: ID-DEVSERVER-56006-1408531950289-0-15 >>> Exchange[Message:
[Body is instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] CamelInternalProcessor TRACE Processing
exchange for exchangeId: ID-DEVSERVER-56006-1408531950289-0-15 ->
Exchange[Message: [Body is instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] DefaultErrorHandler TRACE isRunAllowed()
-> true (Run allowed if we are not stopped/stopping)
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
org.apache.camel.converter.stream.InputStreamCache -> java.lang.String with
value: org.apache.camel.converter.stream.InputStreamCache@4ee3990b
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Using
converter: StaticMethodTypeConverter: public static java.lang.String
org.apache.camel.converter.IOConverter.toString(java.io.InputStream,org.apache.camel.Exchange)
throws java.io.IOException to convert [class
org.apache.camel.converter.stream.InputStreamCache=>class java.lang.String]
[http-bio-8080-exec-13] route4 INFO
{'HostName':'DEVSERVER','IpAddress':'192.168.1.42','x64':true,'OperatingSystem':'Windows
Host'}
[http-bio-8080-exec-13] InstrumentationProcessor TRACE log: Recording
duration: 0 millis for exchange: Exchange[Message: [Body is instance of
org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] DefaultErrorHandler TRACE Is exchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 interrupted? false
[http-bio-8080-exec-13] DefaultErrorHandler TRACE Is exchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 done? true
[http-bio-8080-exec-13] CamelInternalProcessor TRACE Exchange
processed and is continued routed synchronously for exchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 -> Exchange[Message: [Body is
instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] Pipeline TRACE Processing
exchangeId: ID-DEVSERVER-56006-1408531950289-0-15 is continued being
processed synchronously
[http-bio-8080-exec-13] Pipeline TRACE ExchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 should continue routing: true
[http-bio-8080-exec-13] Pipeline TRACE Processing
exchangeId: ID-DEVSERVER-56006-1408531950289-0-15 >>> Exchange[Message:
[Body is instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] CamelInternalProcessor TRACE Processing
exchange for exchangeId: ID-DEVSERVER-56006-1408531950289-0-15 ->
Exchange[Message: [Body is instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] DefaultErrorHandler TRACE isRunAllowed()
-> true (Run allowed if we are not stopped/stopping)
[http-bio-8080-exec-13] SendProcessor DEBUG >>>>
Endpoint[ahc://
http://localhost:58100/api/servers?bridgeEndpoint=true&clientConfig.compressionEnabled=true&throwExceptionOnFailure=false]
Exchange[Message: [Body is instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Setting url
http://localhost:58100/api/servers?address=localhost:58100/api/servers
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Setting method
POST
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
org.apache.catalina.connector.ResponseFacade -> java.lang.String with
value: org.apache.catalina.connector.ResponseFacade@6063f5af
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Fallback type
converter org.apache.camel.impl.converter.ToStringTypeConverter@635c80a4
converted type from: java.lang.String to:
org.apache.catalina.connector.ResponseFacade
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Adding header
breadcrumbId = ID-DEVSERVER-56006-1408531950289-0-16
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Adding header
accept = */*
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Adding header
address = localhost:58100/api/servers
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
org.apache.catalina.connector.RequestFacade -> java.lang.String with value:
org.apache.catalina.connector.RequestFacade@40bbc1f6
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Fallback type
converter org.apache.camel.impl.converter.ToStringTypeConverter@635c80a4
converted type from: java.lang.String to:
org.apache.catalina.connector.RequestFacade
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Adding header
user-agent = curl/7.21.7 (amd64-pc-win32) libcurl/7.21.7 OpenSSL/0.9.8r
zlib/1.2.5
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
org.apache.camel.converter.stream.InputStreamCache ->
com.ning.http.client.BodyGenerator with value:
org.apache.camel.converter.stream.InputStreamCache@4ee3990b
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
org.apache.camel.component.http.HttpMessage ->
com.ning.http.client.BodyGenerator with value: Message: [Body is instance
of org.apache.camel.StreamCache]
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Setting body
com.ning.http.client.generators.InputStreamBodyGenerator@7255cf3f
[http-bio-8080-exec-13] DefaultAhcBinding TRACE Setting
Content-Type application/json
[http-bio-8080-exec-13] AhcProducer DEBUG Executing
request
http://localhost:58100/api/servers?address=localhost%3A58100%2Fapi%2Fservers
POST headers: breadcrumbId:ID-DEVSERVER-56006-1408531950289-0-16 accept:*/*
address:localhost:58100/api/servers user-agent:curl/7.21.7 (amd64-pc-win32)
libcurl/7.21.7 OpenSSL/0.9.8r zlib/1.2.5 Content-Type:application/json
[http-bio-8080-exec-13] CamelInternalProcessor TRACE Exchange
processed and is continued routed asynchronously for exchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 -> Exchange[Message: [Body is
instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] Pipeline TRACE Processing
exchangeId: ID-DEVSERVER-56006-1408531950289-0-15 is continued being
processed asynchronously
[http-bio-8080-exec-13] CamelInternalProcessor TRACE Exchange
processed and is continued routed asynchronously for exchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 -> Exchange[Message: [Body is
instance of org.apache.camel.StreamCache]]
[http-bio-8080-exec-13] AsyncProcessorHelper TRACE Waiting for
asynchronous callback before continuing for exchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 -> Exchange[Message: [Body is
instance of org.apache.camel.StreamCache]]
[ New I/O worker #2] AhcProducer TRACE
ID-DEVSERVER-56006-1408531950289-0-15 onStatusReceived
com.ning.http.client.providers.netty.ResponseStatus@70d76d51
[ New I/O worker #2] AhcProducer TRACE
ID-DEVSERVER-56006-1408531950289-0-15 onHeadersReceived
com.ning.http.client.providers.netty.ResponseHeaders@a200d0c
[ New I/O worker #2] AhcProducer TRACE
ID-DEVSERVER-56006-1408531950289-0-15 onBodyPartReceived 2134 bytes
[ New I/O worker #2] AhcProducer TRACE
ID-DEVSERVER-56006-1408531950289-0-15 onCompleted
[ New I/O worker #2] EventHelper TRACE Notification
of event is disabled: ID-DEVSERVER-56006-1408531950289-0-15 exchange
Exchange[Message: [Body is instance of java.io.InputStream]] sent to:
Endpoint[ahc://
http://localhost:58100/api/servers?bridgeEndpoint=true&clientConfig.compressionEnabled=true&throwExceptionOnFailure=false]
took: 5048 ms.
[ New I/O worker #2] InstrumentationProcessor TRACE to: Recording
duration: 5049 millis for exchange: Exchange[Message: [Body is instance of
java.io.InputStream]]
[ New I/O worker #2] DefaultErrorHandler TRACE Is exchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 interrupted? false
[ New I/O worker #2] DefaultErrorHandler TRACE Is exchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 done? true
[ New I/O worker #2] Pipeline TRACE ExchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 should continue routing: false
[ New I/O worker #2] Pipeline TRACE Processing
complete for exchangeId: ID-DEVSERVER-56006-1408531950289-0-15 >>>
Exchange[Message: [Body is instance of java.io.InputStream]]
[ New I/O worker #2] CamelInternalProcessor TRACE route:
Recording duration: 5051 millis for exchange: Exchange[Message: [Body is
instance of java.io.InputStream]]
[ New I/O worker #2] AsyncProcessorHelper TRACE Asynchronous
callback received for exchangeId: ID-DEVSERVER-56006-1408531950289-0-15
[http-bio-8080-exec-13] AsyncProcessorHelper TRACE Asynchronous
callback received, will continue routing exchangeId:
ID-DEVSERVER-56006-1408531950289-0-15 -> Exchange[Message: [Body is
instance of java.io.InputStream]]
[http-bio-8080-exec-13] CamelHttpTransportServlet TRACE Writing
response for exchangeId: ID-DEVSERVER-56006-1408531950289-0-15
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: localhost:58100/api/servers
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: Wed, 20 Aug 2014 10:58:48
GMT
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value:
ID-DEVSERVER-56006-1408531950289-0-16
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: ASP.NET
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: 4.0.30319
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.Integer -> java.lang.String with value: 500
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Using
converter: StaticMethodTypeConverter: public static java.lang.String
org.apache.camel.converter.ObjectConverter.toString(java.lang.Integer) to
convert [class java.lang.Integer=>class java.lang.String]
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: /tinyproxy2
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
org.apache.catalina.connector.RequestFacade -> java.lang.String with value:
org.apache.catalina.connector.RequestFacade@40bbc1f6
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Fallback type
converter org.apache.camel.impl.converter.ToStringTypeConverter@635c80a4
converted type from: java.lang.String to:
org.apache.catalina.connector.RequestFacade
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: curl/7.21.7
(amd64-pc-win32) libcurl/7.21.7 OpenSSL/0.9.8r zlib/1.2.5
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: application/json;
charset=utf-8
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: chunked
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: no-cache
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value:
http://localhost:8080/camelstubs/camel/tinyproxy2
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: -1
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: POST
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value:
/camelstubs/camel/tinyproxy2
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value:
=?UTF-8?B?QzpcUHJvamVjdHNcSHR0cFRlc3RzXEh0dHBUZXN0c1xhcGlcc2VydmVycw==?=
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
org.apache.catalina.connector.ResponseFacade -> java.lang.String with
value: org.apache.catalina.connector.ResponseFacade@6063f5af
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Fallback type
converter org.apache.camel.impl.converter.ToStringTypeConverter@635c80a4
converted type from: java.lang.String to:
org.apache.catalina.connector.ResponseFacade
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.Integer -> java.lang.String with value: 2134
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Using
converter: StaticMethodTypeConverter: public static java.lang.String
org.apache.camel.converter.ObjectConverter.toString(java.lang.Integer) to
convert [class java.lang.Integer=>class java.lang.String]
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value:
address=localhost:58100/api/servers
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: Microsoft-IIS/8.0
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: no-cache
[http-bio-8080-exec-13] DefaultTypeConverter TRACE Converting
java.lang.String -> java.lang.String with value: */*
[http-bio-8080-exec-13] DefaultHttpBinding DEBUG Streaming
response in chunked mode with buffer size 8192
[http-bio-8080-exec-13] IOHelper TRACE Copying
InputStream: java.io.ByteArrayInputStream@28ce41cc -> OutputStream:
org.apache.catalina.connector.CoyoteOutputStream@227db754 with buffer: 2134
and flush on each write true
[http-bio-8080-exec-13] DefaultUnitOfWork TRACE UnitOfWork
done for ExchangeId: ID-DEVSERVER-56006-1408531950289-0-15 with
Exchange[Message: [Body is instance of java.io.InputStream]]
[http-bio-8080-exec-13] DefaultUnitOfWork TRACE Invoking
synchronization.onComplete: OnCompletion[CachedOutputStream] with
Exchange[Message: [Body is instance of java.io.InputStream]]
[http-bio-8080-exec-13] EventHelper TRACE Notification
of event is disabled: ID-DEVSERVER-56006-1408531950289-0-15 exchange
completed: Exchange[Message: [Body is instance of java.io.InputStream]]
On 20 August 2014 11:01, Raul Kripalani <[email protected]> wrote:
> You can enable logging in the AHC library by setting the appropriate log
> categories to DEBUG or TRACE level in your log stack configuration.
>
> This will show what AHC is actually sending to the backend.
>
> If you are using AHC 1.8.x, the logging category to enable is
> com.ning.http.
>
> It could happen that the payload is being sent, but along with some
> additional HTTP request headers which may confuse the backend
> (Content-Type, Content-Length, etc.).
>
> Regards,
>
> *Raúl Kripalani*
> Apache Camel PMC Member & Committer | Enterprise Architect, Open Source
> Integration specialist
> http://about.me/raulkripalani | http://www.linkedin.com/in/raulkripalani
> http://blog.raulkr.net | twitter: @raulvk
>
> On Wed, Aug 20, 2014 at 9:15 AM, Jaume Sancho <[email protected]> wrote:
>
> > Hi Claus,
> >
> > It does sound a lot like that, but unfortunately that didn't work either.
> >
> > from("servlet:///tinyproxy")
> > .streamCaching()
> > //.log("${body}")
> > .to("ahc:
> >
> >
> http://localhost/api/servers?bridgeEndpoint=true&throwExceptionOnFailure=false
> > ");
> >
> > When the log is enabled I do actually see the body in the console output,
> > but it's still not received the by the server at other end.
> > I also tried removing the "log" call, in case it could have been
> consuming
> > the stream, but same result.
> >
> > Any other suggestions?
> >
> >
> > Thanks very much, I really appreciate you taking the time to answer such
> > beginner questions.
> >
> > Jaume
> >
> >
> >
> >
> > On 19 August 2014 19:02, Claus Ibsen <[email protected]> wrote:
> >
> > > Hi
> > >
> > > Sounds a bit like this
> > > http://camel.apache.org/why-is-my-message-body-empty.html
> > >
> > > On Tue, Aug 19, 2014 at 6:11 PM, Jaume Sancho <[email protected]> wrote:
> > > > Hi,
> > > >
> > > > I am in the process of creating a Camel-based proxy that takes in
> > > requests
> > > > on a Tomcat Servlet, does some internal processing, and ultimately
> > > returns
> > > > the responses that you would expect when accessing the targeted
> server
> > > > itself.
> > > >
> > > > In its simplest implementation this works just fine for GET and
> DELETE
> > > > requests.
> > > >
> > > > from("servlet:///tinyproxy")
> > > > .log("${body}")
> > > > .to("ahc:
> > > >
> > >
> >
> http://localhost/api/servers?bridgeEndpoint=true&throwExceptionOnFailure=false
> > > > ");
> > > >
> > > > However, when I try to do the same with an AHC component, the body*
> of
> > > POST
> > > > and PUT requests is not being received at the other end.
> > > >
> > > > If I change the module to http4, the body of the request is received,
> > and
> > > > the appropriate response is forwarded back to the sender.
> > > >
> > > > from("servlet:///tinyproxy2")
> > > > .log("${body}")
> > > >
> > >
> >
> .to("http4:localhost/api/servers?bridgeEndpoint=true&throwExceptionOnFailure=false");
> > > >
> > > > The log message does actually print the body as it is provided by the
> > > > original request, so that should confirm that the setup of
> Camel/Tomcat
> > > > should be OK.
> > > >
> > > > *Here are some very simple examples of request bodies that fail to be
> > > > passed through when using AHC.
> > > >
> > > > JSON: (using single quotes to avoid parsing issues with Camel)
> > > > {'HostName':'DEVSERVER'}
> > > >
> > > > XML:
> > > > <ServerDetails xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
> > > xmlns="
> > > > http://schemas.datacontract.org/2004/07/HttpTests.Models">
> > > > <HostName>DEVServer</HostName>
> > > > </ServerDetails>
> > > >
> > > > This is occurring with the version 2.13.2 of all components:
> > camel-core,
> > > > camel-servletlistener, camel-http4, camel-ahc
> > > > I'm sending the http requests with Curl.
> > > >
> > > > Could I be missing something entirely obvious?
> > > >
> > > >
> > > > Thanks,
> > > >
> > > > Jaume
> > >
> > >
> > >
> > > --
> > > Claus Ibsen
> > > -----------------
> > > Red Hat, Inc.
> > > Email: [email protected]
> > > Twitter: davsclaus
> > > Blog: http://davsclaus.com
> > > Author of Camel in Action: http://www.manning.com/ibsen
> > > hawtio: http://hawt.io/
> > > fabric8: http://fabric8.io/
> > >
> >
>