Affichage des articles dont le libellé est cdi. Afficher tous les articles
Affichage des articles dont le libellé est cdi. Afficher tous les articles

samedi 27 novembre 2010

GraniteDS Maven archetypes 1.0 RC1 released

We have noticed from a long time that starting a new project with GraniteDS and the usual Java frameworks is not easy enough. We have tried to simplify the configuration as much as possible by allowing to configure GraniteDS directly in the Spring and Seam configuration files but yet there are many steps and caveeats that can take lots of time when setting up a project. It is even more painful when you add the setup of the build system with Ant or Maven.

Fortunately Maven provides a handy mechanism to bootstrap new projects in the form of archetypes. Along with the release of GraniteDS 2.2, we have also released a set of 4 archetypes for common use cases of GraniteDS :
  • graniteds-spring-jpa-hibernate: Flex 4 + Spring 3 + Hibernate/JPA + GraniteDS with standard RemoteObject API
  • graniteds-tide-spring-jpa-hibernate: Flex 4 + Spring 3 + Hibernate/JPA + GraniteDS with Tide API
  • graniteds-tide-seam-jpa-hibernate: Flex 4 + Seam 2.2 + Hibernate/JPA + GraniteDS with Tide API
  • graniteds-tide-cdi-jpa: Flex 4 + CDI/Weld 1.0 + JPA + GraniteDS with Tide API
It is recommended to use Maven 3 but Maven 2.2 should also work. You can run the archetypes from the command line :
mvn archetype:generate
-DarchetypeGroupId=org.graniteds.archetypes
-DarchetypeArtifactId=graniteds-tide-spring-jpa-hibernate
-DarchetypeVersion=1.0.0.RC1
-DgroupId=com.myapp
-DartifactId=example1 -Dversion=1.0-SNAPSHOT
This will create of project named example1 that you can directly build and run with maven :
cd example1
mvn install
cd webapp
mvn jetty:run-war
Then browse http://localhost:8080/example1/example1.swf. The generated project is a multimodule application skeleton with a Java module, a Flex module and a Web module. It includes basic security, service remoting and data synchronization. The default security configuration includes two hardcoded users: admin/admin and user/user.

It is a good starting point to build your own application, after removing the very few example parts. The most interesting thing in these archetypes is that the build poms are automatically created and that they reference selected versions of each framework (Flex, Spring, Seam, Hibernate...) and of build tools (Flexmojos, Jetty plugin...) that work together correctly.

Spring and Seam archetypes are built to be run inside Jetty (for example with the Maven Jetty plugin as shown before). The CDI/Weld example is built to be run inside GlassFish v3.0.1+ and should also work in JBoss 6 M4 (but not later as next versions include the newer and incompatible Weld 1.1). By default it can be run in embedded GlassFish with :
cd example1
mvn install
cd webapp
mvn embedded-glassfish:run
If you don't want to run inside an embedded container but in Tomcat or another container, and still want to use real-time messaging, you will have to change the Gravity servlet implementation in the web.xml file (implementation class names for Tomcat and JBoss 5+ are in comment in the generated web.xml). Then build a war to be deployed in any application server with :
cd webapp
mvn war:war
This is not a final release of these archetypes but they are already usable. They mostly miss the necessary Maven stuff to run unit tests for Flex and Java projects.

As always don't hesitate to give your feedback.

jeudi 21 janvier 2010

New in GraniteDS 2.1.0 RC2: more fun with JEE6/CDI

As early testers have discovered, there have a been a few changes in the CDI API that broke the GDS integration since RC1 was released.
GraniteDS 2.1 RC2 now supports the latest CDI specification and Weld RI as included in JBoss 6 M1 and GlassFish v3 final. It can be downloaded here. There have also been improvements in the integration itself :
  • Tide remoting to CDI components (both @Named and type-safe)

  • All standard features of GraniteDS : container security, paging, lazy-loading

  • Support for CDI conversations

  • Support for client-side observers for remote CDI events

  • Client/server synchronization of CDI beans

