mercredi 4 mars 2015

Restlet: can't locate static files through Directory

Serving static files through Restlet is proving harder than it feels like it ought to be. I suspect some deep issue to do with context initialization, but I could be wrong. Basically, I have yet to be able to get any actual content served through a Directory although all the routing and all classic restlets are working just fine.


The core problem looks like it shows in log messages:



WARNING: No client dispatcher is available on the context. Can't get the target URI: war:///


I've tried a bunch of different base URLs, and none of them seem to make a difference. And when I debug, sure enough getClientDispatcher() is returning null.


When I modified the Spring initialization (wrongly) to use the original context rather than a child context, I didn't get this warning, and directory listings showed, but it also displayed about seven SEVERE messages about that being a security risk.


My Spring XML looks like this:



<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://ift.tt/GArMu6"
xmlns:xsi="http://ift.tt/ra1lAU"
xmlns:util="http://ift.tt/OGfeTW"
xsi:schemaLocation="http://ift.tt/GArMu6
http://ift.tt/1jdM0fG
http://ift.tt/OGfeTW
http://ift.tt/1feTls0">

<bean id="trackerComponent" class="org.restlet.ext.spring.SpringComponent">
<property name="defaultTarget" ref="trackerApplication" />
</bean>

<bean id="trackerComponentChildContext" class="org.restlet.Context">
<lookup-method name="createChildContext" bean="trackerComponent.context" />
</bean>

<bean id="trackerApplication" class="ca.uhnresearch.pughlab.tracker.application.TrackerApplication">
<property name="root" ref="router" />
</bean>

<!-- Define the router -->
<bean name="router" class="org.restlet.ext.spring.SpringRouter">
<constructor-arg ref="trackerComponentChildContext" />
<property name="attachments">
<map>
<entry key="/" value-ref="staticsDirectory" />
</map>
</property>
</bean>

<bean id="staticsDirectory" class="ca.uhnresearch.pughlab.tracker.resource.SpringDirectory">
<constructor-arg ref="router" />
<constructor-arg value="war:///" />
<property name="listingAllowed" value="true" />
</bean>

...


My class SpringDirectory is just a wrapper to provide a Context from a parent Router, like the other Spring helpers, and it seems to work just fine: the same context is passed along -- and none of the child contexts have a getClientDispatcher() that works.


In case it's needed, here's some of the relevant sections of web.xml. I'm not entirely sure why I needed to add the FILE to allow client access (I want to serve through the web container after all) but I did try with a file: URL too, and that didn't make any difference that I could see, except that I had to add extra settings in unusual places.



<servlet>
<servlet-name>tracker</servlet-name>
<servlet-class>org.restlet.ext.spring.SpringServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.clients</param-name>
<param-value>HTTP HTTPS FILE</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

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


I'd be really grateful for advice on this -- I've actually spent more time trying to get an index.html displayed than I have on all the Restlets combined, so any thoughts or pointers will be very welcome.


UPDATE


Thierry's response has been helpful, but I still have some issues and still can't serve static files. The only variation from this is that I don't have a test.CustomSpringServerServlet -- and it's not entirely clear I need one, as the additional init-param seems to be accepted by the default.


When running with a Jetty JAR file (mvn jetty:run-war) I now get a stack backtrace:



WARNING: Exception or error caught in status service
java.lang.NoSuchMethodError: org.restlet.Context.getClientDispatcher()Lorg/restlet/Restlet;
at ca.uhnresearch.pughlab.tracker.restlets.DirectoryFactoryBean$1.getContext(DirectoryFactoryBean.java:16)
at org.restlet.Restlet.handle(Restlet.java:220)
at org.restlet.resource.Finder.handle(Finder.java:449)
at org.restlet.resource.Directory.handle(Directory.java:245)
at org.restlet.routing.Filter.doHandle(Filter.java:156)
...


This stack backtrace could easily be a consequence of my updates -- I'm now using Restlets 2.3.1 and Spring 3.1.4, as it's very similar to the previous warning.


Strangely enough, I don't get this from mvn jetty:run, which paradoxically is now serving directory listings at the top level, but still refuses to serve any files. So that confirms the WAR protocol is able to access something. The war:// protocol isn't highly documented so I'm kind of guessing it's just going to serve from the war contents, and it certainly isn't yet able to do that.


I'd still like the file:// protocol to work -- to be honest, any serving of any static files would be fantastic, I am getting beyond caring. However, trying that still results in errors:



WARNING: The protocol used by this request is not declared in the list of client connectors. (FILE). In case you are using an instance of the Component class, check its "clients" property.


Which I don't really understand, as it is in the clients list in the web.xml and there's nowhere else that makes sense I can put it.


This is proving hard enough that I feel maybe I should throw together a Github repo for people to play with.


Aucun commentaire:

Enregistrer un commentaire