How can I pass parameter from Apache CXF to Camel - web-services

I am working currently on project where Apache CXF is integrated with Apache Camel. Apache CXF is a solution that we use to expose a WebService then marshal/unmarshal SOAP request and pass it to Camel. This is pretty standard. By default a POJO dataFormat in ApacheCXF is used however there is a need for getting some information form SOAP headers "" and pass it to Camel. My question is how to do this? When I use Interceptor in Apache CXF I can get information that I need but I cannot pass it then to Camel. The class below is a CXF Interceptor
public class MyInterceptor extends AbstractSoapInterceptor {
//..... some variables
#Override
public void handleMessage(SoapMessage message) throws Fault {
//..some logic and then setting a variable
message.getExchange().put("Foo", "Bar");
}
}
... and class below is Camel Processor that is eventually called:
public class MyCamelProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
//how can I read information from CXF Intercptor here?
//how can I read "Foo" value?
}
}
I understand that Exchange class that is used by Apache CXF is different then Exchange used by Camel however there should be a way of passing information between these two integrated technologies?

Finally, I solved it how follow:
In my context, I have a consumer service with camel-cxf component which is routed to Processor.
CxfEndpoint class from Camel has a method call setInInterceptors:
public void setInInterceptors(List<org.apache.cxf.interceptor.Interceptor<? extends org.apache.cxf.message.Message>> interceptors)
Therefore, if we define the next in our beans definitions file:
...
<cxf:cxfEndpoint id="consumerId"
address="/myservice"
serviceClass="com.example.service.MyServiceSEI">
<cxf:inInterceptors>
<ref bean="myInterceptor"/>
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean id="myInterceptor" class="com.example.interceptors.MyInterceptor" />
Then, in our custom Interceptor we can set any variable in a map
...
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
...
public class MyInterceptor extends AbstractSoapInterceptor {
public MyInterceptor() {
super(Phase.RECEIVE);
}
#Override
public void handleMessage(SoapMessage message) throws Fault {
//..some logic and then setting a variable
message.getExchange().put("Foo", "Bar");
}
}
Finally, we can get the variables in our Processor, using org.apache.cxf.message.Message class, different from org.apache.camel.Message used with Exchange.getIn() method
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.cxf.message.Message;
import org.apache.camel.component.cxf.common.message.CxfConstants;
public class MyCamelProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
//how can I read information from CXF Intercptor here?
//how can I read "Foo" value?
Message cxfMessage = exchange.getIn().getHeader(CxfConstants.CAMEL_CXF_MESSAGE, Message.class);
String foo = (String) cxfMessage.getExchange().get("Foo");
// read message from camel context
org.apache.camel.Message inMessage = exchange.getIn();
...
}
}
Thanks: http://camel.465427.n5.nabble.com/Getting-entire-Soap-Message-with-header-and-body-in-Payload-mode-td5753162.html

Related

How to send the contents of a file downloaded from aws s3 using apache camel in json format?

I have a rest api using apache camel. When I hit a post request on a route, it gets a file from S3. Here is the code for that ->
public static class HelloRoute extends RouteBuilder {
#Override
public void configure() {
rest("/")
.post("file-from-s3")
.route()
.setHeader(AWS2S3Constants.KEY, constant("filename"))
.to("aws2-s3://bucketname?accessKey=INSERT&secretKey=INSERT&region=INSERT&operation=getObject")
.endRest();
}
}
This gives the content of the file in Postman. I want the response in a json format where the contents of the file will be in the content key of json. How to do this?
Make sure you have binding mode enabled (auto|json) in your REST configuration and the consumes/produces set on your route. Now write your processor to build your response object and set it in the body. Camel will handle the rest for you.
public static class HelloRoute extends RouteBuilder {
restConfiguration().component("netty-http").host("localhost").port(portNum).bindingMode(RestBindingMode.auto);
#Override
public void configure() {
rest("/")
.post("file-from-s3")
.consumes("application/json").type(YourRequest.class)
.produces("application/json").outType(YourResponse.class)
.route()
.setHeader(AWS2S3Constants.KEY, constant("filename"))
.to("aws2-s3://bucketname?accessKey=INSERT&secretKey=INSERT&region=INSERT&operation=getObject")
//.process("responseBuilderProcessor")
.endRest();
}
}

Create a JUnit for Camel route and processor

I am new to JUnit. I am trying to write test case for camel route and processor. I don't know how to start. Here is my route
from("activemq:queue1").process("queueprocessor").toD("activemq:queue2").
I need help to mock my endpoints and processor.
Here mocked all endpoints using "isMockEndpoints" & added expected body content to endpoint(activemq:queue2) and by sending same content as input to mocked endpoint(activemq: queue1) verified assert is satisfied or not.
public class MockEndpointsJUnit4Test extends CamelTestSupport {
#Override
public String isMockEndpoints() {
// override this method and return the pattern for which endpoints to mock.
// use * to indicate all
return "*";
}
#Test
public void testMockAllEndpoints() throws Exception {
// notice we have automatic mocked all endpoints and the name of the endpoints is "mock:uri"
getMockEndpoint("mock:activemq:queue2").expectedMessageCount(1);
getMockEndpoint("mock:activemq:queue2").expectedBodiesReceived("Hello World");
template.sendBody("mock:activemq:queue1", "Hello World");
getMockEndpoint("mock:activemq:queue2").assertIsSatisfied();
/* additional test to ensure correct endpoints in registry */
/* all the endpoints was mocked */
assertNotNull(context.hasEndpoint("mock:activemq:queue1"));
assertNotNull(context.hasEndpoint("mock:activemq:queue2"));
}
}

how to get Soap action from wsdl and generated java files. as my wsdl imports another wsdl which has #webmethod in it

