Spring DispatcherServlet context instantiation error in liferay 6.1.1 - spring

I'm in the process of migrating the liferay version of my webapp from 6.1.0 to 6.1.1 (using the 6.1.1-ga2 version from liferay patchers community and have a little problem with my webservices that where previously working.
I use the PortalDelegateServlet to instantiate a spring DispatcherServlet.
The problem I have is that the spring context of my servlet (myWS-servlet.xml) is instantiate before the application context of the PortletContextLoaderListener ( also tried with the ContextLoaderListener from spring, same problem )
and, as my controllers use services from the principal application context (which is not loaded at the time the DispatcherServlet is instantiated), spring cannot autowired them.
Strange thing is that the problem is resolved if I redeploy my portlet.
Do you have any idea how I can fix this ?
my 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="WebApp_ID" version="2.5">
<display-name>banner-portlet</display-name>
<jsp-config>
<taglib>
<taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>
<taglib-location>/WEB-INF/tlds/liferay-portlet.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://liferay.com/tld/theme</taglib-uri>
<taglib-location>/WEB-INF/tlds/liferay-theme.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://liferay.com/tld/portlet</taglib-uri>
<taglib-location>/WEB-INF/tlds/liferay-portlet-ext.tld</taglib-location>
</taglib>
</jsp-config>
<servlet>
<servlet-name>liferayWSdispatcher</servlet-name>
<servlet-class>com.liferay.portal.kernel.servlet.PortalDelegateServlet</servlet-class>
<init-param>
<param-name>servlet-class</param-name>
<param-value>org.springframework.web.servlet.DispatcherServlet</param-value>
</init-param>
<init-param>
<param-name>sub-context</param-name>
<param-value>rest-api</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>liferayWSdispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>com.liferay.portal.spring.context.PortletContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
<!-- Instruct Mojarra to utilize JBoss-EL instead of the EL implementation
provided by the servlet container. -->
<!-- was used only for admin portlets but make calendar portlet crash
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
</context-param>
-->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<listener>
<listener-class>com.liferay.faces.portal.listener.StartupListener</listener-class>
</listener>
<!-- MyFaces will not initialize unless a servlet-mapping to the Faces Servlet
is present. -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<context-param>
<param-name>portalContextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext-velocity-tool.xml</param-value>
</context-param>
my applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="be.maximede">
<context:exclude-filter type="regex" expression="be.maximede.webservice.*"/>
</context:component-scan>
my myWS-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="be.maximede.webservice"/>
<mvc:annotation-driven />

I know this thread is over a year old. But I wanted to help save people some trouble. My coworkers and I spent a week trying to figure this out why we can't load spring services before portlet controllers using spring and PortalDelegateServlet + DispatcherServlet.
It's somewhat but not directly related to the Issue http://issues.liferay.com/browse/LPS-29103 as the other poster commented. It does have to do with the way Servlets were initialized in liferay and how Liferay handles web.xml rewrite.
Liferay rewrites all your listeners defined within web.xml and puts them into a context param likes this:
<context-param>
<param-name>portalListenerClasses</param-name>
<param-value>com.liferay.portal.kernel.servlet.SerializableSessionAttributeListener,org.springframework.web.context.ContextLoaderListener</param-value>
</context-param>
and then creates its own listener (or not shown, a PluginContextListener):
<listener>
<listener-class>com.liferay.portal.kernel.servlet.SecurePluginContextListener</listener-class>
</listener>
This SecurePluginContextListener then loads up the context and wires things up. The problem is that sometimes, SecurePluginContextListener will initialize PortalDelegateServlet with the Web Application Context first and then it moves on to the init methods within the portalListenerClasses. So any AutoWired stuff within the portlet controller is missing all their dependencies (services from the application context).
In order to get around this, we ditched declaring PortalDelegateServlet within the web.xml and created a custom ServletContextListener that would new up a PortalDelagateServlet and ServletConfig, passing in the same parameters to spring's DispatcherServlet. The reason why this works is because, we let Liferay do all the loading within portalListenerClasses. The rewritten web.xml would look like this:
<context-param>
<param-name>portalListenerClasses</param-name>
<param-value>com.liferay.portal.kernel.servlet.SerializableSessionAttributeListener,org.springframework.web.context.ContextLoaderListener, com.domain.CustomContextListener</param-value>
</context-param>
And CustomContextListener would implement the methods in ServletContextListener.
Within CustomContextListener's contextInitialized(...) method, we just programmatically create the same ServletConfig (An inner class that implements ServletConfig) we had inside the web.xml. We then create a pds = new PortalDelegateServlet() and call pds.init(customServletConfig)

