jeudi 5 novembre 2009

New in GraniteDS 2.1.0 RC1: early support for JSR-299 / JCDI

GraniteDS has almost always had support for EJB3 and JBoss Seam. With the advent of JEE6, support for JSR-299 / JCDI is quite a natural evolution and probably a must have in a not so far future.

So what's in this first implementation :

  • Tide remoting to JCDI Named components

  • All features supported for EJB3: integration with container security, paging, lazy loading

  • Support for JCDI conversations

  • Support for client-side Flex event observers of JCDI typed events


  • Note that for now it will work only with the Weld implementation, as conversation support requires using some non public JSR-299 API.

    Also the supported containers are for now JBoss 5.2 trunk (available here and GlassFish V3 starting from build 70 (available here). It will probably not work in Tomcat for now.

    The GraniteDS distribution contains a graniteds-tide-jcdi example that can be deployed in any of these application servers.

    Configuration

    The configuration is almost the same as for other server framework integrations and consists in five parts :

  • Add the GDS libraries in WEB-INF/lib : granite.jar, granite-jcdi.jar and granite-hibernate.jar (or granite-eclipselink.jar for GlassFish)

  • Add the AMF (and Gravity if needed) servlets in web.xml

  • Add the following granite-config.xml in WEB-INF/granite :
  • <granite-config scan="true">
    <security type="org.granite.messaging.service.security.TomcatSecurityService"/>

    <tide-components>
    <tide-component instance-of="org.granite.tide.jcdi.JCDIIdentity"/>
    <tide-component annotated-with="org.granite.messaging.service.annotations.RemoteDestination"/>
    </tide-components>
    </granite-config>

  • Configure the Tide JCDI service factory in services-config.xml in WEB-INF/flex :
  • <factories>
    <factory id="tideJcdiFactory" class="org.granite.tide.jcdi.JCDIServiceFactory"/>
    </factories>

  • Add an empty beans.xml in WEB-INF

  • Remoting

    Once this is done, add your named JCDI bean and annotate it with @RemoteDestination :

    @Named("helloWorld")
    @RemoteDestination(id="helloWorld")
    public class HelloWorld {

    public String hello(String name) {
    return "hello" + name;
    }
    }

    Then you can easily call it from Flex using Tide remoting and injection :

    <mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns="*"
    preinitialize="Jcdi.getInstance().initApplication()">

    <mx:Script>
    <![CDATA[
    import org.granite.tide.jcdi.Jcdi;
    import org.granite.tide.Component;

    [In]
    public var helloWorld:Component;
    ]]>
    </mx:Script>

    <mx:Button label="Hello" click="helloWorld.hello('Barack')"/>

    </mx:Application>

    You can even use typesafe client proxies (e.g. public var helloWorld:HelloWorld) if you have generated them with gas3. Maybe in RC2 we'll try to use completely typesafe service invocation and will not require @Named beans any more.

    Events

    Support for events is relatively similar to what exists for Seam, but with JCDI it uses typesafe events.
    Define your Java and as3 event classes (in the final release it will be possible to generate the as3 event class automatically with gas3) :
    public class GreetingEvent {
    private String name;

    public GreetingEvent(String name) {
    this.name = name;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    }
    [RemoteClass(alias="test.app.GreetingEvent")]
    public class GreetingEvent extends AbtractTideEvent {
    public var name:String;
    }

    Fire an event from the server method :
    @Named("helloWorld")
    @RemoteDestination(id="helloWorld")
    public class HelloWorld {

    @Inject @Any
    Event greetingEvent;

    public String hello(String name) {
    greetingEvent.fire(new GreetingEvent(name));
    return "hello" + name;
    }
    }

    Then just declare a remote observer in the Flex application and it will be triggered whenever the event is dispatched during a remote call initiated from Flex.
    <mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns="*"
    preinitialize="Jcdi.getInstance().initApplication()">

    <mx:Script>
    <![CDATA[
    import org.granite.tide.jcdi.Jcdi;
    import org.granite.tide.Component;

    [In]
    public var helloWorld:Component;

    [Observer(remote="true")]
    public function greet(event:GreetingEvent):void {
    trace("Greeting to " + event.name);
    }
    ]]>
    </mx:Script>

    <mx:Button label="Hello" click="helloWorld.hello('Barack')"/>

    </mx:Application>



    This is really just an early implementation of this integration and it will be updated for the final release of the JCDI specification and RI.

    Our feeling is that JCDI is a perfect fit for Flex RIAs with an event-driven architecture. JCDI applications looks extremely clean and even JBoss Seam provides a lot more features, they do not necessarily make sense with a RIA front-end.

    Feel free to give some feedback and maybe some ideas for this integration.

    9 commentaires:

    Gavin a dit…

    Looks good. The only think I wondered is do you really need to use a string based @Name to refer to the bean from the client side? Could you use type-based resolution instead?

    Gavin a dit…

    http://in.relation.to/Bloggers/GraniteDSAndCDI

    James Ward a dit…

    This is awesome! Nice work!

    William Draï a dit…

    Hi Gavin, thanks for talking about this on your blog.
    As I told in the post, type-based invocation will be implemented in the final release. It's in fact almost ready but requires many changes in the client-side framework so we had not enough time to include it in RC1.

    Nicklas Karlsson a dit…

    This looks cool, we are looking to start migrating a largeish application (bit by bit) from Oracle Forms to a more modern platform and with the advent of Java EE 6, the pieces are slowly coming into place.

    There are many nice AJAX based JSF components frameworks but some views could benefit from an alternative RIA frontend and this certainly looks like a candidate. We would of course like to minimize code duplication so the tighter the integration is, the better (entities in dropdowns, validation integration, exception propagation etc)...

    Unknown a dit…

    Learning the GraniteDS and flex. Spent the whole weekend to build the jcdi example in eclipse. But fail.

    Than, follow the instruction to build the jcdi example using ANT script. Deployed to Glassfish or JBoss 5.2.1 GA. Both are having the same exceptions:

    SEVERE: Exception while pre processing the request message.
    java.util.NoSuchElementException
    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:796)
    at java.util.HashMap$KeyIterator.next(HashMap.java:828)
    at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1010)
    at org.granite.jcdi.JCDIInterceptor.before(JCDIInterceptor.java:104)
    at org.granite.messaging.amf.process.AMF3MessageProcessor.process(AMF3MessageProcessor.java:56)
    at org.granite.messaging.amf.process.AMF0MessageProcessor.process(AMF0MessageProcessor.java:78)
    at org.granite.messaging.webapp.AMFMessageServlet.doPost(AMFMessageServlet.java:59)

    Any advise?

    Keith

    Viresh a dit…
    Ce commentaire a été supprimé par un administrateur du blog.
    Gexton a dit…

    granite countertops edmonton
    Thanks, you guys that is a great explanation. keep up the good work..

    Web Honerks a dit…

    very informative your article. Thank you for sharing this post.
    granite countertops services Toronto