i have a wsdl which is importing another wsdl in it.
i wanted to call the webservice from java client code, i have configured my java class as follows
package test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
#Configuration
public class WeConfig {
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("test");
return marshaller;
}
#Bean
public WeatherClient1 weatherClient(Jaxb2Marshaller marshaller) {
WeatherClient1 client = new WeatherClient1();
client.setDefaultUri("*******");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
I have my acessing method as follows
GetDataResponse response = (GetDataResponse) getWebServiceTemplate()
.marshalSendAndReceive(
"*******",
request,
new SoapActionCallback("*******"));
My webservice would be something like
https://abcde.handling.com/celebrity/Confi?wsdl
Kindly let me know , what i have to input in setdefaultUri in configuration and soapcallbackaction. soap Ui gives me a method "GetData" for request
Thanks in advance..
Please help ..
After a long struggle , the answer for this query will be as follows;
DefaultUri = (Full WSDL) https://abcde.handling.com/celebrity/Confi?wsdl
there was no call back action for my request so:
GetDataResponse response = (GetDataResponse) getWebServiceTemplate()
.marshalSendAndReceive(
"Imported wsdl's URI",
request);

How to use Spring Autowired in a custom cxf interceptor?

i seem to run into a small issue when using #Autowired into a custom cxf interceptor.
My use case is that i want to log soap messages and send these using AMQP to another system. This process works for normal services etc.
But whatever i do, the needed properties do not get autowired and stay null.
I checked the Spring DI log and the context is scanned and pickedup, so what am i missing?
Is this even possible in CXF interceptors?
#Component
public class LogInInterceptor extends AbstractSoapInterceptor {
private #Value("#{rabbitMQProperties['rabbitmq.binding.log.soap']}")
String binding;
#Autowired
AmqpTemplate amqpTemplate;
public LogInInterceptor() {
super(Phase.RECEIVE);
}
#Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
logIt(soapMessage);
}
private void logIt(SoapMessage message) throws Fault {
// rest of the code omitted...!!!
amqpTemplate.convertAndSend(binding, buffer.toString());
}
}
You can't mix #InInterceptors (a CXF annotation) and #Component (a Spring annotation). That will create two separate instances of your interceptor: the one whose dependencies are getting injected by Spring, and one created by CXF. (You are providing class names in the #InInterceptors annotation, not a bean ID, so CXF has no way of knowing that you already created an instance in the Spring context.)
Remove the #InInterceptors annotation and, in addition to the component scan:
<context:component-scan base-package="org.example.config"/>
You also need something like this in your application context:
<jaxws:endpoint id="myWebService" address="/MyWebService">
<jaxws:inInterceptors>
<ref bean="myInInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
I know this is an old question, but Jonathan W's answer helped me and I would like to add to it.
This is how I got custom interceptors and #Autowired to work with Spring Boot 1.3.1:
http://cxf.apache.org/docs/jax-ws-configuration.html
import java.util.Arrays;
import javax.jws.WebService;
import org.apache.cxf.Bus;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
#Configuration
#EnableAutoConfiguration
#ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
public class Application extends SpringBootServletInitializer {
#Autowired
private ApplicationContext applicationContext;
#Autowired
private MyInterceptor myInterceptor;
#Autowired
private HelloWorldImpl helloWorldImpl;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
// Replaces the need for web.xml
#Bean
public ServletRegistrationBean servletRegistrationBean(ApplicationContext context) {
return new ServletRegistrationBean(new CXFServlet(), "/api/*");
}
// Replaces cxf-servlet.xml
#Bean
// <jaxws:endpoint id="helloWorld" implementor="demo.spring.service.HelloWorldImpl" address="/HelloWorld"/>
public EndpointImpl helloService() {
Bus bus = (Bus) applicationContext.getBean(Bus.DEFAULT_BUS_ID);
EndpointImpl endpoint = new EndpointImpl(bus, helloWorldImpl);
// Set interceptors here
endpoint.setInInterceptors(Arrays.asList(myInterceptor));
endpoint.publish("/hello");
return endpoint;
}
// Used when deploying to a standalone servlet container, i.e. tomcat
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
// Web service endpoint
#WebService(endpointInterface = "demo.spring.service.HelloWorld")
//#InInterceptors not defined here
public static class HelloWorldImpl {
}
public static class MyInterceptor extends LoggingInInterceptor {
// #Autowired works here
}
}

Pass request information from Servlet Filter to Web Service

I need to retrieve some information sent in the HTTP headers from within a Web Service. How can I achieve this?
It depends on the language and web service framework you want to use.
Your question title mentions "Servlet Filter" so I assume you work with a Java application container. If your ws framework does not support the of mapping request headers into value objects, you could use a Servlet Filter that processes the header and stores the information somewhere you can retrieve it later. The best option would be to put it in a request attribute. If you can't get to the HttpServletRequest later (which probably makes you ask this question), you can store it into a ThreadLocal variable, but this is trickier.
I'll give you a minimal example:
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class Filter implements javax.servlet.Filter {
public ThreadLocal<String> local;
#Override
public void doFilter(ServletRequest req, ServletResponse response,
FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest)req;
String bar = request.getHeader("foo");
local.set(bar);
// you can now retrieve the header value in your code with Filter.local.get()
try {
chain.doFilter(request, response);
} finally {
local.remove(); // clean up
}
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig arg0) throws ServletException {
local = new ThreadLocal<String>();
}
}
It works, but in a real life implementation you should store an Object of your own Class in the ThreadLocal (e.g. a Bean) instead of a mere String. You should consider putting the ThreadLocal variable outside your Filter (e.g. as a static variable somewhere in a more logical place).