For Liferay 6.1.1 this is a known issue:
http://issues.liferay.com/browse/LPS-29103

Related

Accessing Spring Rest Service without Dispatcher Servlet

Here actually i am trying to access my spring based rest full service, I am not configuring DispatcherServlet in web.xml, instead of that i am using ContxtLoaderListener to load my spring configuration file.
From my logs i can see my service is getting initialized, when ever i access the above url, ICallServlet is receiving the request since it has the url-pattern as '/*'(this i can't modify).
Here my problem is i could not able to access my service, request is not reaching my service. without using DispatcherServlet is there any way to invoke my rest service, Some one please help me to resolve this issue.
I have a Rest Controller :
package mypackage;
#RestController
#RequestMapping("/api/casaOnboarding")
public class CasaOnboardingRestService {
#ResponseBody
#RequestMapping(value="/pwebXML", method=RequestMethod.POST, consumes={"application/json", "application/xml"})
public ResponseEntity pwebXML(#RequestBody OnboardingReq onboardingReq,
HttpServletRequest request, HttpServletResponse response){
System.out.println("Request Reached");
----
}
}
Web.xml (No Dispatcher Servlet)
<?xml version="1.0" encoding="UTF-8"?>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:controllerServiceContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>iCallUI</servlet-name>
<servlet-class>com.ui.ICallServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>iCallUI</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
controllerServiceContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<context:annotation-config />
<context:component-scan base-package="mypackage"/>
<task:annotation-driven />
</beans>
Log File
10:45:41,643 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ServerService Thread Pool -- 62) Creating shared instance of singleton bean 'casaOnboardingRestService'
10:45:41,643 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ServerService Thread Pool -- 62) Creating instance of bean 'casaOnboardingRestService'
10:45:41,643 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ServerService Thread Pool -- 62) Eagerly caching bean 'casaOnboardingRestService' to allow for resolving potential circular references
10:45:41,643 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ServerService Thread Pool -- 62) Finished creating instance of bean 'casaOnboardingRestService'
URL:
http://localhost:8080/icall-ui/api/casaOnboarding/pwebXML
I'm sorry, but you can't dispatch spring mvc views without a Dispatcher Servlet. Your context will be loaded via the ContextLoaderListener, but just as you've discovered, your routes will never be called.
You could do something like mapping the dispatcher servlet to your api endpoints and then map iCallUI to catch the default route "/" as opposed to "/*":
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>iCallUI</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
ICallServlet will replace the default servlet and this may or may not have bad effects depending on how your application is set up. Static file serving may break, for example.
Subclassing org.springframework.web.servlet.DispatcherServlet is an option. But not knowing what you do in com.ui.ICallServlet, who knows how difficult it will be to extend DispatcherServlet.
Also, it seems like the long way around. If you are using Spring to declare your api routes, why not use it to declare them all? Why have two dispatching mechanisms? If you need to do some preprocessing per request then use a Servlet Filter.
Lastly, and perhaps the simplest solution. Just point iCallUI to another url pattern like: "/ui/*".
That pretty much exhausts the possibilities :). Well that and the fact that your controllerServiceContext file isn't set up to parse the url mapping. You also need to add
<mvc:annotation-driven />
Don't forget all the xml namespace info for that!
xmlns:mvc="http://www.springframework.org/schema/mvc"
.
.
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
.
Finally i got to know that there is no way (as per my knowledge) of invoking spring rest services without using DispatcherServlet.
Thank you so much #Robert for your valuable suggestions. As per #Robert Comments, I modified my code like below to get it to work.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:controllerServiceContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>iCallUI</servlet-name>
<servlet-class>com.ui.ICallServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>iCallUI</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<context:component-scan base-package="mypackage"/>
<mvc:annotation-driven />
</beans>
ControllerServiceContext.xml
I removed below lines of code and left as it is with old code (this file contains some other stuff related to the project).
<context:component-scan base-package="mypackage"/>
<task:annotation-driven />
Log file
After seeing the below statement in logs, I can say my service is ready to serve requests.
15:12:01,782 INFO [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] (ServerService Thread Pool -- 58) Mapped "{[/api/casaOnboarding/pwebXML],methods=[POST],params=[],headers=[],consumes=[application/json || application/xml],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity mypackage.CasaOnboardingRestService.pwebXML(mypackage.OnboardingReq,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
URL -
I used below url to access the service
http://localhost:8080/icall-ui/api/api/casaOnboarding/pwebXML
By using filter in web.xml
<!-- Spring security -->
<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>

