Hey all. I was recently added to this ticket:
http://jira.codehaus.org/browse/GEOS-3436 regarding restlet route
handling. I've attached a small patch to it that addresses the basic
issue, but it brings to mind some larger concerns I have about
GeoServer's Restlet route handling. Basically, routes for restlets in
GeoServer are dynamically added based on instances of a custom
RESTMapping class in the Spring context (example from my scriptlet
extension since it's short):
<bean id="javascriptRestletMapping"
class="org.geoserver.rest.RESTMapping">
<property name="routes">
<map>
<entry>
<key><value>/script</value></key>
<value>javascriptRestlet</value>
</entry>
<entry>
<key><value>/script/{script}</value></key>
<value>javascriptRestlet</value>
</entry>
</map>
</property>
</bean>
This obscures some of the extra facilities provided by Restlet; there
are some settings regarding match "scoring" etc that are made globally
in the code that consumes this extension point. The ticket addresses
one such decision; that all templates should use the default "starts
with" matching mode. Since the index Restlet is routed to the empty
string, every request matches it, if nothing else. My patch switches
this to "entire string" matching, which I think is probably appropriate
for this situation (this matching mode makes it less likely that
extensions will "steal" paths from each other.)
However, Restlet also provides "types" for the variables in templates,
which we have thus far ignored, meaning all variables in templates are
using the default type, URI_SEGMENT. However, there are further
restrictions that might be useful (digit sequences for example) and
relaxations that definitely would be handy, especially in light of
requiring full matches. We would require this to, for example, provide
a service that exposes XML documents as arbitrary-depth hierarchies.
This requires calling mutator function on the Route object created when
Router.attach is called. The function takes a map<string, variable>
from name to variable specification, so we'd need to either set up an
encoding for these in spring, or expose an extension point allowing
routings to customize the Routes they generate.
Going the all-spring route, I guess we could come up with some way of
annotating variables in routes with type info (like
"/path/{var?uri-segment}" or something. But this would be less
extensible and more of a pain to maintain, so I'm not going to explore
it in depth.
I guess more explicit XML would look like:
<bean id="javascriptRestletMapping"
class="org.geoserver.rest.RESTMapping">
<property name="routes">
<list>
<bean class="org.geoserver.rest.Route">
<property name="path" value="/script"/>
<property name="restlet" ref="javascriptRestlet"/>
</bean>
<bean class="org.geoserver.rest.Route">
<property name="path" value="/script/{script}"/>
<property name="restlet" ref="javascriptRestlet"/>
<property name="variables"><map><entry>
<key><value>script</value></key>
<bean class="org.restlet.util.Variable">
<constructor-arg>9</constructor-arg>
</bean>
</entry></map></property>
</bean>
</list>
</property>
</bean>
We might want to wrap Variable so we can do a bit of magic letting us
use the name of the type instead of its numeric value, but you get the
idea. This also exposes other features of Variable like default values.
Alternatively, we could add a hook to the RESTMapping class allowing
extensions to customize the routes after they are added (by subclassing
RESTMapping). It seems like the app-context approach is just as nice or
better, imho. We can also extend geoserver.Route in the future to
expose other restlet.Route features in the future if need be. Plus, we
can pretty easily provide backwards compatibility for existing plugins
by just doing a type-check on RESTMapping.routes (if it's a Map, we do
what we're already doing, if it's a List, we use the newer Route
objects).
Thoughts, opinions, criticisms?
--
David Winslow
OpenGeo - http://opengeo.org/