Integrating vraptor 3 with guice filter

85 views
Skip to first unread message

TL

unread,
Oct 25, 2010, 4:55:35 PM10/25/10
to caelum-vraptor-en
Hi,
I am trying to integrate the two, and have a conceptual problem.
vraptor is a component, but it is trying to start the injector.
Normally the injector is supplying the components, so the options
are :
1. Guice creates vraptor
2. Vraptor binds to an existing guice injector

I also came across issue 278 http://github.com/caelum/vraptor/issues/issue/278

I want to implement my own integration. I figured out by looking at
the source that I need to write an implementation of
ContainerProvider. I am not clear what this is supposed to do. I
assume that I need to also provide the component factory,
br.com.caelum.vraptor.ioc.Container, but I don't see the place that I
can do that.

The guice integration has this method:
public <T> T provideForRequest(RequestInfo request, Execution<T>
execution) {
VRaptorRequestHolder.setRequestForCurrentThread(request);
REQUEST.start();
try {
return execution.insideRequest(container);
} finally {
REQUEST.stop();
VRaptorRequestHolder.resetRequestForCurrentThread();
}
}

This seems generic code that does not have anything to do with guice
(can use any other container).

So the basic question, what do I have to do to implement my own guice
integration in which guice is the IOC container and vraptor is just
using it as an IOC container.

I see in VRaptorAbstractModule all the vraptor components bound to
guice, it seem to duplicate a lot of the code that is already in guice
(like application context and session handling)

Lucas Cavalcanti

unread,
Oct 25, 2010, 11:43:26 PM10/25/10
to caelum-v...@googlegroups.com
Hi TL,

Hi,
I am trying to integrate the two, and have a conceptual problem.
vraptor is a component, but it is trying to start the injector.
Normally the injector is supplying the components, so the options
are :
1. Guice creates vraptor
2. Vraptor binds to an existing guice injector

VRaptor acts as a DI container, and uses Guice (or Spring, or Pico)
to do the actual implementation. So VRaptor is not a component.

I want to implement my own integration. I figured out by looking at
the source that I need to write an implementation of
ContainerProvider. I am not clear what this is supposed to do. I
assume that I need to also provide the component factory,
br.com.caelum.vraptor.ioc.Container, but I don't see the place that I
can do that.
The ContainerProvider must configure the underlying DI container, both
adding VRaptor components and application components.
Container is a wrapper for fetching components from the DI container.
so container.instanceFor would be a wrapper for injector.getInstance
 
The guice integration has this method:
       public <T> T provideForRequest(RequestInfo request, Execution<T>
execution) {
               VRaptorRequestHolder.setRequestForCurrentThread(request);
               REQUEST.start();
               try {
                       return execution.insideRequest(container);
               } finally {
                       REQUEST.stop();
                       VRaptorRequestHolder.resetRequestForCurrentThread();
               }
       }

This seems generic code that does not have anything to do with guice
(can use any other container).
We couldn't come up with a better implementation for this method.
The VRaptorRequestHolder is a thread local (nasty, I know) for holding all
request infos, so we can access them in the Request Providers
(VRaptorAbstractModule#requestInfoBindings)
I don't know a better way to do it, ideas are most welcome =)

So the basic question, what do I have to do to implement my own guice
integration in which guice is the IOC container and vraptor is just
using it as an IOC container.
As I said before, VRaptor acts as the DI container.
The whole problem is that VRaptor's filter must start the RequestExecution
using the actual DI container, and in order to do so it configures the container
(via the ContainerProvider).
We have to receive the configured container on filters start method somehow,
or just modify the VRaptor filter.

I think this would work for the modified filter:
- on start, create an injector that installs VRaptorAbstractModule (or something alike).
- on doFilter, simply forget the provider.providerForRequest method and do instead:
   injector.getInstance(RequestExecution.class).execute();

I see in VRaptorAbstractModule all the vraptor components bound to
guice, it seem to duplicate a lot of the code that is already in guice
(like application context and session handling)
Do you mean in the guice-web module?

Can you share your implementation with us?

Thank you very much for the feedback
Regards
Lucas

TL

unread,
Oct 26, 2010, 2:12:28 AM10/26/10
to caelum-vraptor-en
Hi,
I would love to share my implementation, but its does not work :)