My servlet stopped receive post params after adding CXF web service to the project

Good day, I created simple DynamicWebProject containing servlet Capture extending HttpServlet which overrides method doPost. When I sent a post request to this servlet it successfuly retrieved all posted parameters until I added simple Apache CXF Web Service. The CXF web service works but since I added it my servlet Capture isn't able to receive any posted parameters. When I post data to URL http://x.x.x.x:8080/capture the Capture.doPost method is called but no parameters are passed to it. When I comment out the listener tag it starts work again. Please could you advise why is this happening and how can I fix it? Many thanks in advance. Vojtech
This is my 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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>MyApp</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/cxf.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>/services/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Capture</servlet-name>
<servlet-class>myapp.servlet.Capture</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Capture</servlet-name>
<url-pattern>/capture</url-pattern>
</servlet-mapping>
</web-app>
And the cxf.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:endpoint id="decodeWS" implementor="myapp.ws.decoder.DecoderServiceImpl" address="/decode">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
</jaxws:endpoint>
</beans>
EDIT: I resolved this issue by changing order of servlet mappings. If CaptureParts is on the first place then it works. But I still don't understand why the order matters.
<servlet-mapping>
<servlet-name>CaptureParts</servlet-name>
<url-pattern>/captureParts</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
You have
<param-value>WEB-INF/cfx.xml</param-value>
Should it be cxf.xml instead?

How applicationcontext.xml is interpreted in struts and spring

i have one question on applicationcontext.xml...
when web.xml is interpreted by server(tomcat or whatever)..does it first see applicationcontext.xml or struts.xml
(Or) does it first see whether the struts.xml is there and then interpret applicationcontext.xml and then come back to struts.xml and include applicationcontext.xml environment into struts.xml and then interpret the struts.xml
i would like to know how the flow goes.
i am using struts2 and spring 3 framework...
Thank you all..
Consider the following web.xml
<?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">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<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>
<welcome-file-list>
<welcome-file>/index.action</welcome-file>
</welcome-file-list>
</web-app>
Filters are initialised in order of occurrence. So most definitely struts.xml is read before applicationContext.xml however if reversed the opposite would be true. It is part of the servlet spec and explicitly stated here: http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContextListener.html
If however you used a servlet to access a resource, it would be initialised after the filters and the order can be controlled by the servlets load-on-startup element.

#Autowired does not work Spring 3

