Hi again,

Let me answer inline:

> I upgraded to RC3 and am getting seriously confused.

Oh oh :)

> I have to rewrite most of my application's restlet-related 
> code, and I can't
> figure out how I should do it.

The major change should be regarding Handlers. In most cases you should be
able to completely remove them as their equivalent Finder is now more
dynamic and able to instantiate target Resources based on a given class.

> I started with Handlers, then I replaced them with Finders (along with
> associated Resource classes); and now.
> it seems like I can attach resources to a router, and that 
> the framework will
> take care of the finder.

Perfect. 

> My problem is that I don't understand what the Resource 
> classes are supposed to
> do. Tthe tutorial and the
> code from the example directory are very different; I'm not 
> sure which one I
> should follow.

Currently the Tutorial stops short of explaining how to use resources. I
have a task to add a new section for RC3. This is long overdue. There are
new examples available, especially in the org.restlet.example.book.rest.ch7
package that should provide better guidance for now.
 
> Let me give  you an example. I want to create beans with:
>     POST /bean HTTP/1.1
>     Host: localhost:8182
>     Accept: application/xml
>     name=titi
> 
> and have the server return an  xml representation of the 
> newly created object.

OK. Just a side note, maybe a PUT would be more appropriate here.

> Beans a retrieve  with:
>     GET /bean/we HTTP/1.1
>     Host: localhost:8182
>     Accept: application/xml

OK.

> Here is the code:
> 
>   public static class MyBean{
>     public MyBean(String name){this.name = name;}
>     public String name;
>   }
> 
>   public static class MyBeanResource extends Resource{
> 
>     private MyBean myBean;
> 
>     public MyBeanResource(Context context, Request request, Response
> response){[...]}
> 
>     @Override public boolean allowPost() {return true;}
>     @Override public boolean allowGet() {return true;}
> 
>     @Override public  List<Variant> getVariants(){[...]}
>     @Override public void post( Representation entity){[...]}
>     @Override public Representation getRepresentation(Variant 
> variant) { [,,,]}
>   }

One remark: allowGet() returns true by default so you don't have to override
it in your case. Also, getVariants() has a good default implementation and
shouldn't be overriden IMO. I should probably make it final to prevent
confusion. It is better to update the list of variants from the constructor
instead, because if getVariants() is invoked several times it can be costly
to recreate the list multiple times.
 
>  public void main(String[] args){
> 
>     Application application = new Application() {
>         @Override public Restlet createRoot() {
>           Router router = new Router(getContext());
>           router.attach("/bean", MyBeanResource.class);
>           return router;
>         }
>       };
>      [...]
>       component.start();
> }

Perfect. If you convert it to use PUT, you also also change to URI to
"/bean/{beanId}" and retrieve the "beanId" value in the request's attributes
map.

> The finder uses reflection to build a MyResource object.
> So for a GET, the constructor should retrieve the approriate bean:
> 
>   public MyBeanResource(Context context, Request request, 
> Response response){
>       super(context,request,response);
>       String name = request.getResourceRef().getLastSegment();
>       myBean = new MyBean(name);
>     }

Here you should add those lines at the end:

        getVariants().add(new Variant(MediaType.TEXT_PLAIN);
        getVariants().add(new Variant(MediaType.APPLICATION_XML));

Then, you can remove your overriden getVariants() method.

> So far so good, but what about  POSTs? Should the constructor 
> check the 
> method type, like so:
> 
>   public MyBeanResource(Context context, Request request, 
> Response response){
>       super(context,request,response);
>       if (request.getMethod().equals(Method.GET)) {
>         String name = request.getResourceRef().getLastSegment();
>         myBean = new MyBean(name);
>       } else {
>         // it's a POST - nothing to do.
>       }
>     }
> This doesn't sound right.

Indeed this would be confusing. The method-based dispatching in the
responsability of the caller, not the resource itself. Once the
MyBeanResource instance is created, the Finder will introspect it to find
the matching handle*() method based on the method name. Most of the common
methods already have an implementation of handle*() on the base Resource
class.

For example, handleGet() provides support for content negotiation based on
the getVariants() and getRepresentation() methods. The handlePost() methods
relies on the post() method, the handlePut() on the put() method, etc.

As a writer of a Resource subclass, you should only have to override the
post(Representation entity) method to support POST methods.

> Now, the getVariants method. Is its purpose to return all the 
> representation 
> types the resource can have (text/plain, application/xml, etc.)?.
> 
>     @Override public  List<Variant> getVariants(){
>       Variant v = new Variant(MediaType.TEXT_PLAIN);
>       List<Variant> variants = new ArrayList<Variant>();
>       variants.add(new Variant(MediaType.TEXT_PLAIN);
>       variants.add(new Variant(MediaType.APPLICATION_XML));
>       return variants;
>     }

See above, I will finalize it so that it can't be overriden.

> The getRepresentation seems pretty straightforward:
> 
> @Override public Representation getRepresentation(Variant variant) {
>       if (variant.getMediaType().equals(...)){
>         return new StringRepresentation(myBean.name);
>       } else if (variant.getMediaType().equals(...)){
>         return new....
>       } else {
>         return new StringRepresentation(myBean.name);
>       }
>   }

OK.

> As for the post method I would do something like:
> 
>  @Override public void post( Representation entity){
>       // create the bean
>       Form form = new Form(entity);
>       String name = form.getValues("name");
>       myBean = new MyBean(name);
>       getResponse().setStatus(Status.SUCCESS_CREATED);

If you want to retrieve only the first "name" value, use
form.getFirstValue("name") instead.

> getResponse().setRedirectRef("http://localhost:8182/bean/"; + name);
>       // return a representation of the newly created bean
>       getResponse().setEntity(this.getRepresentation(???);
>     }

In order to make your redirection more portable, you can do this instead:

getResponse().setRedirectRef(getRequest().getRootRef() + "/bean/" + name);

> But, how do I have access to the client's preferred variant 
> (application/xml in
> this case)?

This is done automatically for you in the Resource.handleGet() method. You
don't have to worry about it unless you really want to provide your a custom
implementation (not recommended as this is complex).

> Any clarification is welcome.

The confusion probably comes from the increased responsability of Resource.
In RC2, all the handle*() methods were implemented in the Handler. Now
Resource has a better control on this, which also allows the transparent
usage of Finder, without needing subclasses in most cases. This should
significantly reduce the code size necessary in your application (it did in
the ones I was developping, like the examples mentionned above).

Best regards,
Jerome  

Reply via email to