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.

1 commentaire:

marekd a dit…

Hey,

I'm kinda new to the GDS and got a little problem using the functionality described in the following:
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.

In my case an equivalent of the Post class does not get explicitly imported in the generated .as class. Neither it does in the code you posted. Is this a desired behaviour? (I'm using the 2.1 generator with flexmojos and standard templates).

Marek