Camel unmarshal Rest response exception - java

I'm facing an issue with unmarshalling response from Rest call
My camel-context.xml looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:cxf="http://camel.apache.org/schema/cxf"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf-2.8.3.xsd">
<bean class="com.myapp.MyProcessor" id="myResponseProcessor"/>
<camelContext id="camelId" xmlns="http://camel.apache.org/schema/spring">
<camel:route id="myServiceCreate">
<!-- SKIPPING PREPARATION PART -->
<log message="BODY ----- ${body}"/>
<marshal>
<json library="Jackson"/>
</marshal>
<setHeader headerName="CamelHttpMethod">
<constant>POST</constant>
</setHeader>
<to uri="{{services.myuri}}/create"/>
<log message="Message: ${body}"></log>
<unmarshal>
<json library="Jackson" unmarshalTypeName="com.myapp.MyPojo"/>
</unmarshal>
<process id="_processMyResponse" ref="myResponseProcessor"/>
</camel:route>
</camelContext>
</beans>
As a result I get an exception
Caused by: com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
at [Source: org.apache.camel.converter.stream.CachedOutputStream$WrappedInputStream#68de2df1; line: 1, column: 0]
I've tried adding a cast to String:
<convertBodyTo type="String"/>
but it caused exception with BufferedStream.
Logs show that a response is ok:
17:13:25.532 [http-nio-0.0.0.0-8080-exec-1] INFO myServiceCreate - Message: {"collectionId":"123"}
How can I fix unmarshalling?

The reason unmarshalling started working after you removed the logging is because the body is of the type InputStream which means the stream will be flushed after accessing it the first time, which in this case would be the log.
If, as you say, you need to have logging then add the cast to String before logging, i.e. immediately after to.
<to uri="{{services.myuri}}/create"/>
<convertBodyTo type="java.lang.String" />
<log message="Message: ${body}"></log>
<unmarshal>
<json library="Jackson" unmarshalTypeName="com.myapp.MyPojo"/>
</unmarshal>
Edit
I also found this FAQ which explains this phenomenon.

Related

How to handle errors after sending request(camel-http)?

I want to handle errors depending on the http code response.
I would also like to know how to enable *throwExceptionOnFailure* on my route. For example, if the response code is 500x, send the message to the queue "redmine_errors"
UPDATE 4:
my blueprint after add exception from answer #fg78nc (don't work)
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://cxf.apache.org/blueprint/jaxws http://cxf.apache.org/schemas/blueprint/jaxws.xsd
http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
">
<bean id="tfsToRedmineMapper"
class="com.stackabuse.example.TfsToRedmineMapper" />
<bean id="myBean" class="com.stackabuse.example.MyBean" />
<camelContext
xmlns="http://camel.apache.org/schema/blueprint">
<onException>
<exception>org.apache.camel.http.common.HttpOperationFailedException
</exception>
<onWhen>
<method ref="myBean" method="parseException" />
</onWhen>
<handled>
<constant>true</constant>
</handled>
<to uri="log:redmine_errors" />
</onException>
<route>
<from uri="jetty:http://0.0.0.0:8082/test" />
<inOnly uri="activemq://from_tfs" />
</route>
<route>
<from uri="activemq://from_tfs" />
<process ref="tfsToRedmineMapper" />
<to uri="activemq://for_redmine" />
</route>
<route>
<from uri="activemq://for_redmine" />
<setHeader headerName="Content-Type">
<constant>application/json; charset=utf-8</constant>
</setHeader>
<setHeader headerName="X-Redmine-API-Key">
<constant>my_redmine_api_token</constant>
</setHeader>
<toD uri="${header.url}" />
</route>
ERROR:
2019-02-15 09:35:12,103 | ERROR | mix-7.0.1/deploy | BlueprintCamelContext | 40 - org.apache.camel.camel-blueprint - 2.16.5 | Error occurred during starting Camel: CamelContext(camel-32) due Failed to create route route48 at: >>> OnException[null When[bean{} -> []] -> [To[activemq://redmine_errors]]] <<< in route: Route(route48)[[From[jetty:http://0.0.0.0:8082/test]] -> [On... because of org.apache.camel.http.common.HttpOperationFailedException
org.apache.camel.FailedToCreateRouteException: Failed to create route route48 at: >>> OnException[null When[bean{} -> []] -> [To[activemq://redmine_errors]]] <<< in route: Route(route48)[[From[jetty:http://0.0.0.0:8082/test]] -> [On... because of org.apache.camel.http.common.HttpOperationFailedException
enter image description here
enter image description here
Unfortunately, Camel does not set correctly Http status code.
Solution below is a little bit convoluted, but it works.
It can also be solved within XML with the simple language predicate, but somehow it did not work for me, so I used Java for predicate.
Blueprint :
<bean id="myBean" class="com.example.MyBean" />
<onException>
<exception>org.apache.camel.http.common.HttpOperationFailedException</exception>
<onWhen>
<method ref="myBean" method="parseException" />
</onWhen>
<handled>
<constant>true</constant>
</handled>
<to uri="jms:redmine_errors"/>
</onException>
Java :
package com.example;
public class MyBean {
public boolean parseException(Exchange exchange){
return exchange.getProperty("CamelExceptionCaught")
.toString().contains("statusCode: 500");
}
}

Performance issue in Camel cxf 2.20.0

Environment :Camel 2.20.0
Java 1.8
Hit rate : 150hits/second
We are trying to upgrade our Camel version to 2.20.0 but we encouter some troubles and memory leak between camel-cxf 2.19.5 and 2.20.0.
We have a Camel route (exposing a CXF Endpoint) which write the payload in a file thanks log4j and move it every 15s in another folder.
The second Camel route read the file from the other folder and split it (and do some Processor).
In our test, the split just log the message "****** FOO BAR ****".
Due to the upgrade of the cxf library, our server crash outOfMemory and the garbage Collector isn't efficient as in the 2.19.5 version.
Is there any change between the 2 versions ?
Is there any configuration to change to keep our server stable ?
We can see these troubles (in 2.20.0) in VisualVM that the memory graph increase until the maximum memory and crash.
Thanks in advance.
First route exposing the CXF
<cxf:cxfEndpoint id="frontalSupervision" address="/supervision" endpointName="s:supervisionSOAP" serviceName="s:supervision"
wsdlURL="wsdl/supervision.wsdl" xmlns:s="http://*****/supervision/">
<cxf:properties>
<entry key="dataFormat" value="PAYLOAD" />
<entry key="receiveTimeout" value="${ws.cxf.receiveTimeout}"/>
</cxf:properties>
<cxf:inInterceptors>
<ref bean="supervision-authentication" />
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<routeContext id="webservice-to-log4j2-route-context" xmlns="http://camel.apache.org/schema/spring">
<route id="webservice-to-log4j2-route">
<from uri="cxf:bean:frontalSupervision" />
<!-- permet de logger le contenu de la requete -->
<to uri="log:body?level=DEBUG" />
<process ref="log4j2LoggerProcessor" />
</route>
</routeContext>
-
The seconde route :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<routeContext id="log4j2-to-bdd-route-context" xmlns="http://camel.apache.org/schema/spring">
<route id="log4j2-to-bdd-route">
<from
uri="file:///{{messages.log.directory}}/{{messages.log.rolling.relative.directory}}?delete={{messages.files.delete}}&antInclude={{messages.log.filename}}*.log&maxMessagesPerPoll={{messages.maxmessageperpoll}}&sortBy={{messages.sort.by}}&delay={{messages.delay}}" />
<split streaming="true" parallelProcessing="true"
executorServiceRef="splitExecutor">
<tokenize token="{{messages.xmltype.name}}" xml="true" regex="true"/>
<log message="******* FOO BAR *****" />
</split>
</route>
</routeContext>
</beans>

get return value from bean in jboss

package ats.emvo.routing;
public class routingpath {
public String RoutingPathToXml() {
String requestLogPath ="file:///d:/in"; //(String) AtsBundleActivator.atsEmvoRoutingProperties.get("requestlogpath");
return requestLogPath;
}
}
i want to get this return string to bean in jboss fuse as route path
up to now i called it like below in camel cxml,but i dont get the return value here.
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<camelContext id="cbr-example-context" xmlns="http://camel.apache.org/schema/blueprint">
<route id="_route1">
<from id="_from1" uri="bean:routingInInterceptor"/>
<to id="_to2" uri="file:///d:/out"/>
</route>
</camelContext>
<bean class="ats.emvo.routing.routingpath" id="routingInInterceptor"/>
</blueprint>
I will propose another approaches if you want to follow.
According to Camel, "the bean: component binds beans to Camel message exchanges". So if you after a bean call print the Exchange message body you will see the contents coming form bean.
...
<uri="bean:routingInInterceptor"/>
<log message=Contents of bean: ${body}/> <!-- "file:///d:/in" -->
...
So information is put in Exchange.
In your case, you want to start your route "from" not from a hard-coded endpoint URI.
Approach 1
For that reason you can use property placeholders in endpoint URIs. So after you set up properties place holders you can have something like
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0">
<!-- add file your-configuration-file.cfg with your properties under etc/ -->
<cm:property-placeholder persistent-id="your-configuration-file">
<cm:default-properties>
<cm:property name="your.property" value="file:///d:/in"/>
</cm:default-properties>
</cm:property-placeholder>
<camelContext id="cbr-example-context" xmlns="http://camel.apache.org/schema/blueprint">
<route id="_route1">
<from id="_from1" uri="{{your.property}}"/>
<to id="_to2" uri="file:///d:/out"/>
</route>
</camelContext>
<!-- Actually bean is not needed since you will get the endpoint from properties file -->
<bean class="ats.emvo.routing.routingpath" id="routingInInterceptor"/>
</blueprint>
More details about properties component http://camel.apache.org/properties.html.
Approach 2
Another aproach is to have dynamics endpoints with toD tag, to evaluate the endpoints on runtime. So, you can have something like
<route id="_route1">
<from id="_from1" uri="${header.dynamicUri}}"/>
<to id="_to2" uri="file:///d:/out"/>
</route>
More deatils about are in http://camel.apache.org/message-endpoint.html at section Dynamic To.

how to throttle in camel context

I am using Apache camel and jboss fuse, I have created a sample route blue print listed below in, i have sucessfully handling exceptions in all my routes now the problem is i can not find any example of throttling in routes as i have defined. in apache camel documentation, they have given simple DSL throttling and in stackoverflow i have found rabbitMq throttling which is not my case. how to throttle routes like this in apache camel
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<cxf:rsServer address="/testservice" id="testserver" serviceClass="com.company.HelloBean">
<camelContext id="testContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route id="testRoute" >
<throttle timePeriodMillis="10000">
<constant>3</constant>
<from id="_from1" uri="cxfrs:bean:testserver"/>
<bean beanType="com.company.HelloBean"
id="_bean1" method="hello"/>
</throttle>
</route>
</camelContext>
</blueprint>
this give error when in deploy application in jboss fuse. that can not find service
hy, all you need is you are currently defining your from endpoint in throttle tag which is wrong you need to define the throttling tag only in TO tag like this
<throttle id="_throttle1" rejectExecution="true" timePeriodMillis="10000">
<constant>1</constant>
<bean beanType="com.company.HelloBean"
id="_bean1" method="hello"/>
</throttle>
when requests come to an end point from, you will throttle while requests are going TO another end point you are using beans so, you can do something like this
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<cxf:rsServer address="/testservice" id="testserver" serviceClass="com.evampsaanga.gethomepage.GetHomePageDataLand">
<cxf:providers>
<bean class="com.evampsaanga.restresponses.ExceptionHandler" id="securityException"/>
</cxf:providers>
</cxf:rsServer>
<!-- <bean class="com.saanga.servicetest.THR" id="myPolicy"/> -->
<camelContext id="testContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route id="testRoute" >
<from id="_from1" uri="cxfrs:bean:testserver"/>
<log id="_log1" message="header : ${headers}"/>
<setHeader headerName="headerbalance" id="_setHeader1">
<simple>${headers}</simple>
</setHeader>
<setBody id="_setBody1">
<simple>${body}</simple>
</setBody>
<throttle id="_throttle1" rejectExecution="true" timePeriodMillis="10000">
<constant>1</constant>
<bean beanType="com.evampsaanga.gethomepage.GetHomePageDataLand"
id="_bean1" method="Get"/>
</throttle>
</route>
</camelContext>
</blueprint>

Sending message from HTTP endpoint to JMS

I am trying to have a camel route, which would accept a payload on a http endpoint and then write that payload to a JMS queue.
The route that I have so far is below. But an empty message gets delivered to the jms queue. A message gets there, but it has no body.
Heres the route:
<route >
<from uri="jetty:http://0.0.0.0:8050/add/Customer"/>
<inOnly uri="jms:queue:Q.Customer" />
</route>
Heres the payload that I'm sending into to 'http://0.0.0.0:8050/add/Customer' endpoint:
<Customer xmlns="http://www.openapplications.org/9" xmlns:lw="http://www.org/9">
<Name>John</Name>
<Gender>Female</Gender>
</Customer>
Any inputs on why the message body is not being written to the jms queue?
Thanks...
Your routes worked as expected. I tested it with following setup:
<broker xmlns="http://activemq.apache.org/schema/core" useJmx="true" persistent="false">
<transportConnectors>
<transportConnector uri="tcp://localhost:61616" />
</transportConnectors>
</broker>
<bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="failover:tcp://localhost:61616" />
</bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route >
<from uri="jetty:http://0.0.0.0:8050/add/Customer"/>
<inOnly uri="jms:queue:Q.Customer" />
</route>
<route>
<from uri="jms:queue:Q.Customer" />
<log message="Body: ${body}" />
</route>
</camelContext>
I tested the route using the org.apache.camel.spring.Main helper class:
Main main = new Main();
main.setApplicationContextUri("META-INF/spring/jms-inout-producer.xml"); // change this
main.start();
final Object body = "<Customer xmlns=\"http://www.openapplications.org/9\" xmlns:lw=\"http://www.org/9\"><Name>John</Name><Gender>Female</Gender></Customer>";
final ProducerTemplate template = main.getCamelTemplate();
template.requestBody("http://localhost:8050/add/Customer", body);
This lead to following output:
INFO Body: <Customer xmlns="http://www.openapplications.org/9" xmlns:lw="http://www.org/9"><Name>John</Name><Gender>Female</Gender></Customer>

Categories

Resources