I'm developing a 'user settings portlet' where users can effect the search behaviour of multiple other portlets. The way I'd like to do it is by a shared bean. All portlets are in different wars, and I'd rather avoid having all wars in a single ear and using a parent application context, so deployment of portlets can be made autonomously, but haven't had much luck in finding any information on how to do it.
I have followed this blog post to try to deploy an ear file with the wars in them, but after many hours of wrestling I've come no closer to solving my problem...
The directory structure looks like this:
portlets |--- ear | \--- src/main/application/META-INF/application.xml | |--- jar (contains UserSettings.java) | \--- src/main/resources/beanRefContext.xml | \--- src/main/resources/services-context.xml | \--- src/main/java/com/foo/application/UserSettings.java | |--- messagehistory (war, portlet 1) | \--- [...] | |--- settings (war, portlet 2) | \--- [...] | \--- pom.xml
I've tried setting scope="session"
like the following:
<bean id="userSettings" class="com.foo.application.UserSettings" scope="session">
<aop:scoped-proxy />
</bean>
But then when I deploy the ear I get java.lang.IllegalStateException: No Scope registered for scope 'session'
.
This is the controller för the history portlet, where users can search for message history, with restrictions from the settings portlet. The controller for the settings portlet is identical.
package com.foo;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletSession;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.portlet.bind.annotation.ActionMapping;
import com.foo.application.UserSettings;
import javax.annotation.PostConstruct;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ServletContextAware;
@Controller
@SessionAttributes({"searchQuery", "searchResults"})
@RequestMapping("VIEW")
public class ViewHistory extends ContextLoader implements ServletContextAware {
private UserSettings userSettings;
private ServletContext servletContext;
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
@PostConstruct
public void init() {
ApplicationContext ctx = loadParentContext(servletContext);
servletContext.setAttribute(LOCATOR_FACTORY_KEY_PARAM, "ear.context");
userSettings = (UserSettings) ctx.getBean("userSettings");
}
@ModelAttribute("userSettings")
public UserSettings createUserSettings(Model model) {
model.addAttribute(userSettings);
}
@RequestMapping
public String doSearch(Model model, PortletSession portletSession) {
return "view";
}
@ActionMapping(params = "action=search")
public void searchAction(
Model model,
ActionRequest request, ActionResponse response,
BindingResult bindingResult, SessionStatus status)
{
// do nothing
}
}
The web.xml
file for both wars (they are identical) looks like this:
<?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>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>parentContextKey</param-name>
<param-value>ear.context</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<filter>
<filter-name>springFilter</filter-name>
<filter-class>
org.springframework.web.filter.RequestContextFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>springFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>