How to use Spring Autowired in a custom cxf interceptor? - web-services

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
}
}

Related

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);

Start embedded Jetty using WebApplicationInitializer

I am creating Restful (Jax-RS) services to be deployed to Fuse 6.2.1.
(using Apache CFX, and deploying with OSGi bundles to Karaf)
The server supports only up to Spring 3.2.12.RELEASE.
I am attempting to do everything with next to zero XML configuration.
So far so good, everything is working and I can deploy and run my services.
However, I'd like to be able to test my services locally without having to deploy them. So I'd like to be able to boostrap a webserver and register my servlet, but can't quite figure our how.
I'm configuring the servlet with this (using Spring's WebApplicationInitializer rather than web.xml):
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
public class CxfServletInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(new ContextLoaderListener(createWebAppContext()));
addApacheCxfServlet(servletContext);
}
private void addApacheCxfServlet(ServletContext servletContext) {
CXFServlet cxfServlet = new CXFServlet();
ServletRegistration.Dynamic appServlet = servletContext.addServlet("CXFServlet", cxfServlet);
appServlet.setLoadOnStartup(1);
Set<String> mappingConflicts = appServlet.addMapping("/*");
}
private WebApplicationContext createWebAppContext() {
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(CxfServletConfig.class);
return appContext;
}
}
And my main Spring config looks like this:
import javax.ws.rs.core.Application;
import javax.ws.rs.ext.RuntimeDelegate;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
#Configuration
public class CxfServletConfig {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CxfServletConfig.class);
#Bean(destroyMethod = "shutdown")
public SpringBus cxf() {
return new SpringBus();
}
#Bean
#DependsOn("cxf")
public Server jaxRsServer(ApplicationContext appContext) {
JAXRSServerFactoryBean endpoint = RuntimeDelegate.getInstance().
createEndpoint(jaxRsApiApplication(), JAXRSServerFactoryBean.class);
endpoint.setServiceBeans(Arrays.<Object> asList(testSvc()));
endpoint.setAddress(endpoint.getAddress());
endpoint.setProvider(jsonProvider());
return endpoint.create();
}
#Bean
public Application jaxRsApiApplication() {
return new Application();
}
#Bean
public JacksonJsonProvider jsonProvider() {
return new JacksonJsonProvider();
}
#Bean(name = "testSvc")
public TestService testSvc() {
return new TestService();
}
So just to be clear, the above code is my current, working, deployable configuration. So now I'd like to create a test config that utilizes the same but which also starts Jetty and registers my servlet, and can't quite figure out how. Any help?
Thanks!
EDIT: Turns out I did not need the WebApplicationInitializer at all to get this to work. I ended up creating a Test config for Spring that defines a Jetty server as a bean. Seems to work:
#Configuration
public class TestingSpringConfig {
#Bean (name="jettyServer", destroyMethod = "stop")
public Server jettyServer() throws Exception {
Server server = new Server(0); //start jetty on a random, free port
// Register and map the dispatcher servlet
final ServletHolder servletHolder = new ServletHolder( new CXFServlet() );
final ServletContextHandler context = new ServletContextHandler();
context.setContextPath( "/" );
//fuse uses cxf as base url path for cxf services, so doing so as well here so urls are consistent
context.addServlet( servletHolder, "/mybaseurl/*" );
context.addEventListener( new ContextLoaderListener() );
context.setInitParameter( "contextClass", AnnotationConfigWebApplicationContext.class.getName() );
//this will load the spring config for the CFX servlet
context.setInitParameter( "contextConfigLocation", CxfServletConfig.class.getName() );
server.setHandler( context );
server.start();
//server.join(); if running from a main class instead of bean
return server;
}
#Bean(name = "jettyPort")
#DependsOn("jettyServer")
public Integer jettyPort() throws Exception {
Integer port = jettyServer().getConnectors()[0].getLocalPort();
log.info("Jetty started on port: " + port);
return port;
}
}

How can I pass parameter from Apache CXF to Camel

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

Disable auto generated JAX-WS Status Page

When I deploy and run my web service developed with JAX-WS I can see a summary page with some info on it, something like in this picture:
http://www.mkyong.com/webservices/jax-ws/deploy-jax-ws-web-services-on-tomcat/
For the final implementation we would like to remove this page so that a custom or a blank page is returned while still having access to the web service endpoint.
We are currently running on Tomcat.
There is a field on the WSServlet class that might do what you are looking for: JAXWS_RI_PROPERTY_PUBLISH_STATUS_PAGE (it's value is com.sun.xml.ws.server.http.publishStatusPage).
Looking at the source code from a JAX-WS download it seems that you need to set it as a context parameter in your web.xml file:
<web-app>
<context-param>
<param-name>com.sun.xml.ws.server.http.publishStatusPage</param-name>
<param-value>false</param-value>
</context-param>
...
Seems that HttpAdapter had something similar on it but was taken from an environment variable:
setPublishStatus(
System.getProperty(HttpAdapter.class.getName() + ".publishStatusPage")
.equals("true"));
The code on HttpAdapter is marked deprecated in the javadoc so the context parameter seems the way to go.
I have been trying to solve this for two days, Glassfish 3.1.2.
The only solution was to have
-Dcom.sun.xml.ws.transport.http.HttpAdapter.publishStatusPage=false
I know its old, but wantd to maintain the knowledge. Hope this helps any one with this issue.
I have completed the same task for WebLogic recently.
It was requested to hide/show a status page of a public web service depending on a target environment i.e. hide for production, show for dev.
Nothing of the previous answers worked for me.
The success solution is based on implementation of javax.servlet.Filter.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.HttpMethod;
#WebFilter(urlPatterns = { "/WeblogicWebService" })
public class FilterStatusSoapPage implements Filter {
#Value("${soap.status.page.disabled}")
private boolean flagDisablePublishStatusPage;
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpRes = (HttpServletResponse) response;
String queryString = httpReq.getQueryString();
if(flagDisablePublishStatusPage)
if(queryString == null || queryString.trim().isEmpty())
if(HttpMethod.GET.matches(httpReq.getMethod())) {
httpRes.setStatus(HttpServletResponse.SC_OK);
httpRes.getWriter().write("Access to status page of Web
Service is not allowed");
httpRes.getWriter().flush();
httpRes.getWriter().close();
return;
}
} catch (Exception e) {
System.err.println("Error on FilterStatusSoapPage filter");
chain.doFilter(request, response);
return;
}
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {}
public void destroy() {}
}

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).