exception handling in apache servicemix - exception

I am new to ServiceMix am trying on exception handling in ServiceMix.
when I try to print the exception, it also contains the body of the request in it. Is there any way that I can extract only the errors from exception?
<from uri="activemq:topic://topic1"/>
<!-- Schema validationm for the request received from Biblio -->
<doTry>
<to uri="validator:http://localhost/employee.xsd"/>
<doCatch>
<exception>java.lang.Exception</exception>
<log message="${exception.message}"/>
</doCatch>
</doTry>
below is the logged exception:
org.apache.xerces.jaxp.validation.SimpleXMLSchema#a0059b5
errors: [
org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: 'asd' is not a valid value for 'integer'., Line : -1, Column : -1
org.xml.sax.SAXParseException: cvc-type.3.1.3: The value 'asd' of element 'empnumber' is not valid., Line : -1, Column : -1
]. Exchange[ID-GBSMIXDEV01-uk-oup-com-46713-1511957485149-83-2][Message: <empRecord>
<employee>
<empnumber>asd</empnumber>
<surname>PM</surname>
<firstname>Abhinay</firstname>
</employee>
</empRecord>]
I am getting the correct exception but I dont want the below part in the exception.
Is there any way I can remove these from the exception message?
Exchange[ID-GBSMIXDEV01-uk-oup-com-46713-1511957485149-83-2][Message: <empRecord>
<employee>
<empnumber>asd</empnumber>
<surname>PM</surname>
<firstname>Abhinay</firstname>
</employee>
</empRecord>]

That message is coming from the exception, so you can manipulate the string inside a Processor.
Write a simple class to do this:
private static final Logger logger_ = LoggerFactory
.getLogger(ExceptionMsgProcessor.class);
public void process(Exchange exchange) {
Exception e = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
String msg = e.getMessage();
// manipulate the string here
log.info("Exception message: {}", msg);
}
And then send the Exception to this bean
<doTry>
<to uri="validator:http://localhost/employee.xsd"/>
<doCatch>
<exception>java.lang.Exception</exception>
<to uri="bean:exceptionMsgProcessor" />
</doCatch>
</doTry>

Related

How to unit test an apache camel cxfrs route?

I have a working cxfrs route. I can hit the rest service using SoapUi with a json object and get a response.
I wanted to write unit tests, and I though to use CamelTestSupport. My routebuilder configure() method looks something like this:
from(cxfrsEndpoint)
.recipientList(simple("direct:${header.operationName}"))
.setHeader(Exchange.CONTENT_LENGTH, simple("-1"));
from("direct:submitRequest")
.bean("responseBean", "checkJson")
.bean("responseBean", "createSuccessResponse");
When I hit the url from SoapUi (http://localhost:8181/cxf/myContext/submitRequest) as a POST with an appropriate json string, I get a "success" json back. Cool.
In my unit test, I created an overriden createRouteBuilder method:
#Override
protected RouteBuilder createRouteBuilder() {
MyRouteBuilder myRouteBuilder = new MyRouteBuilder();
myRouteBuilder.setCxfrsEndpoint("direct:start");
return myRouteBuilder;
}
And then my unit test (I thought) would look something like this:
#Test
public void thisIsATest() throws Exception {
MyRequest myRequest = new MyRequest();
request.setSomeProperty("Some property value");
ObjectMapper objectMapper = new ObjectMapper();
String goodJsonRequest = objectMapper.writeValueAsString(request);
String response = (String) template.requestBodyAndHeader(START_POINT, goodJsonRequest, "operationName", "submitRequest");
assertNotNull(response);
//Omitted: further assertions for content of the response json
}
Well, when I execute the unit test, I get an unmarshalling exception with this as the cause:
Caused by: com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character '{' (code 123) in prolog; expected '<'
at [row,col {unknown-source}]: [1,1]
at com.ctc.wstx.sr.StreamScanner.throwUnexpectedChar(StreamScanner.java:647)
at com.ctc.wstx.sr.BasicStreamReader.nextFromProlog(BasicStreamReader.java:2054)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1131)
at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:164)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:415)
... 74 more
It doesn't like my json string. What is the real service receiving?
On the real route, I enabled logging on the endpoint in the blueprint.xml like this:
<!-- RouteBuilder declarations -->
<bean id="myRouteBuilder" class="com.mycompany.MyRouteBuilder">
<property name="cxfrsEndpoint" value="cxfrs:bean:cxfrsEndpoint?bindingStyle=SimpleConsumer&loggingFeatureEnabled=true" />
</bean>
The json string I see in the log as the "Payload:" doesn't look any different than the json string I'm sending via template.requestBodyAndHeader(...).
What am I missing or what am I doing wrong here?
Thanks!
Please, try not rewrite your endpoint like this:
myRouteBuilder.setCxfrsEndpoint("direct:start");
Seems to me that overriding your endpoint changes the interface and the CXF now is expecting a XML and not JSON (based on your logs):
Caused by: com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character '{' (code 123) in prolog; expected '<'
at [row,col {unknown-source}]: [1,1]
at com.ctc.wstx.sr.StreamScanner.throwUnexpectedChar(StreamScanner.java:647)
at com.ctc.wstx.sr.BasicStreamReader.nextFromProlog(BasicStreamReader.java:2054)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1131)
at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:164)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:415)
... 74 more
You already have the endpoint defined in here:
<bean id="myRouteBuilder" class="com.mycompany.MyRouteBuilder">
<property name="cxfrsEndpoint" value="cxfrs:bean:cxfrsEndpoint?bindingStyle=SimpleConsumer&loggingFeatureEnabled=true" />
</bean>
My suggestion is to use this code as example and call your endpoint directly via HTTP:
public void setUp() throws Exception {
super.setUp();
httpclient = HttpClientBuilder.create().build();
}
public void tearDown() throws Exception {
super.tearDown();
httpclient.close();
}
#Test
public void testGetCustomerOnlyHeaders() throws Exception {
HttpGet get = new HttpGet("http://serviceurl.com");
HttpResponse response = httpclient.execute(get);
assertEquals(200, response.getStatusLine().getStatusCode());
}
If you have a chance, take a look into the entire camel-cxf project tests to have an idea how to properly test.

