WSServletContainerInitializer and SpringBeanAutowiringSupport - spring

I have some integration issues regarding the mentioned classes but only with "too new" tomcat versions.
The base setup:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="FooService" version="2.5" metadata-complete="true">
<display-name>FooService</display-name>
<servlet>
<servlet-name>jax-ws</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<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>
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
</web-app>
FooServiceImpl:
#WebService(serviceName = ServiceInfo.SERVICENAME, targetNamespace = ServiceInfo.TARGETNAMESPACE, endpointInterface = "bar.FooService")
#HandlerChain(file = "/handler-chain.xml")
public class FooServiceImpl extends SpringBeanAutowiringSupport implements FooService {
#Autowired
private Bar bar;
<< some methods using the injected bar singleton >>
JAX-WS dependency: compile 'com.sun.xml.ws:jaxws-rt:2.2.7'
Spring version: 3.1.2.RELEASE
With Tomcat 7.0.22 I don't have the problem. The declared webapp version in the web.xml is 2.5. Tomcat 7.0.22 doesn't process the WSServletContainerInitializer. So as declared in web.xml, ContextLoaderListener is initialized first, so an instance of Bar will be available in the WebApplicationContext. Then WSServletContextListener instantiates FooServiceImpl, aoutowiring works and everybody is happy.
But... My colleague tried it with Tomcat 7.0.30 and the autowiring didn't work (7.0.32 gives the same problem, currently this is the newest). It really couldn't work, because the new Tomcat version has processed WSServletContainerInitializer, not taking into account the 2.5 webapp version (and metadata-complete="true").
I've found a possible solution. I commented out the body of the web.xml, changed webapp version to 3.0 and created a WebapplicationInitializer:
public class MyInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
ContextLoader loader = new ContextLoader();
loader.initWebApplicationContext(servletContext);
}
}
This worked perfectly for me. But not for my colleague... If he tried to run the app, WSServletContainerInitializer fired first which created exactly the same wiring problem as above.
Obviously we can "hack" the problem getting rid of SpringBeanAutowiringSupport and inject Bar manually from a getter or a web method, or any similar way. But SpringBeanAutowiringSupport would be much clearer, so we would like to use it if there's a good solution for the above problems.
UPDATE: this causes the problems: https://issues.apache.org/bugzilla/show_bug.cgi?id=53619

for me the solution was to invoke the following when the autowired reference is null
processInjectionBasedOnCurrentContext(this);
I hope it helps for all.

Related

Creating a route with Spring in Netbeans

I know this is a pretty basic issue, but I struggle hard with it...
I'd like to create a bunch of routes with the Spring framework in the Netbeans IDE, I have created a test #Controller class:
#Controller
public class HelloController {
#RequestMapping("/test")
public ModelAndView thisIsATest(HttpServletRequest request) {
return (new ModelAndView("myTestPage.jsp"));
}
}
myTestPage.jsp is a JSP file in the WEB-INF/jsp/ folder, and the HelloController class is in the Source Packages/ folder within a controller java package.
When I start the server, I can acces the root '/index.htm' that displays the index.jsp page (from the redirect.jsp file), but when I try to access '/test' or '/test.htm' I get a 404 error...
I really don't know how to make a Spring controller to work, and I did many tutorials without success.
In your applications web.xml make sure you have something like this. This will allow access to all your jsp pages. Add any other filters you may need here too.
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>myapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet-mapping>
<servlet-name>myapp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
</web-app>

How to set cookie name in a Spring Boot application running in a standalone Tomcat?

I tried different ways to set a customized cookie name. But none is working in my configuration.
I have a Spring Boot application which is running in a standalone Tomcat.
I tried to set the cookie name in the SpringBootApplication class which is derived from SpringBootServletInitializer:
#Value("${session.cookie.name}")
private String sessionCookieName;
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.getSessionCookieConfig().setName(sessionCookieName);
super.onStartup(servletContext);
}
Also I tried to define a bean as DefaultCookieSerializer:
#Value("${session.cookie.name}")
private String sessionCookieName;
#Bean
public DefaultCookieSerializer defaultCookieSerializer(){
DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
defaultCookieSerializer.setCookieName(sessionCookieName);
return defaultCookieSerializer;
}
But nothing is working so far, I always get the default JSESSONID instead of my configured session.cookie.name
Are there any other ways to customize the cookie name?
I tried the TomcatContextCustomizer as suggested. But I think it does not work, when you deploy your application as a WAR-File because it is just for the embedded tomcat.
I resolved the issue by adding a web.xml. In the folder src/main/webapp/WEB-INF. I'm not really satisfied with this solution, because I don't want a web.xml in my spring boot application. But it works...
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
metadata-complete="true">
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<name>CUSTOM_SESSION_ID</name>
<http-only>true</http-only>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
</web-app>
If there are any better solutions let me know
In the spring boot application. You can rename the JESSIONID by setting your custom name in application.properties file as below:
server.servlet.session.cookie.name=Your_custome_name
It works fine for me.

Convert Spring MVC project to JAX-RS

