Hi all,

I'm a Spring Framework user (beneficiary!) and of course have been forced to find ways in which Restlet can integrate easily with Spring. I thought I would just give out the solution we're using for Spring integration. I haven't seen anyone post a solution quite like this yet, and I believe this is a bit easier (possibly more correct) way of doing Spring integration than is currently in the spring extension package of the restlet distribution.

I guess I'm only referring to integration between Restlet's Resource class and Spring, not anything else.

The problem, of course, is that Resource is stateful and cannot be reused per connection (maybe something which can be fixed in a future release) making it impossible to easily integrate with Spring (which is essentially singleton based).

The Finder class is essentially a factory that is meant to produce these stateful Resource instances. This was recently brought up on the mailing list (Re: Proposal for ResourceFactory, Sean Landis). The trick is to think of the Finder class as a Resource factory and then delegate to a spring bean from there.

Finder thankfully happens to be a stateless bean, and therefore can be easily added into your Spring configuration. So the trick is two-fold:

a) Create an interface which has methods similar to Resource, except make the interface stateless by passing in the Request and Response objects. I named this interface ResourceService.

b) Create a Finder which creates a delegating Resource class which delegates to the above ResourceService interface. I call this finder ResourceServiceFinder.

I'm attaching the source code to these two classes. In order to use them, you will need to setup your spring configuration to look like this:

<!--
  This is a ResourceService implementation.
  Ie.  SomeResourceService implements ResourceService
-->
<bean id="someResourceService" class="path.to.SomeResourceService">
    <property name="someDAO" ref="someDAO" />
    <property name="someOtherProperty" value="foo" />
</bean>

<!-- This defines a new Finder for the Service above -->
<bean id="someResourceServiceFinder" class="path.to.ResourceServiceFinder">
    <property name="resourceService" ref="someResourceService" />
</bean>

That's it! Make sure that the "someResourceServiceFinder" Finder is attached to your Restlet router somewhere. This too can be done via Spring (ask me if you need direction on this).

The advantage here, as compared with the spring extension in the restlet package, is that we're not using dynamic proxies to make it work. Ie. In org.restlet.ext.spring.SpringFinder, the Javadoc says to use <lookup-method> which Spring implement using CGLib to create a runtime proxy to make this work properly. The problem is that this may cause other problems if you are using proxies for other pieces in Spring (like Aspects or transactions) as these runtime proxies can conflict, or if you don't want to introduce the CGLib dependency.

Notice that the createResource method creates a new anonymous inner Resource class and then delegates the appropriate methods to the interface.

I hope this helps someone. Jerome, please feel free to post this to the wiki if you want.

Adam

/*
 * Author: Adam Taft - [EMAIL PROTECTED]
 * License: Public Domain 2007
 */

package com.adamtaft.restlet.restlets;

import java.util.List;

import org.restlet.Finder;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.Variant;
import com.adamtaft.restlet.services.ResourceService;

public class ResourceServiceFinder extends Finder {

        private ResourceService resourceService;
        public void setResourceService(ResourceService resourceService) {
                this.resourceService = resourceService;
        }

        @Override
        public Resource createResource(Request request, Response response) {
                return new Resource(getContext(), request, response) {

                        @Override
                        public List<Variant> getVariants() {
                                return resourceService.getVariants();
                        }

                        @Override
                        public boolean allowGet() {
                                return resourceService.allowGet(getRequest());
                        }

                        @Override
                        public boolean allowPost() {
                                return resourceService.allowPost(getRequest());
                        }

                        @Override
                        public boolean allowPut() {
                                return resourceService.allowPut(getRequest());
                        }

                        @Override
                        public boolean allowDelete() {
                                return 
resourceService.allowDelete(getRequest());
                        }

                        @Override
                        public Representation getRepresentation(Variant 
variant) {
                                return resourceService.get(getRequest(), 
getResponse(), variant);
                        }

                        @Override
                        public void post(Representation representation) {
                                resourceService.post(getRequest(), 
getResponse(), representation);
                        }

                        @Override
                        public void put(Representation representation) {
                                resourceService.put(getRequest(), 
getResponse(), representation);
                        }

                        @Override
                        public void delete() {
                                resourceService.delete(getRequest(), 
getResponse());
                        }

                        /**
                         * Overriden to allow a POST without a message body.
                         */
                        @Override
                        public void handlePost() {
                                post(getRequest().getEntity());
                        }

                };
        }

}
/*
 * Author: Adam Taft - [EMAIL PROTECTED]
 * License: Public Domain 2007
 */

package com.adamtaft.restlet.services;

import java.util.List;

import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.Variant;
import org.springframework.transaction.annotation.Transactional;


public interface ResourceService {

        List<Variant> getVariants();
        
        boolean allowGet(Request request);
        
        boolean allowPost(Request request);
        
        boolean allowPut(Request request);
        
        boolean allowDelete(Request request);
        
        @Transactional(readOnly=true)
        Representation get(Request request, Response response, Variant variant);
        
        @Transactional(readOnly=false)
        void post(Request request, Response response, Representation 
representation);
        
        @Transactional(readOnly=false)
        void put(Request request, Response response, Representation 
representation);
        
        @Transactional(readOnly=false)
        void delete(Request request, Response response);        
        
}

Reply via email to