One way to implement it is that the guice web container is
instantiating the juice filter since it can already create filters.
This way guice can inject HttpServletRequest and response and a few
other things to any component that needs it. It is possible to just
create

Another way is that vraptor is starting as a normal filter (web.xml),
and then gets the Injector from a context attribute. This is how I
implemented it. If vraptor needs to add more components to the IOC
container, it can wrap it in another injector that contains the extra
vraptor implementation classes, and then use that injector.

In the current implementation, it would be useful to have a method
where I can specify my own modules, so if I have my DAOs and services
already in modules, I can pass them in.

Another thing to look at is the FreeMarker servlet. It is very easy to
extend by subclassing.

Another idea is that there is a clear separation between injected
classes and request data. So for example, RequestInfo is a data class,
and it is never part of an injection chain. It is passed as a runtime
argument to method calls. Other classes that are injected, never have
this object as a required injection value.

My current implementation looks something like that:

public class GuiceContainerProvider implements ContainerProvider {
static final LifecycleScope REQUEST = new RequestCustomScope();
Container container;

@Override
public <T> T provideForRequest(RequestInfo request,
Execution<T> execution) {
VRaptorRequestHolder.setRequestForCurrentThread(request);
REQUEST.start();
try {
return execution.insideRequest(container);
} finally {
REQUEST.stop();
VRaptorRequestHolder.resetRequestForCurrentThread();
}
}

@Override
public void start(ServletContext context) {
final Injector injector = (Injector) context
.getAttribute(Injector.class.getName());

container = injector.getInstance(Container.class);
}

@Override
public void stop() {
container = null;
}
}

public class GuiceContainer implements Container {

private final Injector injector;

@Inject
private GuiceContainer(Injector injector) {
this.injector = injector;
}

@Override
public <T> T instanceFor(Class<T> type) {
return injector.getInstance(type);
}

@Override
public <T> boolean canProvide(Class<T> type) {
// TODO: The factory method will create a new object every time, not
necessarily good
// maybe just return true.
return instanceFor(type) != null;
}
}

Lucas Cavalcanti

unread,
Oct 26, 2010, 6:40:17 AM10/26/10
to caelum-v...@googlegroups.com
Hi,

On Tue, Oct 26, 2010 at 3:12 AM, TL <twl....@gmail.com> wrote:
Hi,
I would love to share my implementation, but its does not work :)

One way to implement it is that the guice web container is
instantiating the juice filter since it can already create filters.
This way guice can inject HttpServletRequest and response and a few
other things to any component that needs it. It is possible to just
create
The problem with this approach is that it is not portable to Spring and Pico providers,
and we need it =( 

Another way is that vraptor is starting as a normal filter (web.xml),
and then gets the Injector from a context attribute. This is how I
implemented it. If vraptor needs to add more components to the IOC
container, it can wrap it in another injector that contains the extra
vraptor implementation classes, and then use that injector.
Did you install the VRaptorAbstractModule in this injector? 

In the current implementation, it would be useful to have a method
where I can specify my own modules, so if I have my DAOs and services
already in modules, I can pass them in.
The current GuiceProvider has a method customModule, so you can return
your own module (and disable VRaptor's auto scan)
 
Another thing to look at is the FreeMarker servlet. It is very easy to
extend by subclassing.

Another idea is that there is a clear separation between injected
classes and request data. So for example, RequestInfo is a data class,
and it is never part of an injection chain. It is passed as a runtime
argument to method calls. Other classes that are injected, never have
this object as a required injection value.
Depending on RequestInfo was a very bad idea indeed. I will refactor these
classes, removing this dependency.

what isn't working in this implementation?

[]'s
Lucas

Reply all
Reply to author
Forward
0 new messages