Return original exception to the client instead of returning CamelExecutionException Apache Camel

I have a camel context defined inside an XML based spring context file.
There is one route, which is being invoked by the SOAP(XML) web service client bean.
While calling the route, it throws some exception and the client receives Camel Exception, instead of the original exception.
Camel response to the client on exception is shown below
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Exception occurred during execution on the exchange: Exchange[ID-CZC4101XJV-53724-1497351782614-9-2]</faultstring>
</soap:Fault>
Expected response should be the original exception message on
any exception
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>blah blah blah Number Not valid, I am the original exception</faultstring>
</soap:Fault>
Here is my camel route definition
<route>
<from uri="direct:remove" />
<to uri="bean:removeBean?method=validationNubmer" />
<to uri="bean:removeBean?method=checkBusiness" />
<to uri="bean:removeBean?method=triggerRemove" />
</route>
And below the SOAP bean operation which sends an XML request to the
route
public void removeMe(String id) {
RemoveRequest request = new RemoveRequest();
request.setId(id);
producer.requestBody("direct:remove", request);
}
I read the exception clause topic from the Apache Camel documentation, but I couldn't find any information on how to return the original exception to the client, sad!! any help?
I tried using camel onException but no luck :(
<onException>
<exception>java.lang.Exception</exception>
<redeliveryPolicy maximumRedeliveries="0" />
<handled>
<constant>true</constant>
</handled>
<transform>
<simple>Error Occurred: ${exception.message}</simple>
</transform>
</onException>
You can turn on handleFault to let exceptions automatic be transformed to SOAP faults. See Camel in Action 2 book, chapter 11, which has a little example: https://github.com/camelinaction/camelinaction2/tree/master/chapter11/errorhandler#1136---handling-faults
Or you need to use <setFaultBody> instead of <transform> to tell Camel you are setting the message body as a SOAP fault.

Modify the handled exception fault message in Apache camel

In my camel route, I am making a direct-vm call to an existing bundle. In that service, they have handled the exception and setting up some custom fault message. When any exception occurs in that service they are sending fault message like below.
{
"errorCode": "400",
"errorMessage": "Unknown error"
}
But I need to form my own custom fault message based on the fault message received. But once an exception occurs in second bundle, i am not able to recive the fault message and modify it. below is how my route looks.
<route handleFault="true" streamCache="true" id="route1">
<from uri="cxfrs://bean://testCxf?synchronous=true"/>
<log message="The consumer message ${body}"/>
<bean ref="requestValidator" method="validateRequest"/>
<to uri="direct-vm:retrieveData"/>
<bean ref="validateResponse" method="validate"/>//need to manipulate the fault message coming from bundle 2 in this bean.
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<bean ref="faultMapper" method="mapFault"/>
</onException>
</route>
Below is the existing direct:vm route.
<route handleFault="true" streamCache="true" id="route2">
<from uri="direct-vm:retrieveData"/>
<bean ref="manipulateData" method"manipulate"/>
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<bean ref="faultMapper1" method="mapFault1"/>
</onException>
</route>
i need to intercept the fault that is mapped in the class faultmapper1, in my route1 after the direct-vm call.How to acheive this?. I will not be allowed to change anything in the existing 2nd bundle. Thanks in advance.
After some research found that this is not possible. To achieve the requirement, I have made the handled constant as false in the second route and added a , block in the first route. So that I can catch the exception thrown and handled it with some custom fault mapping.

Apache-cxf client gets SOAPFaultException instead of custom exception

I'm having troubles with handling Exceptions in my apache-cxf client.
I'm expecting an exception that is thrown by the soap call 'Fault_Exception' but I'm always receiving the common SOAPFaultException
Generated classes:
#WebFault(name = "FaultMessage", targetNamespace = "http://a.b.c/ws/")
public class Fault_Exception extends Exception {
private a.b.c.Fault faultMessage;
....
}
and Fault is
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "fault", propOrder = {
"code",
"description",
"stack"
})
public class Fault {
...
}
soap:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>EXCEPTION</faultstring>
<detail>
<Fault xmlns:n1="http://a.b.c/ws/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://a.b.c/ws/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="n1:fault">
<code xmlns="http://a.b.c/ws/">error.code.1</code>
<description xmlns="http://a.b.c/ws/">some description of the error.</description>
<stack xmlns="http://a.b.c/ws/">....</stack>
</Fault>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Is there a mismatch between the generated classes and the response ?
Or what else can be the problem of this?
Or is it totally logic that I get a SOAPFaultException? I have no clue how to get the information (code & description) then ...
Kind regards!

