Hi all,

First off a warning that this is a long email :)

In doing the virtual service work (GSIP 44) i have yet again have run up 
against a problem we have had in GeoServer ever since we moved to 
spring. The problem being that we have to register all servlet mappings 
in web.xml.

To describe the problem in more detail the following is how a request is 
  routed/dispatched in GeoServer today. In web.xml we register a single 
servlet (DispatcherServlet) which is the spring dispatcher servlet. This 
servlet essentially handles all requests that come into geoserver. But 
it can only do so if the proper servlet mappings are registered web.xml. 
For example:

     <servlet-mapping>
         <servlet-name>dispatcher</servlet-name>
         <url-pattern>/web/*</url-pattern>
     </servlet-mapping>
     <servlet-mapping>
       <servlet-name>dispatcher</servlet-name>
       <url-pattern>/rest/*</url-pattern>
     </servlet-mapping>
     <servlet-mapping>
       <servlet-name>dispatcher</servlet-name>
       <url-pattern>/wms/*</url-pattern>
     </servlet-mapping>
     <servlet-mapping>
       <servlet-name>dispatcher</servlet-name>
       <url-pattern>/wfs/*</url-pattern>
     </servlet-mapping>

With these mappings a request that comes in of the form "/geoserver/wfs" 
for example, will get routed to our one servlet to rule them all, the 
spring dispatcher.

When handling a request the spring dispatcher takes the request and does 
its down routing. It does this by looking up mappings in the spring 
applicationContext.xml. For example the wfs mappings:

<bean id="wfsURLMapping" ...>
   <property name="alwaysUseFullPath" value="true"/>
        <property name="mappings">
                <props>
                        <prop key="/wfs">dispatcher</prop>
                        <prop key="/wfs/*">dispatcher</prop>
                </props>
        </property>
</bean>

Which basically says map all urls of the form "/wfs*" to the ows dispatcher.

Now there are a couple of problems with this approach:

1) It is redundant in that we have to maintain two sets of mappings.

2) New services are not truly pluggable because any time one adds a new 
path prefix web.xml has to be updated.

3) Mapping in web.xml is quite limited compared to the corresponding 
spring mappings

(3) is where my problem lies with regard to the virtual services stuff. 
To sum up with virtual services the path of a wfs request changes to:

/geoserver/<workspace>/wfs?

Which of course does not have a mapping in web.xml therefore the request 
does not even make it to the spring dispatcher.

So the obvious solution (one that we have tried) would be to create a 
single mapping in web.xml that matches all requests to the spring 
dispatcher. The syntax is quite simple:

     <servlet-mapping>
         <servlet-name>dispatcher</servlet-name>
         <url-pattern>/*</url-pattern>
     </servlet-mapping>

But it does not work. The reason being that when this mapping is applied 
  some attributes of the resulting HttpServletRequest change. Namely the 
"servletPath" property.

With the existing mappings when a request comes in the servlet path gets 
set to the part of the path that matched. For example "web", "rest", 
"wfs", etc... But with the "catch all" mapping the servlet path becomes 
an empty string. I should also point out that this is the behavior in 
Jetty and Tomcat, i have yet to try out other containers.

And this causes problem. Many of the libraries/servets we use depend on 
the servlet path being set. Wicket and restlet pretty much fail 
outright. So.... the evil plan to fix. I tried a variety fo things but 
the following is only one i have had any success with.

Basically the idea is simple. Wrap the HttpServletRequest object in one 
that fakes the servlet path. Since all the existing mappings are simple 
in that they match a single patch component the wrapper class simply 
expects the entire request uri and uses the first component of the path 
(that occurs after /geoserver) and uses that for the servlet path.

So for wicket and restlet things go on working the same as the servlet 
paths become "web" and "rest" the way they were before. And same goes 
for the ows services.

Things get interesting when we get to the virtual services use case. 
Since the path is (for example):

/geoserver/<workspace>/wfs

The servlet path becomes "<workspace>". To amend this the "second level 
mappings" in the application context have to change a bit:

<bean id="wfsURLMapping" ...>
   <property name="alwaysUseFullPath" value="true"/>
        <property name="mappings">
                <props>
                        <prop key="/wfs">dispatcher</prop>
                        <prop key="/wfs/*">dispatcher</prop>
                        <prop key="/*/wfs">dispatcher</prop>
                        <prop key="/*/wfs/*">dispatcher</prop>
                </props>
        </property>
</bean>

And with that it all works. So what do we do. I will be the first to 
admit that this approach is a bit hackish. And I plan to do a great deal 
of more testing in various environments to ensure it is actually even 
viable. But if it is what do people think about it?

If the idea does get some uptake I was thinking we could gradually 
introduce it as we have some of the other recent functionality 
improvements such as advanced rendering functionality, etc... Basically 
add a parameter (settable as system prop, web.xml context variable, 
etc..) called "ADVANCED_DISPATCH" or something that would enable the 
above. We could enable it on trunk and give it time to mature but 
disable it by default on 2.0.x, making it available only by explicitly 
setting the parameter.

Thoughts?

-Justin

-- 
Justin Deoliveira
OpenGeo - http://opengeo.org
Enterprise support for open source geospatial.

------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev 
_______________________________________________
Geoserver-devel mailing list
Geoserver-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/geoserver-devel

Reply via email to