Affichage des articles dont le libellé est seam. Afficher tous les articles
Affichage des articles dont le libellé est seam. 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.

vendredi 9 janvier 2009

New features in GraniteDS 1.2 : Tide support for Seam 2.1 authorizations

Seam 2.1 is the first release that is not tied to the JSF view technology. The Tide integration benefits from this with a little easier deployment (no more JSF jars and servlet configuration).

The migration to Seam 2.1 is very easy : replace granite-tide-seam.jar by granite-tide-seam21.jar and change the security service to
<security type="org.granite.seam21.security.Seam21SecurityService"/>.

Not saying that you also have to change the Seam jars...

Another important new feature of Seam 2.1 is the powerful security/authorization mechanism. We have updated the Seam security service to use the new APIs, but we have mainly added Flex support for server authorizations. The Tide identity component now provides the methods hasRole and hasPermission that request access rights from the server.

The most simple use of these methods is to conditionally enable/show parts of the UI in mxml components depending on user authorizations :

<mx:DataGrid id="dg" dataProvider="{products}"/>

<mx:Button id="bUpdate" label="Update"
enabled="{dg.selectedItem != null}"
visible="{identity.hasPermission(dg.selectedItem, 'update')}"
click="updateProduct()"/>
<mx:Button id="bDelete" label="Delete"
enabled="{dg.selectedItem != null}"
visible="{identity.hasRole('admin')}"
click="deleteProduct()"/>


Here the 'update' button will be showed only if the user has the rights to update the selected entity and the 'delete' button will be shown only to administrators.

The important thing to note is that these access rights are cached on the client and are not requested from the server at each call. This greatly reduces the performance penalty of using them. The hasPermission method is also integrated with the entity cache, meaning that the permission cache for entities is cleared whenever an entity is cleared from the cache.

It is possible to manually clear the cache with identity.clearSecurityCache(). For example you could setup a timer and call this periodically.

The identity.hasRole and identity.hasPermission methods can also be used programmatically in a controller :
Identity.hasRole and Identity.hasPermission can also be used programmatically. As the value may be retrieved asynchonously, the return value of these methods may not be accurate if it was not already in the cache (they return false by default). The correct way of handling this is to pass a result handler function:

public function canDelete(product:Product):void {
identity.hasRole('admin', canDeleteResult);
}

private function canDeleteResult(event:TideResultEvent, role:String):void {
if (!event.result)
Alert.show("You cannot delete the product");
}

public function canUpdate(product:Product):void {
identity.hasPermission(product, 'update', canUpdateResult);
}

private function canUpdateResult(event:TideResultEvent, product:Product, action:String):void {
if (!event.result)
Alert.show("You cannot update the product " + product.name);
}


As getting the result can necessitate a remote call, the hasPermission and hasRole take a result handler that is called when the result is available (immediately when the result is cached). Beware that the direct return value of these methods may not be correct when the data is not in cache.

The above example shows that the result handlers for hasRole and hasPermission have additional arguments that allow to know about the requested role or permission when many permissions are checked simultaneously.

jeudi 20 novembre 2008

Support for Seam 2.1

