Pages

Showing posts with label Weld. Show all posts
Showing posts with label Weld. Show all posts

Wednesday, December 16, 2009

Developing Custom Scopes/Contexts For Weld

This one came up while developing an example JEE6 project, which I'll add it up here in the future. The case is I had a textbox bound to a request scoped bean. When user triggers the paint action the value in the textbox is to be added to the list below and the textbox should be empty. I thought marking the component request scoped should have been enough to empty its values but it didn't.Apparently to empty the value;
1. I might set the value of the field at the action method. Use a clone for the list.
2. Use a JSF component that doesn't redisplay value after post back like the inputSecret.
3. Develop a custom scope that recreates it self after actions are invoked.
Anyway maybe I am missed a simpler solution but I chose number 3 :) .
To do that first thing is to create a new scope type. I called my scope the "ActionScoped":
1:  @NormalScope(passivating=false)
2: @Retention(RUNTIME)
3: @Target({TYPE, METHOD})
4: @Inherited
5: public @interface ActionScoped {
6: }
@NormalScope annotations marks an annotation as a scope-type. Next we need a context that would define when these action scoped objects exist like the request scope exist while there is a http request... This is the action context :
1:  import org.jboss.weld.context.AbstractThreadLocalMapContext;
2: import org.jboss.weld.context.api.helpers.ConcurrentHashMapBeanStore;
3:
4: public class ActionContext extends AbstractThreadLocalMapContext {
5:
6: private static ActionContext instance = new ActionContext();
7:
8: private ActionContext() {
9: super(ActionScoped.class);
10: }
11:
12: public static ActionContext getInstance() {
13: return instance;
14: }
15:
16: @Override
17: protected boolean isCreationLockRequired() {
18: return false;
19: }
20:
21: public void activate() {
22: setActive(true);
23: setBeanStore(new ConcurrentHashMapBeanStore());
24: }
25:
26: public void deActivate() {
27: destroy();
28: setActive(false);
29: setBeanStore(null);
30: }
31:
32: public void reActivate() {
33: deActivate();
34: activate();
35: }
36: }
It's backed with an thread local object which is handled by the weld parent class. Bean store is where we are going to store the scoped beans. Plus I added some methods to activate (set a new bean store) /deactivate (destroy the bean store) the context. Now this context has to be activated with the start of the restore view.Deactivated and reactivated after the invoke application phase. Here is a phase listener that does that :
1:  public class ActionScopedPhaseListener implements PhaseListener {
2:
3: public void beforePhase(PhaseEvent event) {
4: if (event.getPhaseId().equals(PhaseId.RESTORE_VIEW)) {
5: ActionContext.getInstance().activate();
6: }
7: }
8:
9: public void afterPhase(PhaseEvent event) {
10: if (event.getPhaseId().equals(PhaseId.RENDER_RESPONSE)) {
11: ActionContext.getInstance().deActivate();
12: } else if (event.getPhaseId().equals(PhaseId.INVOKE_APPLICATION)) {
13: ActionContext.getInstance().reActivate();
14: }
15: }
16:
17:
18: public PhaseId getPhaseId() {
19: return PhaseId.ANY_PHASE;
20: }
21: }
22:
Now last thing we have to do is register our context object. In order to do that we need to define an 'extension'. There is a nice example here about extensions, spi... Without an extension we are not able listen to events fired from the weld container which we could use to add our new context object. To define an new context we need the META-INF/services/javax.enterprise.inject.spi.Extension file which contains the qualified name of our extensions class. In this case it's 'org.mca.ewall.extensions.Extensions'. Here is what the class looks like :
1:  public class Extensions implements Extension, Service{
2:
3: public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager manager) {
4: event.addContext(ActionContext.getInstance());
5: }
6:
7: public void cleanup() {
8: }
9: }
It simply registers the context object after the application starts up (after the beans are discovered by the weld container). Now the beans could be annotated as @ActionScoped.

Wednesday, December 9, 2009

State of the 'Dependecy Injection'

"Dependecy Injection" is one of the most popular design patterns on the Java platform. It was suggested by Martin Fowler, here, instead of the term "Inversion of control". Article was published on 2004.
What it brings to a application is a way to create, compose, use and destroy any java object, which are called beans.
The leading framework that first used this approach was the "the Spring Framework". The approach emerged as a alternative to EJB's. The applications built with it are easier to test and offered a easy way to integrate to most of the other frameworks and technologies out there. If you check out the api packages you can see the support for other frameworks like jsf, hibernate etc.
Today "Dependecy Injection" is part of JEE6 named CDI, JSR-299. Reference implementation is called Weld. Here are some of the highlights of CDI:
XML vs. Annotations
CDI dumps the xml approach. However there are still some use for xml's. Every bean archive must have a META-INF/beans.xml even if its empty. This file marks the jar archive as a bean archive and is scanned for beans. 'beans.xml' is also where you enable and define the ordering of 'alternative' beans and interceptors.
Qualifiers
First thing that CDI takes to account while trying to inject a bean is the type of the bean. If however there are more than one bean that could qualify CDI requires a Qualifier meta-data to resolve the ambiguity. CDI has a way to define this meta-data as an annotation, thus making our app. strong typed apposed to the usual string based qualifier approach.
Events
By defining a few annotations we could implement the Observer pattern without any boilerplate code.
Decorators
Again with annotations we could implement the decorator pattern.
Part of JEE6
Now we could inject our beans to servlets and filters like we do to any other class.
Overall as far as I could tell CDI looks like it could improve an applications code quality making it decoupled and strong-typed. JEE6 still needs some time though, best implementation out there seems to be JBoss 6 Milestone 1.