I'm trying to do a project with JAX-RS, Spring, Hibernate, Maven and JPA. I'm following this article as reference. This project is in Spring MVC. I'm very new to Spring MVC. I have tried to convert it to JAX-RS. What are the important changes I have to do with this?
The main change I noticed that in Spring MVC we use like this: #RequestMapping("/accounts/{username}").
But in JAX-RS we use like this. #Path("/accounts/{username}")
Therefore If I do the changes like this, what are the other key changes we have to do with this?
The most basic thing you need to do in order to port the Spring MVC controllers to JAX-RS controllers, is to provide and integration between Spring and your JAX-RS provider. One way to do that is to make the appropriate changes to web.xml.
Assuming you are using Jersey 2.x and Spring 3.x, the web.xml would look like:
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<module-name>helloworld-spring</module-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>SpringApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>some.package.MyApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringApplication</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Then MyApplication would look like:
package some.package;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spring.scope.RequestContextFilter;
public class MyApplication extends ResourceConfig {
public MyApplication () {
register(RequestContextFilter.class);
register(JerseyResource.class);
register(SpringSingletonResource.class);
register(SpringRequestResource.class);
register(CustomExceptionMapper.class);
}
}
You will also need the dependency
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.10.1</version>
</dependency>
besides the other Spring 3 and Jersey 2 dependencies.
Once you get that out of the way, you can start transforming the controllers.
For example:
#Path("admin")
#Component
public class AdminController {
#Autowired
private SchoolService service;
#Path("load-home-page")
#GET
public String loadHomePage(Map model){
return "admin/index";
}
//the rest of the code accordingly
}
The documentation for Spring-Jersey integration is here while a complete example can be found here.
Personally I would go the Spring MVC route instead of Jersey if you really don't have a compelling reason to choose Jersey over Spring MVC.

Can Spring "live" alongside other servlets in the same webapp?

I've got the a WEB-INF/web.xml file with a couple of servlets, along with a context
listener which I use to bootstrap the application. I'd like to use Spring in this
web application. What's the best way to work Spring into this so I can use Spring's
injection mechanisms throughout the entire application - even in the servlets which
exists today?
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Company's XMLRPC service</display-name>
<!-- Servlet Listeners -->
<listener>
<listener-class>com.company.download.context.DefaultServletContextListener</listener-class>
</listener>
<!-- Servlet Declarations -->
<servlet>
<servlet-name>DefaultTrackDownloadServlet</servlet-name>
<servlet-class>com.company.download.web.impl.DefaultTrackDownloadServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>DefaultXmlRpcServlet</servlet-name>
<servlet-class>com.company.download.web.impl.DefaultXmlRpcServlet</servlet-class>
</servlet>
<!-- Servlet Configurations -->
<servlet-mapping>
<servlet-name>DefaultTrackDownloadServlet</servlet-name>
<url-pattern>/track</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>DefaultXmlRpcServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
Can Spring “live” alongside other servlets in the same webapp?
Yes, Spring MVC is basically just a DispatcherServlet that can make use of a ContextLoaderListener.
These two classes are already setup to interact with one or more ApplicationContext instances and have Spring manage the declared beans.
Your custom Servlet classes are not. If you need to inject a bean into your own Servlet instances, you need to get a reference to the ApplicationContext from the ContextLoaderListener and get the beans you want. There are a few options, whether you do it yourself or use built-in features.
The ContextLoaderListener stores the ApplicationContext it loads into a ServletContext attribute named
org.springframework.web.context.WebApplicationContext.ROOT
So you can retrieve it with that (there's a constant for easy use)
ApplicationContext ac = (ApplicationContext) config.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
Other options exist, see some of them here:
Autowiring in servlet
I want to inject an object in servlet using Spring

Spring 3, Flex 4 Integration with SpringFlex 1.5.0.M2 api + configuration

We are working on a project where we are using Spring 3 to create a web platform and using Flex 4 to create a specific client side application. Currently, we need to integrate Spring project with Flex.
We are using Spring-Flex integration library version: 1.5.0.M2
I checked the older questions but the integration configurations defined at those entries are generally for previous versions of BlazeDS and Spring. And as I understad, there may be some differencies.
Can anybody tell me how to do the configuration in web.xml and any other xml files needed,and how the folder structures will be. Any up-to-date tutorial links will be appreciated.
Our business requirements are:
Two servlets should exist: 1) projectServlet that has mappings /.html
2) flexServlet that has mappings /messageBroker/
Our service classes that can be used in Flex side will be like:
package com.ecognitio.service;
import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.flex.remoting.RemotingInclude;
import org.springframework.stereotype.Service;
#Service
#RemotingDestination
public class Foo {
#RemotingInclude
public void sayHello(String name){
System.out.println("Hello: "+name);
}
}
Regards,
Ugur
My Flex 4, Hibernate 3, and Spring 3 Integration Refcard walks through the process of setting everything up and should work fine with 1.5.0.M2 (assuming you have changed the namespace in the Spring config file). But here is a basic web.xml example:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns
/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>Project Template</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</liste
ner-class>
</listener>
<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>
<servlet>
<servlet-name>flex</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<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>flex</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>
</web-app>
That should be enough to get you started.

Resources