Il still only works with Weld because of conversation support, but it should be easy to integrate with other implementations by only adapting the CDIInterceptor implementation.
Currently supported containers are JBoss 6.0 M1 and GlassFish v3 final. Some people also managed to get it working in Tomcat 6.

Configuration for JBoss 6 M1

As JBoss 6 does not support servlet 3 yet, the configuration still invoves quite a few files :
  • Add GDS libs in WEB-INF/lib : granite.jar, granite-cdi.jar and granite-hibernate.jar

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

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

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

  • Configure the CDI service factory in WEB-INF/flex/services-config.xml :
    <services>
    <service id="granite-service"
    class="flex.messaging.services.RemotingService"
    messageTypes="flex.messaging.messages.RemotingMessage">

    <destination id="cdi">
    <channels>
    <channel ref="graniteamf"/>
    </channels>
    <properties>
    <factory>tideCdiFactory</factory>
    </properties>
    </destination>
    </service>
    </services>
    ...
    <factories>
    <factory id="tideCdiFactory" class="org.granite.tide.cdi.CDIServiceFactory"/>
    </factories>

  • Add an empty beans.xml in WEB-INF

Note that this configuration should also work in Tomcat 6 with a few restrictions.

Configuration for GlassFish v3 and Servlet 3 containers

  • Add GDS libs in WEB-INF/lib : granite.jar, granite-cdi.jar and granite-eclipselink.jar (or the GDS jar corresponding to your JPA provider)

  • Add a configuration class somewhere in your project :
    @FlexFilter(
    tide=true,
    type="cdi",
    factoryClass=CDIServiceFactory.class,
    tideInterfaces={Identity.class}
    )
    public class GraniteConfig {
    }

  • Add an empty beans.xml in WEB-INF

Note that with this kind of simplified configuration, there is no more services-config.xml so it is required to setup the RemoteObject endpoints manually with :
Cdi.getInstance().addComponentWithFactory("serviceInitializer", DefaultServiceInitializer, { contextRoot: "/graniteds-tide-cdi" });

Remoting