Struts2 Application hides my exceptions after adding Interceptor

So I have a Struts2 application that I'm working on. On my front page I have a section that will display any exceptions my application throws. This worked well until I added a custom Interceptor.
Here is my interceptor code:
public String intercept(ActionInvocation actionInvocation) throws Exception {
String result = actionInvocation.invoke();
return result;
}
This is the code in my Action class where the exception gets generated, it occurs where AuthService.Authorize() is called:
if(AuthService.Authorize(username, password)) {
if(AuthService.AdminAuthorized()) {
return "admin";
}
return SUCCESS;
}
This is inside of AuthService.Authorize(), it throws a null point exception when acc is accessed :
try {
acc = profileRepository.WhereSingle("Username", "=", username);
} catch (Exception e) {
return false;
}
if (acc.Password.equals(password)) {
However, when the page is loaded. This is not populated:
<s:property value="%{exception.message}"/>
I have tested it and it would work if I was simply throwing an exception from the Action class. I am not calling a redirectAction or anything
Here is the top of my default package definition which all my other packages extend
<package name="default" namespace="/" extends="struts-default">
<!-- Interceptors -->
<interceptors>
<interceptor name="conversation" class="global.ConversationInterceptor"/>
<interceptor-stack name="dils-stack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="conversation"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="dils-stack"/>
<global-results>
<result name="Exception" >/index.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="Exception"/>
<exception-mapping exception="java.lang.NullPointerException" result="Exception"/>
</global-exception-mappings>
How is your interceptor stack defined for that action? The ExceptionMappingInterceptor should be defined first in the stack. Can you post the interceptor stack configuration from your struts.xml? Your custom interceptor should not be interfering (it does nothing).
Updated:
I was able to reproduce this issue, however it occurs for me with or without your custom interceptor.
The reason is that you are specifically looking for the exception message, which is not set for NullPointerExceptions that are automatically thrown (as in your case). You can confirm this by instead displaying the stack trace, such as: %{exceptionStack}
%{exception.message} is null for the NullPointerException, and so it displays nothing. If instead you were to throw an exception with a message (e.g., throw new RuntimeException("OMG!");), then you will see the message.
Also, note that you must specify more specific exception mappings before less specific mappings in your struts.xml. Because NullPointerException is more specific than Exception, you must list it first. Note that this doesn't really matter in your example, because they map to the same thing. Just know that your NPE will map to the first entry, not the second.