I looked all around to find a solution and couldn't find.
I am using Tomcat, Spring 3 with the jars:
org.springframework.aop-3.0.5.RELEASE.jar
org.springframework.asm-3.0.5.RELEASE.jar
org.springframework.beans-3.0.5.RELEASE.jar
org.springframework.context-3.0.5.RELEASE.jar
org.springframework.core-3.0.5.RELEASE.jar
org.springframework.expression-3.0.5.RELEASE.jar
org.springframework.jdbc-3.0.5.RELEASE.jar
org.springframework.orm-3.0.5.RELEASE.jar
org.springframework.test-3.0.5.RELEASE.jar
org.springframework.transaction-3.0.5.RELEASE.jar
org.springframework.web-3.0.5.RELEASE.jar
and my code is like this:
public class EmailResource {
#Autowired
EmailManager emailManager;
}
in applicationContext I have:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="emailManager" class="com.mycompany.manager.impl.EmailManagerImpl" />
<context:component-scan base-package="com.mycompany.component" />
and the web.xml:
<?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">
<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>
</web-app>
However, the emailManager is always null! What am I missing?
EDITED
The EmailResource is jersey servlet for rest calls and is defined like this:
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.mycompany.resource</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
You need to use a Jersey/Spring connecter to get Jersey to recognize your Spring context on startup.
Replace:
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.mycompany.resource</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
With:
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
....
</init-param>
</servlet>
You'll also need the jersey-spring dependency:
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-spring</artifactId>
<version>${jersey.version}</version>
</dependency>
The problem is that the Jersey servlet is specified in web.xml as a servlet and thus is not under control of Spring. Spring can't wire the dependencies.
I don't know much about Jersey, but I found this article that is maybe useful to you.
Further, you've to consider EmailManager is an instance variable of a Servlet, and you declared it as Spring Singleton (the default):
<bean id="emailManager" class="com.mycompany.manager.impl.EmailManagerImpl" />
Thus emailManager should not have any state or it will be non-thread safe.
To explain the problem: suppose that emailManager contains a state, such as a destination address, a subject and a message body. Since is defined as a Singleton, there is only one instance for the whole application. If the servlet is called at the same time by two different people, it could happen that the first process inserts the subject and that same subject is rewritten by the second process before the first was able to send the email. So the data of the two emails will be mixed.
Alternatively it can be defined with scope request, so each request will have a different instance.

Splitting applicationContext to multiple files

