Spring and DWR revisited

by Dejan Bosanac

In his blog, Bram Smeets has described mechanisms for configuring the DWR Ajax library with Spring (http://bram.jteam.nl/?p=2 - please read it before proceeding with this post).
That document contains the complete guide that you will need to get started with Ajax in your Spring-enabled Java projects and it is a de-facto tutorial for that topic.
However, there is one issue that bother me with the solution described in that blog. In order to describe this issue, let me first explain how this DWR-Spring integration works.
First of all, you have to put the following configuration snippet in your web.xml file.
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
This configuration maps all URLs that are under /dwr/ path to your Spring's DispatcherServlet named 'main'.
Now we need to map DWR calls to the appropriate DWR controller bean in the instance of our Spring's SimpleUrlHandlerMapping class.
In this example it is done by adding the following property
<prop key="/**/*">dwrController</prop>
to the end of the class's 'mappings'.
In this configuration all requests that are not matched against any other previous pattern are sent to the DWR controller. The appropriate DWR calls are handled correctly and everything looks just fine.
The problem emerges for requests that are not DWR calls, but are matched against this pattern and sent to the DWR controller. As you can guess those are requests for which we expect 404 (page not found) status to be returned. Unfortunately, these requests are passed to the DWR controller that will throw java.lang.SecurityException and thus return a response with 505 (Error) status.
This can be a problem for your web application, especially if you want to receive an email for every exception that is thrown. In this case the DWR controller will generate a bulk of emails for every 404 response (usually generated by various spiders if you run a public web site).
One simple solution is to replace the previous mapping configuration with the following one
<prop key="/**/*.js">dwrController</prop>
<prop key="exec/*">dwrController</prop>
Let me explain how this configuration is different and what benefits does it bring.
When you encounter this problem, your first try would probably be to map all URLs that matches /dwr/**/* pattern to the DWR Controller. Unfortunately, this won't work, because Spring (in a default configuration) sees these URLs without the /dwr prefix. So, for example /dwr/engine.js will basically be treated as engine.js and obviously we have to find another solution.
The DWR controller needs an access to certain JavaScript libraries, such as engine.js, which is usually located at /dwr/engine.js. Also, for every interface that will be exposed through this library there is an appropriate JavaScript library dynamically created (e.g. /dwr/interface/productManager.js in the original example). So the first line in our example is here to allow an access to these dynamic JavaScript libraries.
Secondly, every call to a method defined in the interface is mapped to a certain URL. For example, a call to the getAllProducts() method of the productManager object defined in the Bram's example will be converted to the /dwr/exec/productManager.getAllProducts URL request. All these URLs starts with /dwr/exec/ so we must match them against exec/ pattern. So with the second configuration line, we map this kind of URLs to our DWR controller.
With this solution we have allowed normal functioning of our DWR controller and assured that it will handle only requests that are regular Ajax calls. Also, it will improve the performance of your application a little bit, since there will be no 'false' Ajax calls for every 404 response.

Update: Bram have suggested a more cleaner solution to this issue (look at the comments for more details about this discussion). The trick is to define a new url mapper that will handle just DWR URLs. The final solution could look like this:
<bean id="dwrUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true"/>
<property name="mappings">
<props>
<prop key="/dwr/**/*">dwrController</prop>
</props>
</property>
</bean>


Have you experienced similar issues? How did you solve them?


5 Comments

BramSmeets
2005-12-06 09:19:05
Alternative approach
You have a good point here.
It has been a while back when I wrote my blog entry and it is due to a major update, covering this and some other issues.


Your solution to avoid all non-mapped calls being handled by DWR is a good one. However, it is a little cumbersome especially if you also want to handle the debug pages.


There is an alternative approach. The Spring SimpleUrlHandlerMapping has a alwaysUseFullPath property. So you could define a second SimpleUrlHandlerMapping that only handles DWR calls. So something like the following:



<bean id="dwrUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true"/>
<prop key="/dwr/**/*">dwrController</prop>
</bean>


That way, only calls in the /dwr context will be handled by DWR.

dejanb
2005-12-07 01:12:30
Alternative approach
Bram, you are absolutely right, the solution with alwaysUseFullPath is much cleaner and people that starting a fresh project should certainly follow that path.
However, in my case I was dealing with live project with a lot of mappings (and no full paths enabled) so I didn't want to experiment with that funcionallity. My next Spring-DWR project will definitelly start with full paths :)
BramSmeets
2005-12-07 10:48:32
Alternative approach
Even on an existing project, it poses no problem to add an extra mapping definition, which has the alwaysUseFullPath property set to true. It will not affect existing mappings.


Just make sure that the extra mapping only handles requests in the /dwr/ context (so /dwr/**/* should handle them all).

dejanb
2005-12-08 03:55:25
Alternative approach
It seem that I have been just too lazy to come up with the second URL mapper :) This is great. I have updated the post with this configuration, so that others could find it without reading the comments. Thanks.
Harald
2006-04-06 05:21:49
hallo ehco