With the invaluable help of Bruno Harbulot (and Thierry and Jerome!), I checked 
in a preliminary version of org.restlet.ext.guice to the incubator sources. I 
confirmed that it works for one somewhat artificial example (see 
org.restlet.ext.guice.example), but it needs more eyes on it, it needs tests, 
and it needs some real use.

The design is very much like what I reported blogging about at the beginning of 
this thread, except that FinderFactory is now called DependencyInjection 
because it adds a few "extension methods" for attach/attachDefault (on Routers 
and Virtual Hosts) and setNext (on Filters, Servers, and ServerLists). 

The idea is that you "wrap" regular attach/attachDefault/setNext calls with 
DependencyInjection calls to inject a target ServerResource. For example:

 DependencyInjection di = ...;

 TemplateRoute route = di.attach(router, "/path", MyResource.class);
   // same as router.attach("/path", di.finderFor(MyResource.class));

 // Secret is a Qualifier (JSR-330's version of BindingAnnotation)
 di.setNext(filter, AnotherResource.class, Secret.class);
   // same as filter.setNext(di.finderFor(AnotherResource.class, Secret.class));
 
I moved the FinderFactoryModule into the RestletGuice class, which was 
previously just a container for static methods, so it is now 
RestletGuice.Module. It implements DependencyInjection, and it still has the 
property that if it hasn't been used to create an Injector by the time one of 
its DependencyInjection methods is called, an Injector is created lazily from 
it.

I removed all mention of com.google.inject from DependencyInjection, so this 
interface would be suitable for use with any JSR-330-compliant DI framework. 
All this meant was replacing methods that take a Key argument with variants 
taking a Class<? extends ServerResource> and a Class<? extends Annotation>, 
where the latter must be a javax.inject.Qualifier (or 
com.google.inject.BindingAnnotation).

I removed support for Restlet 1.1 Handlers.

I don't think I'm using any features of Guice introduced in 2.0, but I haven't 
checked to see if it still works with Guice 1.x.

I haven't touched the code that I put in originally to deal with use of a 
single instance of a RestletGuice.Module by multiple Injectors; I suspect it 
isn't correct. I'll fix it eventually, but it seems like a pretty marginal use, 
so it's not a big priority.

I haven't provided any custom Scopes because no one has told me of a Scope need 
that is so common and yet so tricky that it's worth complicating this extension 
to keep people from having to roll it themselves. If you think you have such a 
need, let me know.

ResletGuice.Module binds providers for Application, Context, Request, and 
Response that by default use the getCurrent class method of the corresponding 
class. The getCurrent methods rely on a ThreadLocal value that is set properly 
for most purposes, including tasks executed via a TaskService; if you need to 
change the default behavior, you can override newApplicationProvider, 
newContextProvider, newRequestProvider, and newResponseProvider in a subclass 
of RestletGuice.Module.

There should be no barriers to using RestletGuice.Module in conjunction with 
other frameworks, including guice-servlet. All you need to do is ensure that 
your resource bindings are made in Modules passed to the constructor of a 
RestletGuice.Module that is used to create the final Injector.

I was going to extend Router to make the functionality a little more 
transparent, but that would prevent the extension of Router for other purposes. 
Also, for completeness I would have had to extend VirtualHost, Filter, Server, 
and ServerList, and you'd have to use those new subclass names to get access to 
the variant that takes a qualifier annotation type. It would have been a lot of 
API noise instead of just one interface.

I considered another approach that I'd like to get feedback on, a mini-DSL, 
where the previous examples would look like this:

 TemplateRoute route = di.with(router).attach("/path", MyResource.class);
 di.with(filter).setNext(AnotherResource.class, Secret.class);

That would add a few more interfaces for the intermediate types in the DSL, but 
they wouldn't be in your face. Would this be a better API?

--tim

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2427214

Reply via email to