Once your application is setup for GraniteDS, you can easily enable remote access from Flex to CDI beans by adding the @RemoteDestination annotation :
@RemoteDestination
public class HelloWorld {

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

If you can live without full type-safety, you can also add a @Named annotation and then access your beans from Flex with :
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns="*"
preinitialize="Cdi.getInstance().initApplication()">

<mx:Script>
<![CDATA[
import org.granite.tide.cdi.Cdi;
import org.granite.tide.Component;

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

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

</mx:Application>

If you don't want string-based references, you can use the gas3 generator to generate a Flex remote proxy for the server bean. Just include the bean class in the gas3 generation path, it will be recognized as a service by the @RemoteDestination annotation. Then you can use type-safe injection in Flex with the new [Inject] Tide annotation :
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns="*"
preinitialize="Cdi.getInstance().initApplication()">

<mx:Script>
<![CDATA[
import ...;

[Inject]
public var helloWorld:HelloWorld;
]]>
</mx:Script>

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

</mx:Application>

In this case, Tide will do a lookup of the bean by type. If there is more than one implementation, you must add @Named to let Tide choose between them because there is no real equivalent of typesafe annotations in ActionScript 3.

Events

Since RC1, the only change is that gas3 now supports the @TideEvent annotation and is able to generate a corresponding Flex event class.
@RemoteDestination
public class HelloWorld {

@Inject @Any
Event greetingEvent;

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

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

<mx:Script>
<![CDATA[
import ...;

[Inject]
public var helloWorld:HelloWorld;

[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>

Client/server bean synchronization

This is quite experimental but it can be useful in some cases. It first requires to enable two interceptors in beans.xml :
<beans>
<interceptors>
<class>org.granite.tide.cdi.TideComponentInterceptor</class>
<class>org.granite.tide.cdi.TideBeanInterceptor</alias>
</interceptors>
</beans>

Note that if you have interceptors to handle transactions, they must be setup before Tide interceptors so these Tide interceptors are executed inside the transaction context.
Then you can annotate beans that you want to synchronize with @TideBean and Tide will ensure that any change made on the client is sent to the server and that any change made on the server bean is updated on the client. This synchronization process is not immediate but always delayed until the next remote call.
@TideBean @RequestScoped
@ExternalizedBean(type=DefaultExternalizer.class)
public class CurrentPerson {

private Person person;
private String greeting;

public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}

public String getGreeting() {
return greeting;
}
public void setGreet(String greeting) {
this.greeting = greeting;
}
}

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

<mx:Script>
<![CDATA[
import ...;

[Inject]
public var helloWorld:HelloWorld;

[Inject]
public var currentPerson:CurrentPerson;

private function hello():void {
currentPerson.person = new Person("Barack");
helloWorld.hello();
}

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

<mx:Button label="Hello" click="hello()"/>

</mx:Application>

@RemoteDestination
public class HelloWorld {

@Inject @Any
Event greetingEvent;

@Inject
CurrentPerson currentPerson;

public void hello() {
String name = currentPerson.getPerson().getName();
currentPerson.setGreeting("hello " + name);
greetingEvent.fire(new GreetingEvent(name));
}
}

Besides the fact that this piece of code is as useless and convoluted as it can be, this bean synchronization feature should work in more useful cases.
Note that the interaction is completely typesafe accross Java/CDI and Flex/Tide, that can help avoiding errors much better than when using string-based EL component names.

mercredi 20 janvier 2010

New in GraniteDS 2.1.0 RC2: more improvements in the gas3 generator and simplified configuration

Improvements in the gas3 generator


The previous entry concerning improvements in the gas3 generator already mentioned the new possibility to define a custom EntityFactory in the ant task.

This configuration is now also available in the Eclipse plugin (Project Properties / GraniteDS / Options.



Moreover two new entity factories are also available and make possible to generate validation annotations for the Flex data model.
  • org.granite.generator.as3.HVEntityFactory supports Hibernate Validator 3 annotations

  • org.granite.generator.as3.BVEntityFactory supports Bean Validation (JSR-303) annotations

Here is what a JPA entity class with validation annotations would look like in as3 with one of these factories :
    [Managed]
public class AuthorBase extends AbstractEntity {

private var _name:String;
private var _numPosts:Number;
private var _posts:ListCollectionView;

public static const meta_hasMany:Object = {
posts: Post
};


public function set name(value:String):void {
_name = value;
}
[Length(min="5", max="50", message="{validator.length}")]
public function get name():String {
return _name;
}

[Bindable(event="unused")]
public function get numPosts():Number {
return _numPosts;
}

public function set posts(value:ListCollectionView):void {
_posts = value;
}
public function get posts():ListCollectionView {
return _posts;
}

override meta function merge(em:IEntityManager, obj:*):void {
var src:AuthorBase = AuthorBase(obj);
super.meta::merge(em, obj);
if (meta::isInitialized()) {
em.meta_mergeExternal(src._name, _name, null, this, 'name', function setter(o:*):void{_name = o as String}, false);
em.meta_mergeExternal(src._numPosts, _numPosts, null, this, 'numPosts', function setter(o:*):void{_numPosts = o as Number}, false);
em.meta_mergeExternal(src._posts, _posts, null, this, 'posts', function setter(o:*):void{_posts = o as ListCollectionView}, false);
}
}

override public function readExternal(input:IDataInput):void {
super.readExternal(input);
if (meta::isInitialized()) {
_name = input.readObject() as String;
_numPosts = function(o:*):Number { return (o is Number ? o as Number : Number.NaN) } (input.readObject());
_posts = input.readObject() as ListCollectionView;
}
}

override public function writeExternal(output:IDataOutput):void {
super.writeExternal(output);
if (meta::isInitialized()) {
output.writeObject((_name is IPropertyHolder) ? IPropertyHolder(_name).object : _name);
output.writeObject((_numPosts is IPropertyHolder) ? IPropertyHolder(_numPosts).object : _numPosts);
output.writeObject((_posts is IPropertyHolder) ? IPropertyHolder(_posts).object : _posts);
}
}
}

Two important things are marked in blue :
  • meta_hasMany is a new generated constant that makes possible to know at runtime the type of data in toMany associations. This has two uses : first it forces the compiler to include the associated class by referencing it, then it can be a useful metadata for any client-side framework to know the real type of the associated class at runtime.

  • [Length] has been generated from a Hibernate Validator annotation. Also this can be useful metadata for a client-side framework. And though this is not of much use right now, it sure will be.

Simplified configuration for Spring, Seam


I've already talked about Spring and Seam in a previous post, I'll just mention a few minor improvements and an important change.
In RC1, this was possible to define simple and JMS messaging destinations in the Spring/Seam configuration. This is now supported for ActiveMQ destinations.
It's also possible to define security roles allowed for the Tide destinations :
<graniteds:flex-filter url-pattern=".." tide="true">
<graniteds:tide-roles>
<graniteds:value>ROLE_USER<value/>
</graniteds:tide-roles/>
</graniteds:flex-filter/>

In Spring, there are two new tags :
<graniteds:tide-persistence id="myPersistence" transaction-manager="transactionManager"/>
This declares a Spring persistence manager for Tide lazy-loading that will use the specified Spring transaction manager. Note that is you have only one Spring transaction manager, this is not necessary and Tide will automatically create a default Spring persistence manager.

<graniteds:tide-identity/>
This defines the default Spring security integration bean for Tide. The parameters for integration with Spring security ACL can also be defined here :
<graniteds:tide-identity acl-service="aclService" sidRetrievalStrategy="sidRetrievalStrategy" objectIdentityRetrievalStrategy="oidRetrievalStrategy"/>


The most important thing is the client-side part. In RC1, you had to define a remoteObjectInitializer and build an AMF channel manually. This is now much easier, but take care that there are minor changes to do in your Flex code :
Spring.getInstance().addComponentWithFactory("serviceInitializer", DefaultServiceInitializer, { contextRoot: "/graniteds-tide-spring" });

As you can see, the job is now done by a service initializer class. The DefaultServiceInitializer is suitable in most cases and can be configured with optional server name, port and url mappings for remoting and messaging.
The defaults are :
  • http://{server.name}:{server.port}/graniteds-tide-spring/graniteamf/amf.txt for remoting

  • http://{server.name}:{server.port}/graniteds-tide-spring/gravityamf/amf.txt for Gravity

If you have custom requirements, such a retrieving these urls remotely for an AIR application, you just have to implement IServiceInitializer and add your implementation as a component.

Simplified configuration for Servlet 3 containers


Servlet 3 is very new and is currently supported only in GlassFish v3. However it brings many improvements for framework developers.
Now you just have to define a configuration class annotated with @FlexFilter somewhere in your project and GraniteDS will completely configure itself, there is absolutely nothing else to do. Here is the config class from the example, it is the equivalent of what would have been in granite-config.xml and services-config.xml :
@FlexFilter(
tide=true,
type="ejb",
factoryClass=EjbServiceFactory.class,
ejbLookup="java:global/graniteds-tide-ejb3/{capitalized.component.name}Bean",
entityManagerFactoryJndiName="java:comp/env/jpa",
tideInterfaces={EjbIdentity.class}
)
public class GraniteConfig {

@MessagingDestination(noLocal=true, sessionSelector=true)
AbstractMessagingDestination addressBookTopic;

}

It's hard to think how to do less : just put granite jars in your WEB-INF/lib, create a simple config class and that's all !
Note how Gravity destinations can be defined as fields of this configuration class with @MessagingDestination, @JmsTopicDestination or @ActiveMQDestination.

We'll see how this works when there will be other Servlet 3 containers but this is definitely a great improvement in usability.

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.