Announcement Announcement Module
Collapse
No announcement yet.
Multiple Handler Mapping Chains Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Multiple Handler Mapping Chains

    We currently use Spring MVC integrated with OpenCMS. This involves integrating Spring into the standard OpenCMS WAR and web.xml so that all the correct resources are available. We've done one website so far and were able to use the Spring DispatchServlet for controller dispatch, store the MVC view JSPs in OpenCMS, and pass non-matching file requests on to OpenCMS.

    Our new problem is in wanting to use Spring for other websites hosted in OpenCMS. OpenCMS uses the same context (root) for all websites but displays the correct content based on the host (or session information when in Offline mode). Ideally, we'd like to maintain a different application-context.xml for each website as the handler mappings are complex and varied. I've seen how to load multiple XML files but I'm unable to figure out how the dispatch would work. We can probably avoid bean name collisions without too much difficulty but there will definitely be content name collisions.

    For example, the following URLs:
    http://www.siteA.com/home.html
    http://www.siteB.com/home.html

    Each of these has a different controller and configuration set but are served from the same OpenCMS WAR and context. Further, I'd like both to work in Offline mode. I'm pretty sure that I'll need to extend one or more Spring classes to make them OpenCMS aware. I'd like to keep the individual Spring XML files for each website as normal as possible.

    Suggestions?

  • #2
    In the answering my own question department

    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.

    Comment

    Working...
    X