JAX-RS Client Connection Timeout Handling in Interceptor - cxf

I have added the below config in my client application context xml:
<bean id="customTimeoutConfigInterceptor" class="com.hs18.inventory.client.interceptor.CustomTimeoutConfigInterceptor" />
<jaxrs:client id="inventoryServiceEndPoint"
address="http://$INVENTORY_CLIENT{inventory.api.host}:$INVENTORY_CLIENT{inventory.api.port}/api/1"
serviceClass="com.inventory.common.InventoryService"
inheritHeaders="true">
<jaxrs:providers>
<ref bean="hs18ResponseExceptionMapper" />
</jaxrs:providers>
<jaxrs:inFaultInterceptors>
<ref bean="customTimeoutConfigInterceptor" />
</jaxrs:inFaultInterceptors>
</jaxrs:client>
when the client times out i want to put the request in a message queue, I am trying this through CustomTimeoutConfigInterceptor class. But the handleMessage method is never invoked. Below is the code.
public class CustomTimeoutConfigInterceptor extends AbstractPhaseInterceptor<Message> {
#Resource
InventoryServiceAsync inventoryServiceAsync;
public CustomTimeoutConfigInterceptor() {
super(Phase.PREPARE_SEND_ENDING);
}
#Override
public void handleMessage(Message message) throws Fault {
Exception exception = message.getContent(Exception.class);
if(exception.getMessage().equals("Connection Refused")){
if(message.getContent(List.class) != null && !message.getContent(List.class).isEmpty()){
Object request = message.getContent(List.class).get(0);
if(request.getClass().getAnnotation(Command.class) != null){
inventoryServiceAsync.sendCommand((ICommand)request);
}
}
}
}
}

Is this for a JAX-RS client reaching out to some external endpoint? If so, I can tell a couple of things:
The connection timeout or client timeout happen on the "out" part of the communications stack, so you may want to set it on the outFaultInterceptors instead
From the previous point follows that the phase set on your interceptor constructor also needs to be updated, I have tried setting it to Phase.POST_STREAM and seems to be working.

Related

apache camel: custom sftp configuration with sftp component

I am trying to add a custom sftp component in Apache Camel to wrap the username, host, port and password in a configuration object to be passed to a sftpcomponent.
Below is the code that I have tried:
#Configuration
class SftpConfig {
#Bean("sourceSftp")
public SftpComponent getSourceSftpComponent(
#Qualifier("sftpConfig")
SftpConfiguration sftpConfig) throws Exception{
SftpComponent sftpComponent = new SftpComponent();
// not getting way to set the configuration
return sftpComponent;
}
#Bean("sftpConfig")
public SftpConfiguration getSftpConfig(
#Value("${host}") String host,
#Value("${port}") int port,
#Value("${applicationUserName}") String applicationUserName,
#Value("${password}") String password) {
SftpConfiguration sftpConfiguration = new SftpConfiguration();
sftpConfiguration.setHost(host);
sftpConfiguration.setPort(port);
sftpConfiguration.setUsername(applicationUserName);
sftpConfiguration.setPassword(password);
return sftpConfiguration;
}
}
//In other class
from("sourceSftp:<path of directory>") ---custom component
A similar approach in JMSComponent works fine where I have created a bean for sourcejms, but I am not able to do it for sftp as SftpComponent doesn't have set call for sftpconfiguration.
The Camel maintainers seem to be moving away from providing individual components with a "setXXXConfiguration" method to configure their properties. The "approved" method of providing properties -- which works with the SFTP -- is to specify them on the connection URL:
from ("sftp://host:port/foo?username=foo&password=bar")
.to (....)
An alternative approach is to instantiate an endpoint and set its properties, and then use a reference to the endpoint in the from() call. There's a gazillion ways of configuring Camel -- this works for me for XML-based configuration:
<endpoint id="fred" uri="sftp://acme.net/test/">
<property key="username" value="xxxxxxx"/>
<property key="password" value="yyyyyyy"/>
</endpoint>
<route>
<from uri="fred"/>
<to uri="log:foo"/>
</route>
You can customize it by extending the SftpComponent. This allows you to define multiple endpoints without providing the username/password for each endpoint definition.
Step 1: Extend SftpComponent and give your component a custom name, ie customSftp
#Component("customSftp")
public class CustomSftpComponent extends SftpComponent {
private static final Logger LOG = LoggerFactory.getLogger(CustomSftpComponent.class);
#Value("${sftp.username}")
private String username;
#Value("${sftp.password}")
private String password;
#SuppressWarnings("rawtypes")
protected void afterPropertiesSet(GenericFileEndpoint<SftpRemoteFile> endpoint) throws Exception {
SftpConfiguration config = (SftpConfiguration) endpoint.getConfiguration();
config.setUsername(username);
config.setPassword(password);
}
}
Step 2: Create a camel route to poll 2 different folders using your custom component name.
#Component
public class PollSftpRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("{{sftp.endpoint1}}").routeId("pollSftpRoute1")
.log(LoggingLevel.INFO, "Downloaded file from input folder 1.")
.to("file:data/out1");
from("{{sftp.endpoint2}}").routeId("pollSftpRoute2")
.log(LoggingLevel.INFO, "Downloaded file from input folder 2.")
.to("file:data/out2");
}
}
Step 3: Place this in application.properties
camel.springboot.main-run-controller=true
sftp.endpoint1=customSftp://localhost.net/input/1?delay=30s
sftp.endpoint2=customSftp://localhost.net/input/2?delay=30s
sftp.username=sftp_user1_l
sftp.password=xxxxxxxxxxxx
With this you don't have to repeat the username/password for each endpoints.
Note: With this approach you wont be able to set the username/password in URI endpoint configuration. Anything you set in URI will be replaced in afterPropertiesSet.