Support for Seam 2.1 is now in available the trunk and in the latest
GDS nightly builds
(http://www.graniteds.org/bamboo/browse/GDS-SHOTS/latest). Don't
hesitate to give it a try if you are interested to help us testing it
before the stable release.

As a few parts of the API have changed, there are some little
differences of configuration and deployment.

First you will need to use the granite-tide-seam21.jar instead of
granite-tide-seam.jar. The swc library is the same granite-tide-seam.swc.

Most implementation classes are different :

<granite-config scan="true">
<!--
! Use Seam 2.1 based security service.
!-->
<security type="org.granite.seam21.security.Seam21SecurityService"/>

<!--
! Enable Seam components for Tide
!-->
<tide-components>
<component instanceof="org.jboss.seam.security.Identity"/>
<component instanceof="org.jboss.seam.framework.Home"/>
<component instanceof="org.jboss.seam.framework.Query"/>
<component annotatedwith="org.granite.tide.annotations.TideEnabled"/>
</tide-components>
</granite-config>

services-config.xml is exactly the same.

The good news is that you can completely remove all dependencies on
Faces if you don't use it. Thus web.xml can be as simple as :

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>GraniteDS Seam 2.1</display-name>

<!-- Seam -->

<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>

<filter>
<filter-name>AMFMessageFilter</filter-name>
<filter-class>org.granite.messaging.webapp.AMFMessageFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>AMFMessageFilter</filter-name>
<url-pattern>/graniteamf/*</url-pattern>
</filter-mapping>

<servlet>
<servlet-name>AMFMessageServlet</servlet-name>
<servlet-class>org.granite.messaging.webapp.AMFMessageServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>AMFMessageServlet</servlet-name>
<url-pattern>/graniteamf/*</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>


More complete details are here :
http://www.graniteds.org/confluence/display/DOC/3.+Configuration

Remember that if you remove Faces, you will not be able to use
FacesMessages any more (of course) and you will have to use the new
Seam 2.1 StatusMessages API. By default, Tide comes with a basic
implementation of it but it's not necessary to refer explicitly to the
concrete Tide implementation class and you can just use
@In StatusMessages statusMessage;

If you need to use a html view layer side by side with Flex/Tide, this
default TideStatusMessages will be overriden by the view-specific
implementation and you won't have to change anything in the components.

jeudi 16 octobre 2008

GraniteDS Seam AIR Demo

For people wanting to use GDS & AIR, you'll find a sample graniteds_seam_air.zip file here (download graniteds_seam_air.zip).

Some tips:

  1. You need to have graniteds-seam-1.1.0.zip installed in Eclipse (get it on Sourceforge here) and deployed in JBoss (started on localhost:8080).

  2. graniteds_seam_air.zip is an Eclipse/Flex Builder (tested with 3.4.1/3.0.1 versions) project, unzip it in your workspace.

  3. Use (Flex perspective) "Project" -> "Export Release Build..." and check the "Export and signed an AIR..." option (creating a dummy certificate if you don't have one).

  4. Install the Person.air application.


That's it.
Franck.

vendredi 18 juillet 2008

New features of GDS/Tide in 1.1 RC3

The GDS 1.1 RC3 is an important release for the Tide project because it brings a host of new features, most of which have been requested by the Tide users, and which are very powerful and easy to use :

1. Configuration of Tide-enabled components
2. Transparent lazy loading of collections
3. Paged collections, based on the Seam Query component
4. Propagation of Seam events on the Flex client, both synchronous and asynchronous

This makes this release of Tide feature complete. The upcoming final 1.1 release will contain only bugfixes.


Configuration of Tide-enabled components :

The early Tide versions were quite permissive concerning component access.
It was possible to call any component, even system components or entityManager or anything else. This was obviously a security hole.

The RC3 mandates a new (small) configuration to enable only the needed components.
In granite-config.xml, there is a new section which looks like this :

<tide-components>
<component type="org\.myapp\..*"/>
<component name="org\.myapp\..*"/>
<component instanceof="org.jboss.seam.framework.Query"/>
<component annotatedwith="javax.ejb.Stateless"/>
</tide-components>

The 4 methods of enabling Seam components for Tide are :
- by class name match (type=".."), which enables all Seam components which qualified class name matches the regex
- by component name match (name=".."), which enables all Seam components which qualified name matches the regex
- by component class type (instanceof=".."), which enables all Seam components which class extends or implements the specified class/interface
- by component class annotation (annotatedwith=".."), which enables all Seam components which class is annotated with the specified class/interface

The last method can be used in conjuction with either the WebRemote annotation of Seam or with the Tide-specific org.granite.tide.annotations.TideEnabled annotation.

This is important to carefully expose your Seam components, otherwise your application can have a big security hole.
This new configuration is flexible enough and if correctly used, should not be too hard to maintain.


Transparent lazy loading :

This is a most requested feature, as lazy exceptions are already a pain in a pure web environment, and even more in a RIA.
Tide tries to provide a convenient approach to automate this task, particularly in the context of a Seam conversation.

All uninitialized collections retrieved from the server are wrapped by a particular collection implementation, which can be used as data provider for Flex UI component.
When requested by the UI, these collections will trigger a server call to retrieve initialized data. This process follows the standard Flex ItemPendingError mechanism and works with any component handling correctly this mechanism (i.e. DataGrid and List).

For example, if you have an Order object with a lazy collection of Items, you can do :

<mx:DataGrid id="orders" dataProvider="{tideContext.orders}" change="if (selectedItem) { orderItems.dataProvider=selectedItem.items }">
...
</mx:DataGrid>

<mx:DataGrid id="orderItems">
...
</mx:DataGrid>

The collection is fetched only if it is bound to a component, so if the bindings are correctly designed, this transparent loading should not degrade performance by issuing too many server calls.


Paged collection :

The Flex UI components are designed to be able to fetch data on demand, and wait for remote operation when needed, by the use of the ItemPendingError exception.
Unfortunately, there is no standard collection implementation in the Flex SDK which is able to benefit from this feature and provide paginated access to remote data.

The paginated data access is part of the enterprise features of Adobe LCDS, and even this comes with some limitations :
- remote data are retrieved by page, but never cleaned, so when iterating on a LCDS paged collection, you finish by having the whole data on the client
- remote sorting is not automatic, it necessitates to trigger manually a server call on DataGrid events
- there is no way of managing remote filtering

On the other side, Seam provides a very handy Query component, which can simplify many operations on queries, in particular sorting and filtering data.

The goal of the Tide Query integration is to provide a paged collection implementation which completely manages the interaction between the Flex client and the Seam Query component.
It provides the following features :
- it supports any Flex component correctly managing ItemPendingError exceptions (DataGrid and List do)
- the client caches at most 2 pages of data, that allows to manage any amount of remote data without filling the Flash player memory
- it manages automatically the remote sorting of data. There is absolutely nothing to do manually, the selected Sort on the client is automatically propagated to the order property of the Seam component.
- it manages automatically the remote filtering of data. When used in conjunction with the Tide client context, an example object can be tracked for changes and be sent to the Seam query to be used as restrictions for the query.

A simple example is probably more clear :

Seam components.xml :

<component name="examplePerson" class="test.granite.ejb3.entity.Person">

<framework:entity-query name="people"
ejbql="select p from Person p"
max-results="36">
<framework:restrictions>
<value>lower(p.lastName) like lower( #{examplePerson.lastName} || '%' )</value>
</framework:restrictions>
</framework:entity-query>

This gives us a very classic Seam Query component, the only important thing being the max-results property, which will serve as a the page size for the client collection. It is absolutely necessary that the page size is greater than the maximum number of elements expected to be displayed on the UI component (in general 30-50 is a good fit).

On the Flex side,

import org.granite.tide.seam.framework.PagedQuery;

var seamContext:Context = Seam.getInstance().getSeamContext();

function initColl():void {
Seam.getInstance().addComponent("people", PagedQuery);

people.dataProvider = seamContext.people;
}

<mx:TextInput id="search" text="{seamContext.examplePerson.lastName}"
enter="seamContext.examplePerson.lastName = search.text; seamContext.people.refresh();"/>
<mx:button label="Search" click="seamContext.examplePerson.lastName = search.text; seamContext.people.refresh();">
<mx:datagrid id="people">
<mx:column datafield="firstName" headertext="First Name"/>
<mx:column datafield="lastName" headertext="Last Name"/>
</mx:DataGrid>

This is basically all which is needed to bridge our Seam query component with the Flex UI.
Note that the PagedQuery class actually extends ListCollectionView, and thus can be used whereever a collection can be used in Flex.


Propagation of Seam events :


In this part, we will only show a simple propagation of synchronous events. The asynchronous processing necessitates a little more configuration as Gravity is involved and this will be the subject for the second part of this post.

A new method in the Context object allows the client to register listeners for server events it is interested in.
For example, you can call :
seamContext.addContextEventListener(type:String, listener:Function, remote:Boolean = false);

- type is the type of the Seam event,
- listener is a handler function, which a signature function listener(event:TideContextEvent):void
- remote indicates that the event is expected to come from the remote server

Once registered, the listener function will be called after any remote call during which the interesting event type is raised by a component.

Let's take the Seam booking example :

public class HotelBookingAction implements HotelBooking {

@In private Events events;
...

@End
public void confirm() {
...
events.raiseTransactionSuccessEvent("bookingConfirmed");
}
}

On the Flex side, we could do this :

private function init():void {
...
seamContext.addContextEventListener("bookingConfirmed", bookingConfirmedHandler, true);
...
}

private function confirmBooking():void {
seamContext.hotelBooking.confirm();
}

private function bookingConfirmedHandler(event:TideContextEvent):void {
Alert.show("Booking confirmed");
seamContext.bookingList.refresh();
}

The bookingConfirmedHandler callback should be called when the remote call to hotelBooking.confirm() returns, because we have registered interest in the event, and it has been raised by the Seam component.

Handling of asynchronous events is very similar but needs a little more configuration to integrate with Gravity push.
The integration is made at two levels :
- events raised asynchronously by Seam components of the user context
- events raised by asynchronous method calls from Seam components of the user context

The first thing is to configure a messaging destination named 'seamAsync' in services-config.xml which will handle communication with the server components :

<services-config>

<services>
<service id="granite-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<!--
! Use "tideSeamFactory" and "my-graniteamf" for "seam" destination (see below).
!-->
<destination id="seam">
<channels>
<channel ref="my-graniteamf"/>
</channels>
<properties>
<factory>tideSeamFactory</factory>
</properties>
<security>
<security-constraint>
<auth-method>Custom</auth-method>
<roles>
<role>user</role>
<role>admin</role>
</roles>
</security-constraint>
</security>
</destination>
</service>

<service id="gravity-service"
class="flex.messaging.services.MessagingService"
messageTypes="flex.messaging.messages.AsyncMessage">
<adapters>
<adapter-definition id="seam" class="org.granite.gravity.adapters.SimpleServiceAdapter"/>
</adapters>

<destination id="seamAsync">
<channels>
<channel ref="my-gravityamf"/>
</channels>
<security>
<security-constraint>
<auth-method>Custom</auth-method>
<roles>
<role>user</role>
<role>admin</role>
</roles>
</security-constraint>
</security>
<adapter ref="seam"/>
</destination>
</service>
</services>

<!--
! Declare Tide+Seam service factory.
!-->
<factories>
<factory id="tideSeamFactory" class="org.granite.tide.seam.SeamServiceFactory"/>
</factories>

<!--
! Declare granite channels.
!-->
<channels>
<channel-definition id="my-graniteamf" class="mx.messaging.channels.AMFChannel">
<endpoint
uri="http://{server.name}:{server.port}/{context.root}/graniteamf/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>

<channel-definition id="my-gravityamf" class="org.granite.gravity.channels.GravityChannel">
<endpoint
uri="http://{server.name}:{server.port}/{context.root}/gravity/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>

</services-config>


Second, we need to startup the messaging client at the beginning of the application, for example in a static initializer block of our main mxml :

{
Seam.getInstance().addPlugin(TideAsync.getInstance("seamAsync"));
}

That's all.


Now we are able to listen to events raised asynchronously with Events.instance().raiseAsynchronousEvent() or raiseTimedEvent(), or to events raised from an asynchronous method call.

The client part is exactly the same as for synchronous events :

tideContext.addContextEventListener("notification", notificationHandler, true);

For security reasons, only events initiated by a component in the current user session context can be received. This cannot be used for now to communicate between different users.

Possible uses of this feature could be :
- notify the user of incoming events (new mail, new chat message, ...)
- notify the user periodically of the progress of a long process running on the server

This is really powerful and makes the use of the Seam asynchronicity framework almost transparent for the Flex client.
The client code is exactly the same, so you can make any method call asynchronous or not depending on the needs of the application.


You can try and see most of these things working on the example projects (graniteds_seam and graniteds_seam_booking). You can also go to the GDS forum for any help or comments.

A similar integration for Spring is in progress and may be included in a future release (maybe 1.2).

mardi 8 avril 2008

Quick presentation of the GraniteDS Tide project

We are in the process of releasing the GraniteDS Tide subproject as part of GraniteDS 1.1.

This new subproject is aimed at improving the data services part of GraniteDS and simplify the Flex client programming model when integrating with server side frameworks.

In a first step Tide will be focused on a strong integration with Seam and Hibernate, built on the existing GraniteDS/Seam integration, to extend the Seam programming model to the Flex client and make the use of remote Seam components very easy.

The main goal of Tide is to remove all the useless and redundant declarations and integration code both on Flex side and on server side, for example the dozens of destinations for RemoteObjects in service-config.xml and mxmls, and the necessary service adapters on the server.

Tide is heavily based on the concept of a client context, which proxies all communications between the client and the server. This client context provides an entity cache and a component container, similar to the server PersistenceContext and Seam context.

HelloWorld with Tide

Seam component :

@Stateless
@Name("helloAction")
public class HelloAction implements HelloLocal {
public String sayHello(String name) {
return "Hello, " + name;
}
}


Flex code :

public function init():void {
// The main piece : getting the client context
var tideContext:Context = Seam.getInstance().getSeamContext();
// Triggers the remote call of the 'helloAction' component
tideContext.helloAction.sayHello("Jimi", resultHandler);
}

private function resultHandler(event:TideResultEvent):void {
// Should output 'Hello, Jimi'...
trace(event.result);
}


This is very similar to the JavaScript Seam remoting way of calling server components. The Context object proxies all calls on its managed components and transmits them to the server through a single hidden RemoteObject. That means that just one destination has to be declared in services-config.xml.
A faultHandler can optionally be specified for handling errors.


Using existing Seam components

Let's go one step further with an extract of the Seam contactlist example :

Seam components :

<fwk:entity-query name="contacts" results="5">
<fwk:ejbql>from Contact</fwk:ejbql>
<fwk:order>lastName</fwk:order>
<fwk:restrictions>
<value>lower(firstName) like lower(concat(#{exampleContact.firstName}, '%'))</value>
<value>lower(lastName) like lower(concat(#{exampleContact.lastName}, '%'))</value>
</fwk:restrictions>
</fwk:entity-query>

<component name="exampleContact" class="org.jboss.seam.example.contactlist.Contact"/>

Flex code :

public function init():void {
var tideContext:Context = Seam.getInstance().getSeamContext();
tideContext.exampleContact.firstName = '';
tideContext.exampleContact.lastName = 'hendrix';
// Triggers the remote call of the 'contacts' component.
tideContext.contacts.getResultList(resultHandler);
}

private function resultHandler(event:TideResultEvent):void {
var list:ArrayCollection = ArrayCollection(event.result);
}


Here the main point is that the exampleContact properties have been sent to the server along with the remote call of getResultList. As the Context is an ActionScript proxy, it is able to detect all assignments on objects attached to it and to propagate them when needed.

Another kind of use is also possible and makes binding of server objects in mxml very easy :

MXML code :

<mx:textinput id="inputFirstName"/>
<mx:textinput id="inputLastName"/>
<mx:button label="Go"
click="tideContext.exampleContact.firstName = inputFirstName.text;
tideContext.examplePerson.lastName = inputLastName.text;
tideContext.contacts.refresh();"/>

<mx:datagrid id="contacts" dataprovider="{tideContext.contacts.resultList}">
...
</mx:datagrid>


The resultList collection will be updated each time the refresh() method is called on the remote component. Interestingly, the collection instance itself is not replaced, instead data received from the server are merged with the existing data, and even the instances of Contact are kept and merged when possible, allowing the DataGrid to correctly keep its selectedItem (this would not be the case if the object instances were overwritten).


Integration with Seam bijection

Still better, Tide integrates with the Seam component bijection interceptor and all outjected objects and datamodels are propagated from the server to the client context.
Here is an example from Seam booking :

Seam component :

@Stateful
@Name("hotelSearch")
@Scope(ScopeType.SESSION)
@Restrict("#{identity.loggedIn}")
public class HotelSearchingAction implements HotelSearching {

@PersistenceContext private EntityManager em;

private String searchString;
...

@DataModel private List hotels;

public void find() {
page = 0;
queryHotels();
}

public void nextPage() {
page++;
queryHotels();
}
...

public String getSearchString() {
return searchString;
}

public void setSearchString(String searchString) {
this.searchString = searchString;
}
...
}

MXML code :

<mx:textinput id="inputSearchString"/>
<mx:button label="Search"
click="tideContext.hotelSearch.searchString = inputSearchString.text;
tideContext.hotelSearch.find();"/>

<mx:datagrid id="hotels" dataprovider="{tideContext.hotels}">
...
</mx:datagrid>



This 3 relatively simple examples are significantly less verbose and easier to read than the classic way with RemoteObjects.


Advanced features

But Tide does not stop here and comes with some more advanced features which allow a more complete integration with the server side :

Propagation of context messages from the server

All Seam context messages are serialized back to the client and available in the client context after each remote call.

Flex code :

public function login(username:String, password:String):void {
tideContext.identity.username = username;
tideContext.identity.password = password;
tideContext.identity.login(loginHandler);
}

private function loginHandler(event:TideResultEvent):void {
var message:FacesMessage = tideContext.messages.getItemAt(0);
}


Integration with Seam security, in particular the identity component

The Tide client identity component takes care of both the RemoteObject credentials and the server Seam security, allowing a clean login/logout functionality.


Support for client conversations with possible transparent synchronization with a server conversation.
A new separate context object is created for each new server conversation. All remote calls made from this new context are then considered to be in the same server conversation.

Seam component :

@Stateful
@Name("hotelBooking")
@Restrict("#{identity.loggedIn}")
public class HotelBookingAction implements HotelBooking {
...
@Begin
public void selectHotel(Hotel selectedHotel) {
hotel = em.merge(selectedHotel);
}
...
}

Flex code :

private function selectHotel(hotel:Hotel):void {
tideContext.hotelBooking.selectHotel(hotel, selectHotelHandler);
}

private function selectHotelHandler(event:TideResultEvent):void {
// Get a new client context allowing interaction with the server conversation
var conversationContext:Context = event.context as Context;
}


Integration with server side validation (Hibernate Validator)

A TideValidator component listening for server validation errors can be attached to any Flex control and trigger the display of the error message.

MXML code :

<mx:textinput id="inputEmail" text="{tideContext.contactHome.instance.email}"/>

<tide:tidevalidator entity="{tideContext.contactHome.instance}"
property="email" listener="{inputEmail}"/>


Conclusion

The project is still alpha and can only be found in the nightly builds or built from the subversion trunk for the moment, but we expect to get a preview version in the forthcoming GraniteDS 1.1 RC and a stable version as part of the final release of GraniteDS 1.1.

Two sample projects are available :
- The graniteds_seam_booking project, using most features of Tide.
- The graniteds_seam simple address book.

We hope that it will greatly simplify the development for people currently working with both Flex and Seam.

Don't hesitate to try it and give some feedback.