What is the correct way to split Spring's configuration to multiple xml files?
At the moment I have
/WEB-INF/foo-servlet.xml
/WEB-INF/foo-service.xml
/WEB-INF/foo-persistence.xml
My web.xml has the following:
<servlet>
<description>Spring MVC Dispatcher Servlet</description>
<servlet-name>intrafest</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/foo-*.xml
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/foo-*.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
The actual questions:
Is this approach correct/best?
Do I really need to specify the config locations both in the DispatcherServlet AND the context-param sections?
What do I need to keep in mind to be able to reference beans defined in foo-servlet.xml from foo-service.xml? Does this have something to do with specifying contextConfigLocation in web.xml?
Update 1:
I'm using Spring framework 3.0. It's my understanding that I don't need to do resource importing like this:
<import resource="foo-services.xml"/>
Is this a correct assumption?
I find the following setup the easiest.
Use the default config file loading mechanism of DispatcherServlet:
The framework will, on initialization
of a DispatcherServlet, look for a
file named [servlet-name]-servlet.xml
in the WEB-INF directory of your web
application and create the beans
defined there (overriding the
definitions of any beans defined with
the same name in the global scope).
In your case, simply create a file intrafest-servlet.xml in the WEB-INF dir and don't need to specify anything specific information in web.xml.
In intrafest-servlet.xml file you can use import to compose your XML configuration.
<beans>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
<import resource="foo-services.xml"/>
<import resource="foo-persistence.xml"/>
</beans>
Note that the Spring team actually prefers to load multiple config files when creating the (Web)ApplicationContext. If you still want to do it this way, I think you don't need to specify both context parameters (context-param) and servlet initialization parameters (init-param). One of the two will do. You can also use commas to specify multiple config locations.
Mike Nereson has this to say on his blog at:
http://blog.codehangover.com/load-multiple-contexts-into-spring/
There are a couple of ways to do this.
1. web.xml contextConfigLocation
Your first option is to load them all into your Web application
context via the ContextConfigLocation element. You’re already going
to have your primary applicationContext here, assuming you’re writing
a web application. All you need to do is put some white space between
the declaration of the next context.
<context-param>
<param-name> contextConfigLocation </param-name>
<param-value>
applicationContext1.xml
applicationContext2.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
The above uses carriage returns. Alternatively, yo could just put in a
space.
<context-param>
<param-name> contextConfigLocation </param-name>
<param-value> applicationContext1.xml applicationContext2.xml </param-value>
</context-param>
<listener>
<listener-class> org.springframework.web.context.ContextLoaderListener </listener-class>
</listener>
2. applicationContext.xml import resource
Your other option is to just add your primary applicationContext.xml
to the web.xml and then use import statements in that primary context.
In applicationContext.xml you might have…
<!-- hibernate configuration and mappings -->
<import resource="applicationContext-hibernate.xml"/>
<!-- ldap -->
<import resource="applicationContext-ldap.xml"/>
<!-- aspects -->
<import resource="applicationContext-aspects.xml"/>
Which strategy should you use?
1. I always prefer to load up via web.xml.
Because , this allows me to keep all contexts isolated from each
other. With tests, we can load just the contexts that we need to run
those tests. This makes development more modular too as components
stay loosely coupled, so that in the future I can extract a package
or vertical layer and move it to its own module.
2. If you are loading contexts into a non-web application, I would use the import resource.
There are two types of contexts we are dealing with:
1: root context (parent context. Typically include all jdbc(ORM, Hibernate) initialisation and other spring security related configuration)
2: individual servlet context (child context.Typically Dispatcher Servlet Context and initialise all beans related to spring-mvc (controllers , URL Mapping etc)).
Here is an example of web.xml which includes multiple application context file
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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">
<display-name>Spring Web Application example</display-name>
<!-- Configurations for the root application context (parent context) -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/jdbc/spring-jdbc.xml <!-- JDBC related context -->
/WEB-INF/spring/security/spring-security-context.xml <!-- Spring Security related context -->
</param-value>
</context-param>
<!-- Configurations for the DispatcherServlet application context (child context) -->
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/mvc/spring-mvc-servlet.xml
</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/admin/*</url-pattern>
</servlet-mapping>
</web-app>
#eljenso : intrafest-servlet.xml webapplication context xml will be used if the application uses SPRING WEB MVC.
Otherwise the #kosoant configuration is fine.
Simple example if you dont use SPRING WEB MVC, but want to utitlize SPRING IOC :
In web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value>
</context-param>
Then, your application-context.xml will contain: <import resource="foo-services.xml"/>
these import statements to load various application context files and put into main application-context.xml.
Thanks and hope this helps.
I'm the author of modular-spring-contexts.
This is a small utility library to allow a more modular organization of spring contexts than is achieved by using Composing XML-based configuration metadata. modular-spring-contexts works by defining modules, which are basically stand alone application contexts and allowing modules to import beans from other modules, which are exported ín their originating module.
The key points then are
control over dependencies between modules
control over which beans are exported and where they are used
reduced possibility of naming collisions of beans
A simple example would look like this:
File moduleDefinitions.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:module="http://www.gitlab.com/SpaceTrucker/modular-spring-contexts"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.gitlab.com/SpaceTrucker/modular-spring-contexts xsd/modular-spring-contexts.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<module:module id="serverModule">
<module:config location="/serverModule.xml" />
</module:module>
<module:module id="clientModule">
<module:config location="/clientModule.xml" />
<module:requires module="serverModule" />
</module:module>
</beans>
File serverModule.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:module="http://www.gitlab.com/SpaceTrucker/modular-spring-contexts"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.gitlab.com/SpaceTrucker/modular-spring-contexts xsd/modular-spring-contexts.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<bean id="serverSingleton" class="java.math.BigDecimal" scope="singleton">
<constructor-arg index="0" value="123.45" />
<meta key="exported" value="true"/>
</bean>
</beans>
File clientModule.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:module="http://www.gitlab.com/SpaceTrucker/modular-spring-contexts"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.gitlab.com/SpaceTrucker/modular-spring-contexts xsd/modular-spring-contexts.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<module:import id="importedSingleton" sourceModule="serverModule" sourceBean="serverSingleton" />
</beans>

Resources