How to generate a custom ack with apache camel hl7

I am trying to set up an mllp listener for hl7v2.x messages using camel.
My environment
apache camel and components version 2.18.3
Also I would like to avoid the use of the HAPI library, as I prefer a custom parser for the received and generated messages. As my clients are each one using different versions of the standard and really different fields usage.That's why there is no unmarshalling to the hl7 datatype in the following route, just to string. I'll do the parser myself.
And my route (all the beans and variables are defined elsewhere in the code, I think they are not relevant)
from("netty4:tcp://0.0.0.0:3333?
encoder=#encoderHl7&decoder=#decoderHl7&sync=true")
.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
.unmarshal().string()
.to("file://" + rutaSalidaFichero)
;
First, as a prove of concept, I am just trying to copy all the messages received into a file system directory. The messages are correctly received and wrote to the directory. But I do not know how to generate and send the ACK, an incorrect one is being automatically generated and sended.
If I send a hl7 message from an outer/sending system, the camel component send the same message as the ack, so the sending system sends an error in return as it is not the ack expected. I am sending the hl7 message using mirth, dcm4chee, hapi ... all of then with the same result.
For instance, if I send the following message from an outer/sender system
MSH|^~\&|LIS|LIS|HIS|HIS|20170412131105||OML^O21|0000000001|P|2.5|||AL|||8859/1|||1.0
PID|1||123456||APELLIDO1&APELLIDO2^NOMBRE|19200101
ORC|RP|009509452919|317018426||||||20170412000000
OBR|1|317018426|317018426|CULT^CULTIVO
I received the same as the ack in the sending system. This is the camel generating the ack as the receiving message
MSH|^~\&|LIS|LIS|HIS|HIS|20170412131105||OML^O21|0000000001|P|2.5|||AL|||8859/1|||1.0
PID|1||123456||APELLIDO1&APELLIDO2^NOMBRE|19200101
ORC|RP|009509452919|317018426||||||20170412000000
OBR|1|317018426|317018426|CULT^CULTIVO
I have not found in the camel docs references to the generation of the ack, or if I can use a custom "something" to generate it. I would like to change this default behaviour.
This is what I have done on my project:
<bean id="hl7Processor" class="com.mediresource.MessageRouting.HL7.HL7Processor" />
<route>
<from uri="mina2:tcp://10.68.124.140:2575?sync=true&codec=#hl7codec" />
<onException>
<exception>org.apache.camel.RuntimeCamelException</exception>
<exception>ca.uhn.hl7v2.HL7Exception</exception>
<redeliveryPolicy maximumRedeliveries="0" />
<handled>
<constant>true</constant>
</handled>
<bean ref="hl7Processor" method="sendACKError" />
</onException>
<bean ref="hl7Processor" method="sendACK" />
</route>
On class HL7Processor I have this:
public Message sendACK(Message message, Exchange exchange ) throws HL7Exception, IOException {
logger.debug("Entering");
Message ack = message.generateACK();
logger.info("(10-4), End - ACK sent for " + exchange.getExchangeId());
return ack;
}
public Message sendACKError(Message message, Exception ex) throws HL7Exception, IOException {
try {
logger.warn("Internal Error:" + ex);
Message ack = message.generateACK(AcknowledgmentCode.AE, new HL7Exception("Internal Error") );
logger.warn("(10-4), End - NACK");
return ack;
} catch (Exception ex1) {
logger.error("Fatal error on processError! ", ex1);
}
return null;
}
As camel hl7 component docs says (http://camel.apache.org/hl7.html, "HL7 Acknowledgement expression") you can generate default ack just by using
import static org.apache.camel.component.hl7.HL7.ack;
...
from("direct:test1")
// acknowledgement
.transform(ack())
Here "ack()" is a call for "org.apache.camel.component.hl7.HL7#ack()". But you can check that "org.apache.camel.component.hl7.HL7" contains some other helpful methods like
org.apache.camel.component.hl7.HL7#ack(ca.uhn.hl7v2.AcknowledgmentCode code)
or
org.apache.camel.component.hl7.HL7#ack(ca.uhn.hl7v2.AcknowledgmentCode code, java.lang.String errorMessage, ca.uhn.hl7v2.ErrorCode )
You can use them to customise the actual ACK response.
If we will go deeper then you can see that "org.apache.camel.component.hl7.HL7#ack" are just wrappers for
new ValueBuilder(new AckExpression(...))
and most params from "ack" methods are going directly to the org.apache.camel.component.hl7.AckExpression. Actual ACK generation is done in "org.apache.camel.component.hl7.AckExpression#evaluate" and looks like
public Object evaluate(Exchange exchange) {
Throwable t = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class);
Message msg = exchange.getIn().getBody(Message.class);
try {
HL7Exception hl7e = generateHL7Exception(t);
AcknowledgmentCode code = acknowledgementCode;
if (t != null && code == null) {
code = AcknowledgmentCode.AE;
}
return msg.generateACK(code == null ? AcknowledgmentCode.AA : code, hl7e);
} catch (Exception e) {
throw ObjectHelper.wrapRuntimeCamelException(e);
}
}
If you want deeper customization you can just write your own MyCustomAckExpression which will extend org.apache.camel.component.hl7.AckExpression and implement required logic instead of
return msg.generateACK(code == null ? AcknowledgmentCode.AA : code, hl7e);
and use it like
...
from("direct:test1")
// acknowledgement
.transform(new ValueBuilder(new MyCustomAckExpression()))

Application REST Client on Karaf

I'am writing a simple . application deploying on Karaf 4.1.0. It's role is sending a rest request to REST API. When I start my bundle I have an error:
javax.ws.rs.ProcessingException: org.apache.cxf.interceptor.Fault: No message body writer has been found for class package.QueueSharedDTO, ContentType: application/json
at org.apache.cxf.jaxrs.client.WebClient.doResponse(WebClient.java:1149)
at org.apache.cxf.jaxrs.client.WebClient.doChainedInvocation(WebClient.java:1094)
at org.apache.cxf.jaxrs.client.WebClient.doInvoke(WebClient.java:894)
at org.apache.cxf.jaxrs.client.WebClient.doInvoke(WebClient.java:865)
at org.apache.cxf.jaxrs.client.WebClient.invoke(WebClient.java:428)
at org.apache.cxf.jaxrs.client.WebClient$SyncInvokerImpl.method(WebClient.java:1631)
at org.apache.cxf.jaxrs.client.WebClient$SyncInvokerImpl.method(WebClient.java:1626)
at org.apache.cxf.jaxrs.client.WebClient$SyncInvokerImpl.post(WebClient.java:1566)
at org.apache.cxf.jaxrs.client.spec.InvocationBuilderImpl.post(InvocationBuilderImpl.java:145)
at package.worker.service.implementation.ConnectionServiceImpl.postCheckRequest(ConnectionServiceImpl.java:114)
at package.worker.service.implementation.ConnectionServiceImpl.sendCheck(ConnectionServiceImpl.java:103)
at package.worker.module.QueueSharedListener.run(QueueSharedListener.java:37)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.cxf.interceptor.Fault: No message body writer has been found for class package.QueueSharedDTO, ContentType: application/json
at org.apache.cxf.jaxrs.client.WebClient$BodyWriter.doWriteBody(WebClient.java:1222)
at org.apache.cxf.jaxrs.client.AbstractClient$AbstractBodyWriter.handleMessage(AbstractClient.java:1091)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.jaxrs.client.AbstractClient.doRunInterceptorChain(AbstractClient.java:649)
at org.apache.cxf.jaxrs.client.WebClient.doChainedInvocation(WebClient.java:1093)
... 11 more
Caused by: javax.ws.rs.ProcessingException: No message body writer has been found for class com.emot.dto.QueueSharedDTO, ContentType: application/json
at org.apache.cxf.jaxrs.client.AbstractClient.reportMessageHandlerProblem(AbstractClient.java:780)
at org.apache.cxf.jaxrs.client.AbstractClient.writeBody(AbstractClient.java:494)
at org.apache.cxf.jaxrs.client.WebClient$BodyWriter.doWriteBody(WebClient.java:1217)
... 15 more
Initialization WebTarget:
private ConnectionServiceImpl() {
client = ClientBuilder.newClient();
client.property(
ClientProperties.CONNECT_TIMEOUT,
snifferProperties.getProperty(SnifferProperties.PARAM_REST_API_CONNECTION_TIMEOUT));
client.property(
ClientProperties.READ_TIMEOUT,
snifferProperties.getProperty(SnifferProperties.PARAM_REST_API_READ_TIMEOUT));
System.out.println(2);
webTarget = client.target(buildUrl());
}
Send requests :
private synchronized boolean postCheckRequest(String path, Object content) {
boolean result = true;
try {
Response response = webTarget
.path("check")
.path("add/one")
.request(MediaType.APPLICATION_JSON)
.post(Entity.json(content));
result = (response.getStatus() == 200);
} catch (Exception e) {
System.out.println("Error but working");
e.printStackTrace();
result = false;
}
return result;
}
I have always the problems with Karaf... i dont understand why it . couldn't working correctly...
The issue you are facing is mostly not a Karaf issue, but a typical issue you may face while working with some JAX-RS implementation in non-JavaEE environment.
Exception literally says that your implementation misses message body writer. Message body writer is the class which implements class javax.ws.rs.ext.MessageBodyWriter and is responsible for serializing your data objects to some format (like JSON). There is another class named javax.ws.rs.ext.MessageBodyReader, which does the opposite thing. All these classes are registered to JAX-RS framework as providers, extending its capabilities. Details are here: https://jersey.java.net/documentation/latest/message-body-workers.html
So, generally you must decide what you use for serializing/deserializing between your data objects and HTTP MediaType and register a proper JAX-RS provider.
With Jackson, for example, your problem can be easily solved by using one of its standard implementation: either com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider, if you use JAXB annotations, or com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider, if you prefer Jackson annotations. Add this class in providers section of your Blueprint descriptor:
<jaxrs:server id="restServer" address="/rest">
<jaxrs:serviceBeans>
....
</jaxrs:serviceBeans>
<jaxrs:providers>
....
<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider"/>
....
</jaxrs:providers>
</jaxrs:server>

ByteArrayDecoder is not #Sharable handler, so can't be added or removed multiple times

I'm trying to run simple echo server for perfomance tests. I set up netty4 tcp endpoint and ByteArrayDecoder for my purporse. Everything works fine while only one/once soket is created. When I want to connect second client, or reconnect the first one I continously get following error:
2015-12-03 14:58:08,218 | WARN | yServerTCPWorker | ChannelInitializer | 175 - io.netty.common - 4.0.27.Final | Failed to initialize a channel. Closing: [id: 0xe9f9fb16, /127.0.0.1:6056
3 => /127.0.0.1:1542]
io.netty.channel.ChannelPipelineException: io.netty.handler.codec.bytes.ByteArrayDecoder is not a #Sharable handler, so can't be added or removed multiple times.
at io.netty.channel.DefaultChannelPipeline.checkMultiplicity(DefaultChannelPipeline.java:464)[178:io.netty.transport:4.0.27.Final]
at io.netty.channel.DefaultChannelPipeline.addLast0(DefaultChannelPipeline.java:136)[178:io.netty.transport:4.0.27.Final]
at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:129)[178:io.netty.transport:4.0.27.Final]
at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:120)[178:io.netty.transport:4.0.27.Final]
at org.apache.camel.component.netty4.DefaultServerInitializerFactory.addToPipeline(DefaultServerInitializerFactory.java:118)[83:org.apache.camel.camel-netty4:2.16.0]
at org.apache.camel.component.netty4.DefaultServerInitializerFactory.initChannel(DefaultServerInitializerFactory.java:100)[83:org.apache.camel.camel-netty4:2.16.0]
at io.netty.channel.ChannelInitializer.channelRegistered(ChannelInitializer.java:69)[178:io.netty.transport:4.0.27.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRegistered(AbstractChannelHandlerContext.java:162)[178:io.netty.transport:4.0.27.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRegistered(AbstractChannelHandlerContext.java:148)[178:io.netty.transport:4.0.27.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRegistered(DefaultChannelPipeline.java:734)[178:io.netty.transport:4.0.27.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:450)[178:io.netty.transport:4.0.27.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.access$100(AbstractChannel.java:378)[178:io.netty.transport:4.0.27.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:424)[178:io.netty.transport:4.0.27.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:357)[175:io.netty.common:4.0.27.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)[178:io.netty.transport:4.0.27.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:111)[175:io.netty.common:4.0.27.Final]
at java.lang.Thread.run(Thread.java:745)[:1.8.0_25]
I was dealing with ByteArrayDecoder to find it is anyway #Sharable. Although I created factory which should return me new instances of ByteArrayDecoder but it also didn't help. I compared the versions of dependent modules on Karaf and seems that they are the same.
Below my blueprint
<!--bean id="decoder" class="io.netty.handler.codec.bytes.ByteArrayDecoder"/-->
<!--bean id="decoder" class="com.company.feature.ChannelHandlerFactoryByteArrayDecoder" factory-method="newChannelHandler"/-->
<bean id="factory" class="com.company.feature.ChannelHandlerFactoryByteArrayDecoder" />
<bean id="decoder" class="io.netty.handler.codec.bytes.ChannelInboundHandlerAdapter" factory-ref="factory" factory-method="newChannelHandler"/>
<bean id="process" class="com.company.feature.Process"/>
<camelContext id="camel_netty_tcp_test" xmlns="http://camel.apache.org/schema/blueprint" allowUseOriginalMessage="false">
<route id="featureRoute">
<from uri="{{feature.in_route}}"/>
<process ref="process"/>
<log message="Received"/>
</route>
</camelContext>
And Factory class which I use
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import org.apache.camel.component.netty4.ChannelHandlerFactory;
import io.netty.channel.ChannelHandler;
public class ChannelHandlerFactoryByteArrayDecoder implements ChannelHandlerFactory {
public ChannelHandler newChannelHandler() {
return (ChannelHandler) new ByteArrayDecoder();
}
public void handlerAdded(ChannelHandlerContext chc) throws Exception {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
public void handlerRemoved(ChannelHandlerContext chc) throws Exception {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
public void exceptionCaught(ChannelHandlerContext chc, Throwable thrwbl) throws Exception {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
To avoid this error for now I inherited from ByteArrayDecoder class and implemented it as follow.
import io.netty.channel.ChannelHandler;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
#ChannelHandler.Sharable
public class MyByteArrayDecoder extends ByteArrayDecoder {
}
After repleacing the return type in factory everything starts to work.

CXF custom validation and FaultOutInterceptors for manage Errors

I have developed a web service using cxf. In case of an error due to a request that doesn't respect the xsd schema asociated I would custom the error sent to the client. For that:
1- I have added a specific EventHandlerValidator and a specific FaultOutInterceptor in web-services.xml
<jaxws:endpoint id="getNewCustomerOrderId" implementor="#getNewCustomerOrderIdWS" address="/GetNewCustomerOrderId">
<jaxws:properties>
<entry key="jaxb-validation-event-handler">
<ref bean="getNewCustomerOrderIdEventHandlerValidator"/>
</entry>
<entry key="schema-validation-enabled" value="IN"/>
<entry key="set-jaxb-validation-event-handler" value="true"/>
</jaxws:properties>
<jaxws:outFaultInterceptors>
<ref bean="getNewCustomerOrderIdCXFFaultOutInterceptor"/>
</jaxws:outFaultInterceptors>
</jaxws:endpoint>`enter code here
2 - I have implemented these classes:
In the handleValidator I just throw my own exception with a code and message
public class GetNewCustomerOrderIdEventHandlerValidator implements ValidationEventHandler {
#Override
public boolean handleEvent(ValidationEvent event) {
throw new MyException(MyExceptionCode.ERCC_GNCOI_100, event.getMessage());
}
}
FaultExceptionInterceptor runs for every exception thrown during webservice call. I only want to catch MyException with code ERCC_GNCOI_100 for customizing it, so:
public class GetNewCustomerOrderIdCXFFaultOutInterceptor extends AbstractSoapInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(CreateCustomerOrderCXFFaultOutInterceptor.class);
#Inject
private CreateCustomerOrderFaultExceptionService createCustomerOrderFaultExceptionService;
private static final JAXBContext jaxbContext;
static {
try {
jaxbContext = JAXBContext.newInstance(CreateCustomerOrderException.class);
} catch (JAXBException e) {
LOGGER.error(CormoranMarker.TECH, "Error during JAXBContext instantiation");
throw new RuntimeException(e);
}
}
public GetNewCustomerOrderIdCXFFaultOutInterceptor() {
super(Phase.MARSHAL);
}
#Override
public void handleMessage(SoapMessage message) throws Fault {
Fault exceptionFault = (Fault) message.getContent(Exception.class);
exceptionFault.setMessage("My custom message");
if (exceptionFault.getCause() instanceof MyException) {
MyException myException = (MyException) exceptionFault
.getCause();
if (myException.getCode().equals(myException.ERCC_GNCOI_100)) {// validation
// schema
// errors
Element elt = buildExceptionFaultDetail(cormoranFunctionalException);
exceptionFault.setDetail(elt);
}
}
}
private Element buildExceptionFaultDetail(CormoranFunctionalException cormoranFunctionalException) {
// Build custom response
}
}
However, in the interceptor I'm not able to catch my exception:
Fault exceptionFault = (Fault) message.getContent(Exception.class);
This line gets an unmarshalling exception:
Unmarshalling Error: cvc-complex-type.2.4.a: Invalid content was found starting with element 'customerOrderType1'. One of '{customerOrderID, version, customerOrderType, depositDate}' is expected.
In the logs I see that My exception has been thrown:
12:32:27.338 [qtp200426125-38] ERROR c.o.c.c.e.MyException - [] - MyException : Non-respect du schéma (XSD) du WebService exposé par Cormoran : cvc-complex-type.2.4.a: Invalid content was found starting with element 'customerOrderType1'. One of '{customerOrderID, version, customerOrderType, depositDate}' is expected.
Could you help me?
Thank you in advance!
Auri
There are two problems with the Interceptor as written.
First, you need to set the new content to the message after you make your changes. To do that, you can add the following to the handleMessage method after your code
message.setContent(Exception.class, exceptionFault);
Second, the phase you chose was too late to make changes to the Fault object. It looks like PRE_STREAM is the latest phase that allows the change. The CXF Interceptor documentation has the full list of phases.
You can modify the message as below.
Fault exceptionFault = (Fault) message..getExchange().getContent(Exception.class);

Resources