I have a server and client application in which both use Apache Camel to configure and manage their routing. I am trying to use the REST component to make a POST request from the client to the server, and send a message in the request body. It seems that the REST endpoint is being invoked, but the body is not making it through. I assume I'm either missing some steps, or I'm doing it incorrectly.
There is a separate problem where the client makes a GET request, the server generates and returns a response, but the client is having a problem getting the response message.
Another thing to mention is that I'm using a generic message class that can essentially contain any object (including arrays of bytes or chars). Perhaps this is part (or maybe all) of the cause behind the problems I'm having.
GenericMessage.java:
public class GenericMessage<T extends Object> {
private T payload;
public GenericMessage(T payload) {
this.payload = payload;
}
public T getPayload() {
return payload;
}
public void setPayload(T payload) {
this.payload = payload;
}
@Override
public String toString() {
return "GenericMessage [payload=" + payload + "]";
}
}
Server
camel-context.xml:
<camelContext id="camel-context" xmlns="http://camel.apache.org/schema/spring">
<restConfiguration component="jetty" bindingMode="json"
contextPath="/" host="localhost" port="9100">
<dataFormatProperty key="prettyPrint" value="true" />
</restConfiguration>
<rest>
<get uri="/data?size={size}" produces="JSON">
<route id="get-data-by-size">
<log loggingLevel="INFO" message="start - get-data-by-size" />
<process ref="get-request-processor" />
<log loggingLevel="INFO" message="end - get-data-by-size" />
</route>
</get>
<post uri="post-data" consumes="json">
<route id="post-data">
<log loggingLevel="INFO" message="start - post-data" />
<process ref="post-request-processor" />
<log loggingLevel="INFO" message="end - post-data" />
</route>
</post>
</rest>
</camelContext>
GetRequestProcessor.java:
@Component("get-request-processor")
public class GetRequestProcessor implements Processor {
@Autowired
private DataProvider provider;
public void process(Exchange exchange) throws Exception {
int size = exchange.getIn().getHeader("size", Integer.class);
// TODO currently only sends char[] data
GenericMessage<?> data = provider.getCharData(size);
exchange.getMessage().setBody(data, GenericMessage.class);
}
}
PostRequestProcessor.java:
@Component("post-request-processor")
public class PostRequestProcessor implements Processor {
private final Logger logger = LoggerFactory.getLogger(PostRequestProcessor.class);
public void process(Exchange exchange) throws Exception {
GenericMessage<?> data = exchange.getIn().getBody(GenericMessage.class);
if (data != null) {
logger.info("process: object received: {}", data);
} else {
logger.warn("process: null object");
}
}
}
DataProvider.java:
@Component
public class DataProvider {
private final Logger logger = LoggerFactory.getLogger(DataProvider.class);
public GenericMessage<?> getByteData(final int size) {
logger.info("getByteData: size={}", size);
return new GenericMessage<byte[]>(DataGenerator.generateByteArray(size));
}
public GenericMessage<?> getCharData(final int size) {
logger.info("getCharData: size={}", size);
return new GenericMessage<char[]>(DataGenerator.generateCharArray(size));
}
}
Client
camel-context.xml:
<camelContext id="camel-context" xmlns="http://camel.apache.org/schema/spring">
<restConfiguration component="jetty" bindingMode="json"
contextPath="/" host="{{http-client.server.host}}"
port="{{http-client.server.port}}">
<dataFormatProperty key="prettyPrint" value="true" />
</restConfiguration>
<route id="rest-get">
<from
uri="timer:{{http-client.timers.http-get.name}}?delay={{http-client.timers.http-get.start-delay}}&fixedRate=true&period={{http-client.timers.http-get.period}}&repeatCount={{http-client.timers.http-get.repeat-count}}" />
<log loggingLevel="INFO" message="start - rest-get" />
<to uri="rest:get:{{http-client.endpoints.http-get}}" />
<process ref="process-get-response" />
<log loggingLevel="INFO" message="end - rest-get" />
</route>
<route id="rest-post">
<from
uri="timer:{{http-client.timers.http-post.name}}?delay={{http-client.timers.http-post.start-delay}}&fixedRate=true&period={{http-client.timers.http-post.period}}&repeatCount={{http-client.timers.http-post.repeat-count}}" />
<log loggingLevel="INFO" message="start - rest-post" />
<process ref="add-post-body" />
<to uri="rest:post:{{http-client.endpoints.http-post}}" />
<log loggingLevel="INFO" message="end - rest-post" />
</route>
</camelContext>
AddPostRequestBody.java:
@Component("add-post-body")
public class AddPostRequestBody implements Processor {
private final Logger logger = LoggerFactory.getLogger(AddPostRequestBody.class);
@Autowired
private DataProvider provider;
@Override
public void process(Exchange exchange) throws Exception {
GenericMessage<?> data = null;
int intValue = RandomUtil.generateInt(1);
switch (intValue) {
case 0:
data = provider.produceByteArrayData();
break;
case 1:
data = provider.produceCharArrayData();
break;
default:
break;
}
logger.info("adding POST request body:\n{}", data);
exchange.getMessage().setHeader(Exchange.HTTP_METHOD, "POST");
exchange.getMessage().setHeader(Exchange.CONTENT_TYPE, "application/json");
exchange.getMessage().setBody(data, GenericMessage.class);
}
}
GetResponseProcessor.java:
@Component("process-get-response")
public class GetResponseProcessor implements Processor {
private final Logger logger = LoggerFactory.getLogger(GetResponseProcessor.class);
@Override
public void process(Exchange exchange) throws Exception {
GenericMessage<?> body = (GenericMessage<?>) exchange.getIn().getBody();
logger.info("body: {}", body);
}
}
DataProvider.java:
@Component
public class DataProvider {
private final Logger logger = LoggerFactory.getLogger(DataProvider.class);
public GenericMessage<byte[]> produceByteArrayData() {
int size = RandomUtil.generateInt(1000, 20000000);
byte[] bytes = DataGenerator.generateByteArray(size);
logger.info("produceByteArrayData: generated {} bytes", size);
GenericMessage<byte[]> data = new GenericMessage<>(bytes);
return data;
}
public GenericMessage<char[]> produceCharArrayData() {
int size = RandomUtil.generateInt(1000, 20000000);
char[] chars = DataGenerator.generateCharArray(size);
logger.info("produceCharArrayData: generated {} characters", size);
GenericMessage<char[]> data = new GenericMessage<>(chars);
return data;
}
}
I have it configured to do one GET and one POST request from the client. There are logging statements scattered about to give an idea what is going on.
I start the server, then the client and there are two problems that I can see:
- There is an error when it attempts to serialize the GET response message.
- The POST request body is not making it to the server side.
Client console:
2020-04-10 14:42:38.678 INFO 19968 --- [ main] o.a.c.i.e.AbstractCamelContext : Route: rest-get started and consuming from: timer://http-get
2020-04-10 14:42:38.680 INFO 19968 --- [ main] o.a.c.i.e.AbstractCamelContext : Route: rest-post started and consuming from: timer://http-post
2020-04-10 14:42:38.684 INFO 19968 --- [ main] o.a.c.i.e.AbstractCamelContext : Total 2 routes, of which 2 are started
2020-04-10 14:42:38.684 INFO 19968 --- [ main] o.a.c.i.e.AbstractCamelContext : Apache Camel 3.1.0 (CamelContext: RESTClient) started in 1.715 seconds
...
2020-04-10 14:42:38.695 INFO 19968 --- [imer://http-get] rest-get : start - rest-get
2020-04-10 14:42:38.701 INFO 19968 --- [ main] e.m.l.m.ApplicationMain : Started ApplicationMain in 5.176 seconds (JVM running for 7.624)
2020-04-10 14:42:39.021 ERROR 19968 --- [imer://http-get] o.a.c.p.e.DefaultErrorHandler : Failed delivery for (MessageId: ID-489789-MITLL-1586544159020-0-1 on ExchangeId: ID-489789-MITLL-1586544159020-0-1). Exhausted after delivery attempt: 1 caught: java.lang.ClassCastException: org.apache.camel.converter.stream.CachedOutputStream$WrappedInputStream cannot be cast to edu.mit.ll.mission_services.model.GenericMessage
Message History (complete message history is disabled)
---------------------------------------------------------------------------------------------------------------------------------------
RouteId ProcessorId Processor Elapsed (ms)
[rest-get ] [rest-get ] [from[timer://http-get?delay=0&fixedRate=true&period=1000&repeatCount=1] ] [ 337]
...
[rest-get ] [process1 ] [ref:process-get-response ] [ 0]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
java.lang.ClassCastException: org.apache.camel.converter.stream.CachedOutputStream$WrappedInputStream cannot be cast to edu.mit.ll.mission_services.model.GenericMessage
at edu.mit.ll.mission_services.processor.GetResponseProcessor.process(GetResponseProcessor.java:18) ~[classes/:?]
at org.apache.camel.support.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:64) ~[camel-support-3.1.0.jar:3.1.0]
at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:396) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:153) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:60) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:147) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:286) [camel-base-3.1.0.jar:3.1.0]
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:198) [camel-timer-3.1.0.jar:3.1.0]
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:78) [camel-timer-3.1.0.jar:3.1.0]
at java.util.TimerThread.mainLoop(Timer.java:555) [?:1.8.0_241]
at java.util.TimerThread.run(Timer.java:505) [?:1.8.0_241]
...
2020-04-10 14:42:41.182 INFO 19968 --- [mer://http-post] rest-post : start - rest-post
2020-04-10 14:42:41.455 INFO 19968 --- [mer://http-post] e.m.l.m.s.DataProvider : produceCharArrayData: generated 15775578 characters
2020-04-10 14:42:41.455 INFO 19968 --- [mer://http-post] e.m.l.m.p.AddPostRequestBody : adding POST request body:
GenericMessage [payload=[C@572d6e9b]
2020-04-10 14:42:43.497 INFO 19968 --- [mer://http-post] rest-post : end - rest-post
Server console:
2020-04-10 14:42:25.598 INFO 22860 --- [ main] o.a.c.i.e.AbstractCamelContext : Route: get-data-by-size started and consuming from: jetty:http://localhost:9100/data
2020-04-10 14:42:25.599 INFO 22860 --- [ main] o.a.c.i.e.AbstractCamelContext : Route: post-data started and consuming from: jetty:http://localhost:9100/post-data
2020-04-10 14:42:25.607 INFO 22860 --- [ main] o.a.c.i.e.AbstractCamelContext : Total 2 routes, of which 2 are started
2020-04-10 14:42:25.607 INFO 22860 --- [ main] o.a.c.i.e.AbstractCamelContext : Apache Camel 3.1.0 (CamelContext: RESTServer) started in 0.342 seconds
...
2020-04-10 14:42:38.901 INFO 22860 --- [qtp913796146-39] get-data-by-size : start - get-data-by-size
2020-04-10 14:42:38.902 INFO 22860 --- [qtp913796146-39] e.m.l.m.s.DataProvider : getCharData: size=500
2020-04-10 14:42:38.905 INFO 22860 --- [qtp913796146-39] get-data-by-size : end - get-data-by-size
2020-04-10 14:42:43.097 INFO 22860 --- [qtp913796146-34] post-data : start - post-data
2020-04-10 14:42:43.100 WARN 22860 --- [qtp913796146-34] e.m.l.m.p.PostRequestProcessor : process: null object
2020-04-10 14:42:43.100 INFO 22860 --- [qtp913796146-34] post-data : end - post-data
Please login or Register to submit your answer