I had an issue come up during development of a CXF-RS route that I couldn’t find a solution to with a quick bit of googling (I’m no Google ninja so that’s not saying much). To summarize, no matter what value I populated as the response code, the route would always return a 200 response :S
Basically I had a route with an onException guard. That part of the route I show below, but to summarize, if it encountered any exception it would send it to the exception processor and then stop. The cxf route itself for this demo did one thing, threw an exception.
<jaxrs:server id="restServerLoc" address="${publicAddress}">
<jaxrs:providers>
<ref bean="jaxbProvider" />
<ref bean="jsonProvider" />
</jaxrs:providers>
<jaxrs:serviceBeans>
<ref bean="terminalLocationRest" />
</jaxrs:serviceBeans>
</jaxrs:server>
<bean id="forced" class="java.lang.IllegalArgumentException">
<constructor-arg index="0" value="This is forced" />
</bean>
<bean id="exceptionProcessor" class="com.kramkroc.example.support.ExceptionProcessor" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder location="ref:service-properties" id="properties"/>
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<to uri="bean:exceptionProcessor"/>
<stop/>
</onException>
<route>
<from uri="cxfrs://bean://restServerLoc"/>
<throwException ref="forced"/>
</route>
</camelContext>
The following was the bare bones of the processor I was using:
package com.kramkroc.example.support;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExceptionProcessor implements Processor {
private final Logger logger = LoggerFactory.getLogger(getClass());
public void process(Exchange exchange) throws Exception {
try {
processException(exchange);
} catch (IllegalArgumentException e) {
logger.error("Exception Processor Called but could not find an exception to process", e);
}
}
private void processException(final Exchange exchange) {
Exception exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
logger.error("The following was caught!", exception);
logger.debug("About to Process incoming [{}]", exception.getClass().getName());
int httpResponseCode = 400;
if (exception instanceof NullPointerException) {
buildResponse(exchange, httpResponseCode, exception.getLocalizedMessage());
} else {
httpResponseCode = 500;
buildResponse(exchange, httpResponseCode, exception.getLocalizedMessage());
}
}
private void buildResponse(Exchange exchange, final int httpResponseCode, final String requestError) {
exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, httpResponseCode);
exchange.getOut().setHeader(Exchange.CONTENT_TYPE, "application/json");
logger.debug("Returning Request Error [{}]", requestError);
exchange.getOut().setBody(requestError, String.class);
}
}
Again, the problem was that in spite of setting the error response code as expected, the route was always returning a 200 response!
Somehow the penny dropped: what if instead of building an error the camel way, I build it the CXF way instead, I.e through the Response objects. Eureka!
See an example of the updated processor below:
package com.kramkroc.example.support;
import javax.ws.rs.core.Response;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExceptionProcessor implements Processor {
private final Logger logger = LoggerFactory.getLogger(getClass());
public void process(Exchange exchange) throws Exception {
try {
processException(exchange);
} catch (IllegalArgumentException e) {
logger.error("Exception Processor Called but could not find an exception to process", e);
}
}
private void processException(final Exchange exchange) {
Exception exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
logger.error("The following was caught!", exception);
logger.debug("About to Process incoming [{}]", exception.getClass().getName());
int httpResponseCode = 400;
if (exception instanceof NullPointerException) {
buildResponse(exchange, httpResponseCode, exception.getLocalizedMessage());
} else {
httpResponseCode = 500;
buildResponse(exchange, httpResponseCode, exception.getLocalizedMessage());
}
}
private void buildResponse(Exchange exchange, final int httpResponseCode, final String requestError) {
final Response r = Response.status(httpResponseCode).entity(requestError).build();
exchange.getOut().setBody(r);
logger.debug("Returning das Request Error [{}]", r);
}
}