#Autowired not working in CXF interceptor + Spring application - spring

Having an issue with how CXF interceptor is setup and used by Spring. I want to log the incoming SOAP requests to database for audit log. I have the setup as below, but whenever incoming SOAP request comes, I get NPE where the service layer class is being accessed. It looks from log that the web application context is being re-loaded again leading to null reference for service bean.
I had a look at the two entries - this and this - which are close, and tried out the solution in first link, but not working.
Any help is appreciated.
Thanks
Interceptor code:
public class AuditLogInterceptor extends AbstractLoggingInterceptor {
private AuditLogService auditLogService;
#Autowired
public void setAuditLogService(AuditLogService auditLogService) {
this.auditLogService = auditLogService;
}
private void saveAuditLogEntry() {
// some more code ...
auditLogService.logRequest(logEntry);
}
cxf-servlet.xml
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
<!-- Add new endpoints for additional services you'd like to expose -->
<bean id="abstractLogInterceptor" abstract="true">
<property name="prettyLogging" value="true" />
</bean>
<bean class="com.xyz.interceptor.AuditLogInterceptor" id="logInInterceptor" parent="abstractLogInterceptor"/>
<jaxws:endpoint id="dataService" implementor="#masterDataService" address="/MasterDataService">
<jaxws:inInterceptors>
<ref bean="logInInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/applicationContext-resources.xml
classpath:/applicationContext-dao.xml
classpath:/applicationContext-service.xml
classpath*:/applicationContext.xml
/WEB-INF/applicationContext*.xml
/WEB-INF/cxf-servlet.xml
/WEB-INF/security.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

I expect you're getting the contents of /WEB-INF/cxf-servlet.xml included in both the CXFServlet's context and the ContextLoaderListener's. Try removing the line /WEB-INF/cxf-servlet.xml from the ContextLoaderListener's contextConfigLocation attribute. You should also rename cxf-servlet.xml because the CXFServlet looks for a file with that exact name (see http://cxf.apache.org/docs/configuration.html) - or merge it into the rest of your applicationContext.xml.

Related

Spring mvc #RequestMapping on class level and method level 404 Status

I know that there are lot of posts here with the same problem, but none of them seem to help me, so this will probably be a duplicate.
Im creating a spring mvc application using Maven, i have only one controller with one method. When i put the request mapping annotation only on the class level the application works fine but when i put it on the class level and the method level and i send a request like this:
localhost:8080/myapplication/planification/projet
i get 404 error: HTTP Status 404 - /myapplication/planification/WEB-INF/pages/test.jsp
here is my controller
#Controller
#RequestMapping("/planification")
public class PlanificationController {
#RequestMapping("/projet")
public ModelAndView projets (ModelAndView m){
m.addObject("projets", "All projects");
m.setViewName("test");
return m;
}
}
mvc-dispatcher-servlet.xml
<beans>
<context:component-scan base-package="com.smit"/>
<mvc:annotation-driven/>
<!-- **** VIEW RESOLVER BEAN **** -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
web.xml
<web-app>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet- class>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/mvc-dispatcher-servlet.xml
</param-value>
</context-param>
</web-app>
Hold on, you are using / in front of RequestMapping value, which means from the root. You should removed it like this
#RequestMapping("projet")
Then go to localhost:8080/myapplication/planification/projet
Edit:
WEB-INF should have / in front!

spring-ws: no endpoint mapping found

I made a simple web service but when I'am trying to test it on soapui its giving this error:
WARN : [Oct-11 12:56:38,081] ws.server.EndpointNotFound - No endpoint mapping found for [SaajSoapMessage {http://www.servesy.com/api/v1/service}signupRequest]
I do not have any idea what should I do to make it correct, I saw many questions regarding this problem but did not find any solution.
My spring-ws configuration are follows:
(apart from this configuration I also tried to make simple input output example and that
also shows same warning)
web.xml
<web-app
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/servesy-config.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>servesyservices</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>servesyservices</servlet-name>
<url-pattern>*.wsdl</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servesyservices</servlet-name>
<url-pattern>/endpoints/*</url-pattern>
</servlet-mapping>
</web-app>
servesy-config.xml
<beans
<context:component-scan base-package="com.servesy.webservices" />
<sws:annotation-driven />
<bean id="ServesyService" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition" lazy-init="true">
<property name="schemaCollection">
<bean class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
<property name="inline" value="true" />
<property name="xsds">
<list>
<value>schemas/ServesyServices.xsd</value>
</list>
</property>
</bean>
</property>
<property name="portTypeName" value="ServesyService"/>
<property name="serviceName" value="ServesyServices" />
<property name="locationUri" value="/endpoints"/>
</bean>
</beans>
Endpoint
#Endpoint
public class ServesyWebServiceEndpoint {
private static final String TARGET_NAMESPACE ="http://www.servesy.com/api/v1/service";
private ServesyWebService servesyservice_i;
#Autowired
public void setServesyWebService(ServesyWebService servesyservice_p)
{
this.servesyservice_i = servesyservice_p;
}
#PayloadRoot(localPart="SignupRequest", namespace=TARGET_NAMESPACE)
public #ResponsePayload SignupResponse response(SignupRequest signupRequest) {
SignupResponse signupResponse = new SignupResponse();
Signup signup = servesyservice_i.signupResponse( signupRequest.getMobileNumber(), signupRequest.getPassword(), signupRequest.getCustomerName(), signupRequest.getEmailId(), signupRequest.getPromoCode(), signupRequest.getDevice());
signupResponse.setSignup(signup);
return signupResponse;
}
#PayloadRoot(localPart="LoginRequest", namespace=TARGET_NAMESPACE)
public #ResponsePayload LoginResponse response(LoginRequest loginRequest) {
LoginResponse loginResponse = new LoginResponse();
String string = servesyservice_i.signinResponse( loginRequest.getEmailID(), loginRequest.getPassword(), loginRequest.getDevice());
loginResponse.setSessionId(string);
return loginResponse;
}
}
and my soupui gives this type of blank output:
The EndpointNotFoundException occurs when Spring-WS cannot find a suitable #Endpoint that can handle the incoming request.
In this case, the incoming message has namespace http://www.servesy.com/api/v1/service and local name signupRequest (as can be seen in the log). While your #PayloadRoot mapping does have the same namespace; it does not have the same local name, as it uses SignupRequest with a capital S. Chances are that if you change the uppercase S to a lower case s in the #PayloadRoot annotation, it will work.
context level parameters need to be reflected in MessageDispatcherServlet level also.
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class> <br>
<init-param> <br>
<param-name>transformWsdlLocations</param-name> <br>
<param-value>true</param-value> <br>
</init-param> <br>
<init-param> <br>
<param-name>contextConfigLocation</param-name> <br>
<param-value>/WEB-INF/config/servesy-config.xml</param-value> <br>
</init-param> <br>
For what's it worth, I was facing this issue 2021-02-17 14:13:52.810 DEBUG 204429 --- [nio-8080-exec-7] o.s.w.soap.server.SoapMessageDispatcher : Endpoint mapping [org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping#7f98f516] has no mapping for request while following - https://spring.io/guides/gs/producing-web-service/- was that I somehow missed to annotate the the endpoint with #Endpoint public class CountryEndpoint
I have faced a similar issue and the root cause was in the application servlet context path.
The best way how to approach this problem is, in my opinion, to set DEBUG logging level for "org.springframework.ws" and carefully watch logs. You should find a message like this:
o.s.w.s.e.mapping.UriEndpointMapping - Mapped key [/ws/CardInfoWS_v3] onto endpoint [bean 'cardInfoEndpointGateway_v3'; defined in: '...']
And the warn after sending request says:
o.s.w.s.e.mapping.UriEndpointMapping - Looking up endpoint for [/cms-ws/ws/CardInfoWS_v3]
o.s.ws.server.EndpointNotFound - No endpoint mapping found for [SaajSoapMessage {...}GetCardRequest]
So... it is looking for endpoint mapping under the key "/cms-ws/ws/CardInfoWS_v3" but the endpoint is registered under the key "/ws/CardInfoWS_v3".
You can also put the breakpoint to the method lookupEndpoint in your endpoint mapper (AbstractMapBasedEndpointMapping or AbstractMethodEndpointMapping) that looks like this:
protected Object lookupEndpoint(String key) {
return endpointMap.get(key);
}
and after sending the request, in the debug mode you will see all your registered endpoints and the key which is currently searched.

Restful web service based on CXF

everyone!
Something has confused me a lot. I make a Restful Web service based on CXF,but it does not work.
My web.xml is as follows:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
and then is my applicationContext.xml:
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="handleRequest" class="test.cjm.HandleReuqst"/> <jaxrs:server id="customerService" address="/">
<jaxrs:serviceBeans>
<ref bean="handleRequest"/>
</jaxrs:serviceBeans>
and my HandleRequest.java file presents below:
#Produces("application/json")
#Path("/test")
public class HandleRequest {
#GET
#Path("/Spring")
public TestVO testSpring(){
System.out.println("get users:");
TestVO tv = TestDAO.getPerson();
return tv;
}
}
The TestDAO.java file
private static Map<String,TestVO> testVOs;
static{
testVOs = new HashMap<String,TestVO>();
TestVO t1 = new TestVO();
t1.setId(1);
t1.setName("cjm");
testVOs.put("1", t1);
}
public static TestVO getPerson(){
return testVOs.get("1");
}
I deploy the program in tomcat named CXFSpring. I don't know where is wrong, Everytime I make a request to localhost:8080/CXFSpring/test/Spring, It just return a 404 status.
Could you tell me Where is wrong?
you CXF serving servlet is mapped to /service/*
try the following URL: localhost:8080/CXFSpring/service/test/Spring

Properties file not getting loaded

I have Two projects, CarpoolDB and Carpool.
CarpoolDB : contains backend stuff and has
carpool-application-context.xml
<context:annotation-config />
<context:component-scan base-package="com.onmobile" />
<context:property-placeholder location="classpath:server.properties" />
server.properties
cm.db.driverClassName=com.mysql.jdbc.Driver
cm.db.url=jdbc:mysql://localhost:3306/carpool1
cm.db.username=abc
cm.db.password=xyz
I make a jar of carpoolDB and place in Carpool Application
Carpool: contains UI thing and for backend contact carpoolDB jar and has
carpool-application-context1.xml
<import resource="classpath:carpool-application-context.xml"/>
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpool.authentication" />
spring-servlet.xml
<context:property-placeholder location="classpath:carpool.properties" />
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpool.controller, com.onmobile.carpool.util" />
carpool.properties
cm.email.sender.mail.smtp.host=mail.on.com
Now, I have one class com.onmobile.carpool.util.EmailSender, it has one property smtpHost and want the value to get injected by Spring using #Value but it is not getting injected.
#Controller
public class EmailSender {
public static final Log logger = LogFactory.getLog(EmailSender.class);
#Value("${cm.email.sender.mail.smtp.host}")
private String smtpHost;
}
I am getting error as
java.lang.IllegalArgumentException: Could not resolve placeholder 'cm.email.sender.mail.smtp.host'
carpool.properties is present in src folder.
Why it is not picking the cm.email.sender.mail.smtp.host from carpool.properties file. is there any relation with properties file present in jar file.
Actually properties file is loaded as I can't see in logs like file not found but field is not getting autowired.
Posting updated complete configuration files after removing import
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/carpool-application-context1.xml
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/jsp/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>
carpool-application-context1.xml
<!-- Configure annotated beans -->
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpooldb.db" />
<context:property-placeholder location="classpath:carpool.properties" />
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<beans:property name="driverClassName"><beans:value>${cm.db.driverClassName}</beans:value></beans:property>
<beans:property name="url"><beans:value>${cm.db.url}</beans:value></beans:property>
<beans:property name="username"><beans:value>${cm.db.username}</beans:value></beans:property>
<beans:property name="password"><beans:value>${cm.db.password}</beans:value></beans:property>
<beans:property name="testOnBorrow"><beans:value>true</beans:value></beans:property>
<beans:property name="testOnReturn"><beans:value>true</beans:value></beans:property>
<beans:property name="validationQuery"><beans:value>select 1</beans:value></beans:property>
<beans:property name="maxIdle"><beans:value>-1</beans:value></beans:property>
<beans:property name="maxActive"><beans:value>-1</beans:value></beans:property>
<beans:property name="maxOpenPreparedStatements"><beans:value>-1</beans:value></beans:property>
<beans:property name="maxWait"><beans:value>30000</beans:value></beans:property>
</beans:bean>
//session factory bean and other configuration
spring-servlet.xml
<context:property-placeholder location="classpath:carpool.properties" />
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpool.authentication, com.onmobile.carpool.controller, com.onmobile.carpool.util" />
<!-- Declare a view resolver -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="100000"/>
</bean>
carpool.properties
cm.db.driverClassName=com.mysql.jdbc.Driver
cm.db.url=jdbc:mysql://localhost:3306/carpool
cm.db.username=abc
cm.db.password=xyz
user.profile.pic.base.folder=D:\\carpoolRepository\\carpoolProfilePicUpload
google.places.autocomplete.response.xml.base.folder=D:\\carpoolRepository\\googleMapXML
#EMAIL - FORGOT PASSWORD
cm.email.sender.mail.smtp.host=mail.on.com
I am trying to inject value of cm.email.sender.mail.smtp.host in EmailSender "smtpHost" property way mentioned above, when i read it it says null.
other properties like cm.db.driverClassName etc get properly injected in carpool-application-context1.xml.
I am attaching the snap containing location for configuration files
You have <context:component-scan base-package="com.onmobile" /> in the carpool-application-context.xml which is imported from carpool-application-context1.xml so that forces your controller to be created in the root web app context, because "com.onmobile" includes "com.onmobile.carpool.controller", and there is no property-placeholder config for the root context.
You have a property placeholder configurer in the servlet context(spring-servlet.xml). Property placeholder configurers(defined by the context:property-placeholder tag) are bean postprocessors and work on per container basis, so they can't modify the bean definitions of context they are not defined in. So it can't modify the bean definition of controller instance declared in the root context(carpool-application-context.xml, carpool-application-context1.xml). So because of the double scanning your controller is created twice - both in root and servlet context, and only one is processed by the correct placeholder configurer.
As a fix, you can use filter expressions in component-scan to pick up #Controller annotated classes only only in the spring-servlet.xml, and exclude it from carpool-application-context.xml/carpool-application-context1.xml
See #Service are constructed twice for examples of filters
Please keep your Spring configuration simple, your configuration is very puzzling.
update you are confusing controllers (which are annotated with #Controller and I think should be better put into aaa.bbb.controllers package) with services which should be annotated with #Service in the util package. My advice is to move your services to the root web app context(carpool-application-context1.xml) and put the property placeholder configurer declaration there.

I am trying to use spring application context and spring di in my scala vaadin app, but can't get a datasource to be injected

i am new to scala and vaadin, i'm just experimenting. I am trying to use spring application context and spring di in my scala vaadin app, but can't get a datasource to be injected. I dont know, maybe i'm doing something fundamentally wrong but here's my code:
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<description>
Vaadin production mode</description>
<param-name>productionMode</param-name>
<param-value>false</param-value>
</context-param>
<servlet>
<servlet-name>Scalatest Application</servlet-name>
<servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
<init-param>
<description>Vaadin application class to start</description>
<param-name>application</param-name>
<param-value>com.example.scalatest.ScalaApp</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Scalatest Application</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
application context:
<bean id="main" class="com.example.scalatest.ScalaApp">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="url"/>
<property name="username" value="root"/>
<property name="password" value="pass"/>
</bean>
and in my scala class
var dataSource:DataSource = _;
def setDataSource(datasource:DataSource){
dataSource = datasource;
}
Isn't working, ds is null at launch.
Can anyone guide me please?
The main problem you have is your application (ScalaApp) is not instantiated by Spring container but by VaadinServlet - make sure it does. There are several strategies. Here is the example project that can help you: https://github.com/archiecobbs/dellroad-stuff-vaadin-spring-demo3
Few more pieces of advice...
Instead of writing a setter yourself, add #BeanProperty annotation to your variable. Scala compiler will generate setter and getter for your variable:
#BeanProperty private var dataSource:DataSource = _
There is even better way - using Spring's annotation based container configuration. If you have only one bean of type DataSource in your context, simply add #Autowired to your variable (no need for xml definition in the context file - your class should be annotated as a #Component ):
#Component
class ScalaApp {
#Autowired private var dataSource:DataSource = _
}
Here is more information: http://static.springsource.org/spring/docs/3.0.x/reference/beans.html#beans-annotation-config

Resources