Server-side includes for org.restlet.resource.Directory?

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Server-side includes for org.restlet.resource.Directory?

kevinpauli
Hi, I've got resources compressed in a .war that I want restlet to serve up.  So I attached a directory to the router:

Directory new Directory(getContext(), "war:///");

But this is not processing server side includes in my *.shtml files.  How would I accomplish this?
Reply | Threaded
Open this post in threaded view
|

RE: Server-side includes for org.restlet.resource.Directory?

Thierry Boileau
Hello Kevin,

unfortunately the SSI feature is not supported at this time (I've added an RFE for this http://restlet.tigris.org/issues/show_bug.cgi?id=1074). At this time, you can used template representations based on Freemarker or Velocity frameworks, with the suitable extensions.

Best regards,
Thierry Boileau

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2508620
Reply | Threaded
Open this post in threaded view
|

RE: Server-side includes for org.restlet.resource.Directory?

kevinpauli
Thanks Thierry.

Can you point me to a primer on Restlet-Freemarker integration, hello-world style?  I have done some googling with no luck.  I saw the javadocs for the restlet freemarker extension, but those aren't really helping me see how it should be configured, high-level.

Thanks again...
Reply | Threaded
Open this post in threaded view
|

RE: Server-side includes for org.restlet.resource.Directory?

kevinpauli
I tried this:

    router.attach(new TemplateFilter(getContext(), new Directory(getContext(), "war:///")));

and switched my includes to look like this:

<#include "/masthead.html">

But it doesn't seem to be doing anything...
Reply | Threaded
Open this post in threaded view
|

RE: Server-side includes for org.restlet.resource.Directory?

kevinpauli
I found the example of FreemarkerResource that was included with the Restlet 1.1 distribution.  Is it true that I will have to create a Resource for each and every *.ftl file in my war?  I don't like that, I was hoping I could just wrap the whole contents of the war in a filter that would process the includes (as I was attempting to do in my previous post).  However, I am game to try this way.  I guess it has the advantage of making all the resources that are will require template processing explicit.

So, since 2.0 does not seem to include any examples that I can find, I'm trying to re-implement this example from Restlet 1.1 it in terms of Restlet 2.0rc2.

However I am getting an UnsupportedOperationException.  The problem seems to be that in lines 113-114 of org.restlet.ext.freemarker.ContextTemplateLoader it creates a new Request without setting any protocol:

        return getContext().getClientDispatcher().handle(
                new Request(Method.GET, fullUri)).getEntity();

Then when this request is attempted to be handled by org.restlet.engine.TemplateDispatcher in lines 105-108, it finds the null protocol and then throws an exception:

        if (protocol == null) {
            throw new UnsupportedOperationException(
                    "Unable to determine the protocol to use for this call.");
        }

Any ideas?
Reply | Threaded
Open this post in threaded view
|

Re: Server-side includes for org.restlet.resource.Directory?

Thierry Boileau
Hello Kevin,

I send you a sample app based on Freemarker template representations, illustrating the inclusion of templates and the usage of the ContextTemplateLoader.
I hope this will help you.

Best regards,
Thierry Boileau


I found the example of FreemarkerResource that was included with the Restlet
1.1 distribution.  Is it true that I will have to create a Resource for each
and every *.ftl file in my war?  I don't like that, I was hoping I could
just wrap the whole contents of the war in a filter that would process the
includes (as I was attempting to do in my previous post).  However, I am
game to try this way.  I guess it has the advantage of making all the
resources that are will require template processing explicit.

So, since 2.0 does not seem to include any examples that I can find, I'm
trying to re-implement this example from Restlet 1.1 it in terms of Restlet
2.0rc2.

However I am getting an UnsupportedOperationException.  The problem seems to
be that in lines 113-114 of org.restlet.ext.freemarker.ContextTemplateLoader
it creates a new Request without setting any protocol:

        return getContext().getClientDispatcher().handle(
                new Request(Method.GET, fullUri)).getEntity();

Then when this request is attempted to be handled by
org.restlet.engine.TemplateDispatcher in lines 105-108, it finds the null
protocol and then throws an exception:

        if (protocol == null) {
            throw new UnsupportedOperationException(
                    "Unable to determine the protocol to use for this
call.");
        }

Any ideas?
  

testFreemarker.zip (11K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Server-side includes for org.restlet.resource.Directory?

kevinpauli
Thanks!  I think I'm just missing one thing now, how to declare the CLAP protocol when using an Application configured with the Servlet extension.

I am getting this:

WARNING [ClientRouter] The protocol used by this request is not declared in the list of client connectors.
WARNING [ClientRouter] Unable to get the template hello.ftl. Error message: Template hello.ftl not found.

In the example you sent you are using a Component constructed in main(), so you are able to do this:

        c.getClients().add(Protocol.CLAP);

But I am in a war hosted by tomcat, so I have only my Application subclass to work with.  I couldn't see a way to get at the containing component so I could add the CLAP protocol.

Or is there a way to add the CLAP protocol declaratively in the web.xml?

Thanks again.  I think I am really going to enjoy using Restlet.

Reply | Threaded
Open this post in threaded view
|

RE: Re: Server-side includes for org.restlet.resource.Directory?

Thierry Boileau
Hello Kevin,

good question.

>Or is there a way to add the CLAP protocol declaratively in the web.xml?
yes!

I've updated the FAQ of the user guide:
http://wiki.restlet.org/docs_2.0/13-restlet/338-restlet.html

Best regards,
Thierry Boileau

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2534225
Reply | Threaded
Open this post in threaded view
|

RE: Re: Server-side includes for org.restlet.resource.Directory?

kevinpauli
Okay!  Finally got it working.  

Found out that I have to put all the *.ftl files under WEB-INF/classes since it uses CLAP protocol, and the classloader only seems to be able find them there.  Then, I had to put all the images, css, etc. in the root of the war, so that the org.restlet.resource.Directory can serve them with the "war:///" protocol.

I don't necessarily like that I have them split up like that, since I'm used to seeing the templates, html, images and css all together, but I can live with it.  If you know of a way I can keep everything together, I'd appreciate it.

Thanks again!
Reply | Threaded
Open this post in threaded view
|

RE: Re: Server-side includes for org.restlet.resource.Directory?

webpost
Hello Kevin,

you can keep all together with the WAR client:
 - move the templates directory to /WebContent
 - replace the declaration of the client connector in the component: component.getClients().add(Protocol.WAR);
 - change the way uou instantiate the freemarker configuration file: fmc.setTemplateLoader(new ContextTemplateLoader(getContext(),
                "war:///tmpl"));

Best regards,
Thierry Boileau

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2566503
Reply | Threaded
Open this post in threaded view
|

Serving static files from jar: Spring config expert needed!

kevinpauli
Thanks for the idea on the WAR client, but it turns out I am going to have to use CLAP, for reasons I won't go into here (okay, if you're interested, it's because we're configuring everything with Spring using the Spring Deployer in JBoss 5.1, and so everything needs to be in jars).

While I am able to access all my ServerResources, (including ones built with Freemarker, yay!) I am just not able to get it to serve static files out of the jar.  I would really appreciate some help with this, I am sure it is something simple.  Things are probably complicated by the fact that I am using the Spring extension for configuration, but I really have no choice.  The architect is breathing down my neck and I have tweaked things and restarted JBoss about 100 times trying to get it to serve up an image file contained in my jar and I have had no luck.

Here's the jar structure:

myApp.jar
+--my
+----package
+------MyServlet.class (extends org.restlet.ext.servlet.ServerServlet, overriding createComponent() method to retrieve bean id="rootRestletComponent" from the Spring Context stored in JNDI)
+------HelloWorldResource.class  (returns hard-coded greeting)
+------DashboardResource.class (builds html representation with freemarker)
+------dashboard.ftl (freemarker template for DashboardResource.  references "header.ftl")
+------header.ftl (freemarker template included by dashboard.ftl.  references "images/banner.gif")
+------images
+--------banner.gif

What I want is for http://localhost/myapp/images/banner.gif to serve up the gif.  However, in playing with the Routers it looks like I may want to stick a "static" in there to make routing more efficient, so I'm not opposed to making it http://localhost/myapp/static/images/banner.gif.  However I would prefer the former.  But as of now neither way is working for me.

Okay, here's the spring config:

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

  <bean id="virtualHost" class="org.restlet.ext.spring.SpringHost">
    <constructor-arg ref="rootRestletComponent" />
    <property name="attachments">
      <map>
        <entry key="/myapp">
          <ref bean="restletApplication" />
        </entry>
      </map>
    </property>
  </bean>

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

 
  <bean id="localClapReference" class="org.restlet.data.LocalReference" factory-method="createClapReference">
    <constructor-arg>
      <util:constant static-field="org.restlet.data.LocalReference.CLAP_CLASS" />
    </constructor-arg>
    <constructor-arg value="/my/package" />
  </bean>

 
  <bean id="freemarkerConfig" class="freemarker.template.Configuration">
    <property name="localizedLookup" value="false" />
    <property name="templateLoader">
      <bean class="org.restlet.ext.freemarker.ContextTemplateLoader">
        <constructor-arg ref="rootRestletComponentChildContext" />
        <constructor-arg ref="localClapReference" />
      </bean>
    </property>
  </bean>

 

  <bean id="helloWorldResource" class="my.package.HelloWorldResource" scope="prototype" />

  <bean id="dashboardResource" class="my.package.DashboardResource" scope="prototype">
    <property name="freemarkerConfig" ref="freemarkerConfig" />
  </bean>

  <bean id="ritwsUserResource" class="mil.nga.ritws.service.uam.RitwsUserResource" scope="prototype">
    <property name="ritwsUserDao" ref="ritwsUserDao" />
  </bean>

  <bean id="restletApplication" class="org.restlet.Application">
    <constructor-arg ref="rootRestletComponentChildContext" />
    <property name="name" value="Ritws Restlet Application" />
    <property name="inboundRoot">
      <bean id="rootApplicationRouter" class="org.restlet.ext.spring.SpringRouter">
        <constructor-arg ref="restletApplication" />

       
        <property name="routingMode">
          <util:constant static-field="org.restlet.routing.Router.MODE_BEST_MATCH" />
        </property>

        <property name="attachments">
          <map>

           

            <entry key="/hello">
              <bean class="org.restlet.ext.spring.SpringFinder">
                <lookup-method name="create" bean="helloWorldResource" />
              </bean>
            </entry>

            <entry key="/dashboard">
              <bean class="org.restlet.ext.spring.SpringFinder">
                <lookup-method name="create" bean="dashboardResource" />
              </bean>
            </entry>

           
            <entry key="/static">
              <bean id="directory" class="org.restlet.resource.Directory">
                <constructor-arg ref="rootRestletComponentChildContext" />
                <constructor-arg ref="localClapReference" />
              </bean>
            </entry>

          </map>
        </property>
      </bean>
    </property>
  </bean>


When I debug a call to GET http://localhost/myapp/static/images/banner.gif, it matches the "/static/" template and gets all the way to the Directory.  But then it looks like there's a problem at org.restlet.engine.local.DirectoryServerResource.doInit() line: 230, which is finding null for the context's clientDispatcher().  That is causing it to skip the code that would set directoryContent or fileContent.

Later, at org.restlet.engine.local.DirectoryServerResource.get() line: 421 the getVariants() is returning null (due to directoryContent and fileContent both being null), and then, because variants was null, it hits org.restlet.engine.local.DirectoryServerResource.get() line: 424 which sets the response code to 404.

I suspect it has something to do with how my Spring config is causing contexts and childContexts to be instantiated and initialized.  My assumption was that including the CLAP client up at the servlet level would cause that info to get propagated all the way down to the Directory's context, which would then have an appropriate clientDispatcher instantiated with the CLAP protocol configured.  But it doesn't... and I really am having a hard time since this is all declarative and I'm having trouble following it.  

Should I be somehow explicitly setting a clientDispatcher with the CLAP protocol on context being used by the Directory?  How would I even do that using the Spring extensions?

So... any Spring config experts out there?

for grins, here's the web.xml.  Note that I DO include CLAP

  <servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>my.package.MyServlet</servlet-class>
    <init-param>
      <param-name>org.restlet.clients</param-name>
      <param-value>HTTP HTTPS CLAP</param-value>
    </init-param>
  </servlet>
 
 
  <servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

Thanks to anyone with ideas...

Reply | Threaded
Open this post in threaded view
|

Re: Serving static files from jar: Spring config expert needed!

kevinpauli
BTW when showing my Spring config I forgot to include the clap in the client list in my root component.  It's presence is not helping the problem, but I wanted to give an accurate view of my spring config as it stands, in case anyone was willing to help me:

  <bean id="rootRestletComponent" class="org.restlet.ext.spring.SpringComponent">
    <property name="clientsList">
      <list>
        <value>clap</value>
      </list>
    </property>
    <property name="defaultTarget" ref="virtualHost" />
  </bean>

  <bean id="virtualHost" class="org.restlet.ext.spring.SpringHost">
    <constructor-arg ref="rootRestletComponent" />
    <property name="attachments">
      <map>
        <entry key="/myapp">
          <ref bean="restletApplication" />
        </entry>
      </map>
    </property>
  </bean>

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

 
  <bean id="localClapReference" class="org.restlet.data.LocalReference" factory-method="createClapReference">
    <constructor-arg>
      <util:constant static-field="org.restlet.data.LocalReference.CLAP_CLASS" />
    </constructor-arg>
    <constructor-arg value="/my/package" />
  </bean>

 
  <bean id="freemarkerConfig" class="freemarker.template.Configuration">
    <property name="localizedLookup" value="false" />
    <property name="templateLoader">
      <bean class="org.restlet.ext.freemarker.ContextTemplateLoader">
        <constructor-arg ref="rootRestletComponentChildContext" />
        <constructor-arg ref="localClapReference" />
      </bean>
    </property>
  </bean>

 

  <bean id="helloWorldResource" class="my.package.HelloWorldResource" scope="prototype" />

  <bean id="dashboardResource" class="my.package.DashboardResource" scope="prototype">
    <property name="freemarkerConfig" ref="freemarkerConfig" />
  </bean>

  <bean id="restletApplication" class="org.restlet.Application">
    <constructor-arg ref="rootRestletComponentChildContext" />
    <property name="inboundRoot">
      <bean id="rootApplicationRouter" class="org.restlet.ext.spring.SpringRouter">
        <constructor-arg ref="restletApplication" />

       
        <property name="routingMode">
          <util:constant static-field="org.restlet.routing.Router.MODE_BEST_MATCH" />
        </property>

        <property name="attachments">
          <map>

           

            <entry key="/hello">
              <bean class="org.restlet.ext.spring.SpringFinder">
                <lookup-method name="create" bean="helloWorldResource" />
              </bean>
            </entry>

            <entry key="/dashboard">
              <bean class="org.restlet.ext.spring.SpringFinder">
                <lookup-method name="create" bean="dashboardResource" />
              </bean>
            </entry>

           
            <entry key="/static">
              <bean id="directory" class="org.restlet.resource.Directory">
                <constructor-arg ref="rootRestletComponentChildContext" />
                <constructor-arg ref="localClapReference" />
              </bean>
            </entry>

          </map>
        </property>
      </bean>
    </property>
  </bean> 

Also, I guess when using the spring config it is normal to get log messages such as these?

2010-04-14 13:15:41,743 FINE  [org.restlet.engine.component.ComponentClientDispatcher] The connector has been instantiated without any protocol. [org.restlet.Connector.<init>(Connector.java:94)]
2010-04-14 13:15:41,759 FINE  [org.restlet.engine.component.ComponentServerDispatcher] The connector has been instantiated without any protocol. [org.restlet.Connector.<init>(Connector.java:94)]
2010-04-14 13:15:41,821 FINE  [org.restlet.engine.component.ChildClientDispatcher] The connector has been instantiated without any protocol. [org.restlet.Connector.<init>(Connector.java:94)]
2010-04-14 13:15:41,821 FINE  [org.restlet.engine.component.ChildClientDispatcher] The connector has been instantiated without any protocol. [org.restlet.Connector.<init>(Connector.java:94)]
Reply | Threaded
Open this post in threaded view
|

Re: Serving static files from jar: Spring config expert needed!

kevinpauli
The problem seems to be that Spring instantiates the Directory before it invokes the setClientList() on the root component.  So the context with which the Directory is constructed still has a null clientDispatcher.

I worked around the problem by modifying my custom servlet to reset the context on the directory to a new child one, after Spring gets done wiring everything together.

Hope this helps anyone else running into similar issues.  Luckily in my case there was easy place to do some imperative programming.