Found a workable solution. Please let me know if there is an better/easier way that I missed.
The integration OpenCMS has all "/opencms/" calls going to Spring in web.xml of the WAR directory but the OpenCmsListener is retained:
Code:
<listener>
<listener-class>org.opencms.main.OpenCmsListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
...
<servlet>
<description>
The main servlet that handles all requests to the OpenCms VFS.
</description>
<servlet-name>OpenCmsServlet</servlet-name>
<servlet-class>org.opencms.main.OpenCmsServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/opencms/*</url-pattern>
</servlet-mapping>
Context files are split into a parent that imports the others (wildcard import in the classpath did not seem to work but was not necessary). In the main context file put a fall back to OpenCMS with an order value unlikely to be less than anything else. This forwards the non-spring requests correctly:
Code:
<bean id="openCmsHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="order" value="99"/>
<property name="mappings">
<value>
/**/*=opencms
</value>
</property>
<property name="defaultHandler"><value>opencms</value></property>
</bean>
<bean id="opencms" class="org.springframework.web.servlet.mvc.ServletForwardingController">
<property name="servletName"><value>OpenCmsServlet</value></property>
</bean>
<import resource="classpath:/siteA-context.xml"/>
<import resource="classpath:/siteB-context.xml"/>
The various site context files can be configured normally except they need modifications to any HandlerMapping classes. The site in Offline mode is determined by the session information and in Online mode is derived from the host using CMS calls:
Code:
public class CmsSiteRootFilteredSimpleUrlHandlerMapping extends SimpleUrlHandlerMapping {
protected String cmsSiteRoot ;
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
if (cmsSiteRoot != null) {
String siteRoot = null ;
CmsSessionInfo session = OpenCms.getSessionManager().getSessionInfo(request);
if (session != null) {
siteRoot = session.getSiteRoot();
} else {
CmsSite site = OpenCms.getSiteManager().matchRequest(request);
if (site != null) {
siteRoot = site.getSiteRoot();
}
}
if (siteRoot != null
&& !siteRoot.equals(cmsSiteRoot)) {
return null ;
}
}
return super.getHandlerInternal(request);
}
public String getCmsSiteRoot() {
return cmsSiteRoot;
}
public void setCmsSiteRoot(String cmsSiteRoot) {
this.cmsSiteRoot = cmsSiteRoot;
}
}
And the corresponding context entry looks almost the same:
Code:
<bean id="simpleUrlHandlerMapping" class="com.mysites.CmsSiteRootFilteredSimpleUrlHandlerMapping">
<property name="order" value="2"/>
<property name="cmsSiteRoot" value="/sites/siteA"/>
<property name="mappings">
<value>
/**/home.html=home
/**/viewCart.html=viewCart
/**/product.html=product
</value>
</property>
</bean>
Now multiple Spring websites can play nice together in a single OpenCMS. This is very important in our load balanced and replicated production environment.