Help

Controls

PermLinkWikiLink
Switch Workspace

Built with Seam

You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.

Forum: Seam Users Forum ListTopic List
16. Oct 2008, 17:53 America/New_York | Link

Hi all,

We have just released Granite Data Services 1.1.0, a LGPL alternative to Adobe LiveCycle Data Services, which includes the first stable release of the Tide integration package for Seam.

Tide aims at providing to the Flex client a transparent integration with server Seam components, with a client programming model similar to Seam remoting in JavaScript. After an initial setup, it requires close to no configuration during development and makes developing Flex applications very natural for people used to Seam/JSF/facelets.

Tide integrates with most features of Seam : component bijection, events, conversations, security with Identity component. For example, a Tide Flex client component can get injected with values that have been outjected by a server component, or can register as a listener for Seam events raised by server components (even asynchronously thanks to the integration with the GraniteDS Gravity push library).

Finally Tide provides advanced data management features. It allows to use Seam Query components as paged data providers for Flex UI components (DataGrids, Lists...) and can transparently initialize lazy collections. This GDS release includes Granite Eclipse builder, an Eclipse plugin which can automatically generate the ActionScript entity classes from the Java JPA/EJB3 model.

You can download two sample projects : - a port of Seam booking to Flex (without any modification on the original Seam components) - a simple Address Book, demonstrating simple CRUD functionality with data paging and lazy loading of collections (using only basic Seam Home and Query components)

Here is a small example from the hotel booking project showing the use of context injection in Flex.

Seam component :

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

 @PersistenceContext
 private EntityManager em;

 private String searchString;
 private int pageSize = 10;
 ...
 @DataModel
 private List<Hotel> hotels;

 public void find() {
    page = 0;
    queryHotels();
 }
 ...
 private void queryHotels() {
    hotels = em.createQuery("select h from Hotel h where lower(h.name) like #{pattern} or lower(h.city) like #{pattern} or lower(h.zip) like #{pattern} or lower(h.address) like #{pattern}")
          .setMaxResults(pageSize)
          .setFirstResult( page * pageSize )
          .getResultList();
 }

 public List<Hotel> getHotels() {
     return this.hotels;
 }

 public int getPageSize() {
    return pageSize;
 }

 public void setPageSize(int pageSize) {
    this.pageSize = pageSize;
 }

 @Factory(value="pattern", scope=ScopeType.EVENT)
 public String getSearchPattern() {
    return searchString==null ? "%" : '%' + searchString.toLowerCase().replace('*', '%') + '%';
 }

 public String getSearchString() {
    return searchString;
 }

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

Flex/Tide component :

[Bindable]
[Name("hotelsCtl", restrict="true")]
public class HotelsCtl {

  // The [In] annotation indicates that this variable will be injected with a proxy of the Seam component named 'hotelSearch'.
  [In]
  public var hotelSearch:Object;

  // The [Observer] annotation indicates that this method is an event handler. It will listen for events raised by other components or by the UI.
  [Observer("searchForHotels")]
  public function searchForHotels(searchString:String, pageSize:Number):void {
      // Set the variables to inject in the hotelSearch component
      hotelSearch.searchString = searchString;
      hotelSearch.pageSize = pageSize;
      // Remote call of the 'find' method of the 'hotelSearch' Seam component
      hotelSearch.find();
  }
}

Flex/Tide UI :

<mx:Application initialize="tideContext.mainAppUI = this;">
...
<mx:Script>
  <![CDATA[
      // Initialize the Tide context
      [Bindable]
      private var tideContext:Context = Seam.getInstance().getSeamContext();
      
      // Register our client component
      Seam.getInstance().addComponents([HotelsCtl]);


      [Bindable]
      public var pageSizes:ArrayCollection = new ArrayCollection([5, 10, 20]);

      // The [In] annotation indicates that this 'hotels' variable will be injected with the Seam component/context variable named 'hotels' whenever a Seam component outjects it
      [Bindable] [In]
      public var hotels:ArrayCollection;
  ]]>
</mx:Script>
...
<mx:HBox direction="horizontal" paddingBottom="5" paddingLeft="0" paddingRight="0" paddingTop="5" width="100%">
  <mx:TextInput id="txtQueryString" width="200" color="#C0C0C0" />
  <mx:ComboBox id="cmbResultSize" width="58" x="0" y="0" upSkin="myCombobox" downSkin="myComboboxDown" overSkin="myComboboxOver" disabledSkin="myComboboxDisabled" dataProvider="{pageSizes}"/>
  <mx:Spacer width="5"/>
  <!-- Raises an event which will trigger our Observer client component -->
  <mx:Button label="Search" x="0" y="0" 
      click="dispatchEvent(new TideUIEvent('searchForHotels', txtQueryString.text, Number(cmbResultSize.selectedLabel)));" 
      upSkin="myButton" downSkin="myButtonDown" overSkin="myButtonOver" disabledSkin="myButtonDisabled"/>
</mx:HBox>
...
<mx:VBox height="360" width="100%" styleName="boxBordersSubbgSkin">
  <mx:Box backgroundColor="#e2e5d5" borderColor="#c0c0c0" styleName="tabssub" width="100%">
      <mx:DataGrid id="hotelSearchResults" rowCount="6" width="100%" dataProvider="{hotels}">
          <mx:columns>
              <mx:DataGridColumn itemRenderer="components.ImageRender" width="25"  />
              <mx:DataGridColumn dataField="name" width="175"  />
              <mx:DataGridColumn dataField="address" width="175"  />
              <mx:DataGridColumn dataField="city" width="100"  />
              <mx:DataGridColumn dataField="state" width="75" />
              <mx:DataGridColumn dataField="zip" width="50"  />
          </mx:columns>
      </mx:DataGrid>
  </mx:Box>
</mx:VBox>
...
</mx:Application>

You can get more information at http://www.graniteds.org.

19 Replies:
20. Oct 2008, 23:05 America/New_York | Link

I tried to run the examples but ran into several problems. I couldn't get any of them run in eclipse. Switching to the commandline, I made the booking app run by correcting the import.sql file and manually deploying the datasource. The other app ran, but it gave a number of errors like the following:

javax.servlet.ServletException: Not in a valid Comet configuration (use an APR or NIO connector)
        at org.granite.gravity.tomcat.AbstractCometProcessor.service(AbstractCometProcessor.java:192)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182)
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
        at java.lang.Thread.run(Thread.java:613)
16:04:08,016 ERROR [AMFMessageFilter] AMF message error
java.lang.RuntimeException: Could not read externalizable object: []
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:379)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:389)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Array(AMF3Deserializer.java:253)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:116)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:389)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at org.granite.messaging.amf.io.AMF0Deserializer.readAMF3Data(AMF0Deserializer.java:324)
        at org.granite.messaging.amf.io.AMF0Deserializer.readData(AMF0Deserializer.java:376)
        at org.granite.messaging.amf.io.AMF0Deserializer.readArray(AMF0Deserializer.java:239)
        at org.granite.messaging.amf.io.AMF0Deserializer.readData(AMF0Deserializer.java:362)
        at org.granite.messaging.amf.io.AMF0Deserializer.readBodies(AMF0Deserializer.java:155)
        at org.granite.messaging.amf.io.AMF0Deserializer.<init>(AMF0Deserializer.java:94)
        at org.granite.messaging.webapp.AMFMessageFilter.doFilter(AMFMessageFilter.java:80)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182)
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
        at java.lang.Thread.run(Thread.java:613)
Caused by: java.lang.RuntimeException: Could not read externalized object: test.granite.ejb3.entity.Person@650d29e0
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:359)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:389)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Array(AMF3Deserializer.java:253)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:116)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at flex.messaging.io.ArrayCollection.readExternal(ArrayCollection.java:64)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:375)
        ... 34 more
Caused by: java.lang.RuntimeException: Could not create instance of: test.granite.ejb3.entity.Person$Salutation
        at org.granite.messaging.amf.io.util.DefaultActionScriptClassDescriptor.newJavaInstance(DefaultActionScriptClassDescriptor.java:83)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:345)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at org.granite.hibernate.HibernateExternalizer.readExternal(HibernateExternalizer.java:107)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:355)
        ... 43 more
Caused by: java.lang.InstantiationException: test.granite.ejb3.entity.Person$Salutation
        at java.lang.Class.newInstance0(Class.java:335)
        at java.lang.Class.newInstance(Class.java:303)
        at org.granite.util.ClassUtil.newInstance(ClassUtil.java:47)
        at org.granite.messaging.amf.io.util.DefaultActionScriptClassDescriptor.newJavaInstance(DefaultActionScriptClassDescriptor.java:81)
        ... 48 more
16:04:08,018 ERROR [[AMFMessageServlet]] Servlet.service() for servlet AMFMessageServlet threw exception
java.lang.InstantiationException: test.granite.ejb3.entity.Person$Salutation
        at java.lang.Class.newInstance0(Class.java:335)
        at java.lang.Class.newInstance(Class.java:303)
        at org.granite.util.ClassUtil.newInstance(ClassUtil.java:47)
        at org.granite.messaging.amf.io.util.DefaultActionScriptClassDescriptor.newJavaInstance(DefaultActionScriptClassDescriptor.java:81)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:345)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at org.granite.hibernate.HibernateExternalizer.readExternal(HibernateExternalizer.java:107)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:355)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:389)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Array(AMF3Deserializer.java:253)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:116)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at flex.messaging.io.ArrayCollection.readExternal(ArrayCollection.java:64)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:375)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:389)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Array(AMF3Deserializer.java:253)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:116)
        at org.granite.messaging.amf.io.AMF3Deserializer.readAMF3Object(AMF3Deserializer.java:389)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:118)
        at org.granite.messaging.amf.io.AMF3Deserializer.readObject(AMF3Deserializer.java:87)
        at org.granite.messaging.amf.io.AMF0Deserializer.readAMF3Data(AMF0Deserializer.java:324)
        at org.granite.messaging.amf.io.AMF0Deserializer.readData(AMF0Deserializer.java:376)
        at org.granite.messaging.amf.io.AMF0Deserializer.readArray(AMF0Deserializer.java:239)
        at org.granite.messaging.amf.io.AMF0Deserializer.readData(AMF0Deserializer.java:362)
        at org.granite.messaging.amf.io.AMF0Deserializer.readBodies(AMF0Deserializer.java:155)
        at org.granite.messaging.amf.io.AMF0Deserializer.<init>(AMF0Deserializer.java:94)
        at org.granite.messaging.webapp.AMFMessageFilter.doFilter(AMFMessageFilter.java:80)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182)
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
        at java.lang.Thread.run(Thread.java:613)
21. Oct 2008, 00:32 America/New_York | Link

Aie, I should have added more information for installing the sample projects :

For both projects, there is an ant build file which needs some settings in env.properties :

FLEX_HOME should be set to the Flex SDK home :

For a Flex Builder 3 setup, this is in general something like this :

    FLEX_HOME=C:/Program Files/Adobe/Flex Builder 3 Plug-in/sdks/3.0.0
    FLEX_TASKS_JAR=${FLEX_HOME}/ant/lib/flexTasks.jar

Otherwise :

    FLEX_HOME=C:/flex_sdk_3
    FLEX_TASKS_JAR=${FLEX_HOME}/ant/lib/flexTasks.jar

JBOSS_HOME should be set to your jboss home directory

For seam-booking, just run the 'deploy' target of the ant build file, it will deploy the ear, datasource and import.sql.

For the address book, there are a few more things needed :

The APR or NIO connector is used for handling asynchronous servlets and should be enabled for Tomcat (6.0.14 minimum). Just put the Tomcat native dll from here in C:\windows\system32 or in jboss/bin. Other better configurations are possible : tomcat docs are here.

The security configuration of this project uses JAAS, so you might add defaultUsers.properties and defaultRoles.properties in jboss/server/default/conf.

defaultUsers.properties:

admin=admin
user=user

defaultRoles.properties :

admin=admin
user=user

Hope this helps.

21. Oct 2008, 02:23 America/New_York | Link

You should add the NIO information to the README. Everything else was covered there.

On the booking example, the build.xml file is looking for the import.sql file in the classes directory, but it is in the ejb3 directory. (the build.xml also seems to be looking for the ds.xml in the wrong directory too) Maybe there is supposed to a target that copies these files there?

On the address book example, I discovered that the error I posted above comes only when I select a select a Salutation. When I don't, the app appears to work to some degree. Would not having the NIO connector installed be likely to cause the rest of the app to behave strangely? I'm not seeing any other exceptions generated beyond the first one.

21. Oct 2008, 16:25 America/New_York | Link

This is very strange. I've rebuilt the addressbook sample from scratch from the provided url and it works fine with a jboss 4.2.3 instance. Even with APR/NIO not installed, the parts which do not depend on it (almost everything) do work correctly. The issue with Person$Salutation is likely to happen if there is no META-INF/granite-config.properties in granite-tide.jar, which was the case in some recent nightly builds.

The build file for the booking sample will be fixed in the next snapshots. It was indeed broken when not executed inside eclipse.

Thanks for taking the time of trying it.

19. Nov 2008, 08:17 America/New_York | Link

I'm a total Flex neophyte so I know very little but what you've got showing there looks pretty darn cool. It has total wow factor.

Thanks for posting this, definitely something interesting to check out. :)

 

Beware of programmers carrying screwdrivers

11. Dec 2008, 22:53 America/New_York | Link

This should be what jboss bundles with Seam, not jsf/RichFaces. I dont want to be unkind but richfaces is so far from anything you would want to call production worthy that i am amazed jboss put their name to it.

12. Dec 2008, 18:16 America/New_York | Link

Thanks for these encouraging comments !

I'll just add a quick news to announce GraniteDS 1.2.0 RC1 with full support for Seam 2.1 (there were API changes that were incompatible with GDS 1.1).

18. Jan 2009, 21:27 America/New_York | Link

Has anyone done a GraniteDS / Flamingo comparison?

13. Feb 2009, 15:56 America/New_York | Link

Can the updated example using GraniteDS and Seam 2.1 (or latest) be posted and/or made available for download? I'm new to Seam/GraniteDS so I doubt I can make the changes manually.

07. Apr 2009, 16:19 America/New_York | Link

Hi all,

GraniteDS 2.0 beta 2 has just been released and is available for download here.

It brings a lot of bug fixes and improvements and Seam 2.1 is now the recommended version when integrating with Flex.

The two GraniteDS/Seam example projects have been completely rewritten and demonstrate most functionalities of the integration.

  • The address book example now shows the integration with the new Seam 2.1 authorization model: edit and delete buttons are displayed depending on the roles and access rights of the logged in user for each contact. It also demonstrates the new data push functionality of GDS 2.0: changes made on a Flex client are displayed in near real-time on other logged in Flex clients.
  • The Seam booking example has now the exact same look and functionality than the original JSF example, including conversations and workspace management. Note that the server side code is exactly identical as then original example and if you have a look at the Flex code, you will also see that it's very similar to the original JSF code. Many other GDS features are shown like use of status messages to display error messages on a particular control on the Flex client, remote validation with Hibernate validator and security integration.

These examples can be deployed in a JBoss 4.2.2/4.2.3 instance (please read examples/README.txt for instructions, in particular Tomcat APR/NIO configuration).

William

11. Apr 2009, 02:26 America/New_York | Link

Do you have any idea about the time frame for GraniteDS 2.0 GA? If I want to run Seam & GraniteDS on Glassfish, do I need special instructions?

Regards.

13. Apr 2009, 12:00 America/New_York | Link

There will be at least one RC before the final release, so you can expect a final 2.0 in about 1 or 2 months.

We have not finished the documentation about GraniteDS / Seam on GlassFish, but if you have a working setup of your Seam app on GlassFish, you've done the most difficult part. There is no special configuration for GraniteDS on GF, except choosing between granite-hibernate.jar, granite-toplink.jar and granite-eclipselink.jar depending on the JPA implementation you plan to use.

13. May 2009, 12:25 America/New_York | Link

Hi,

why does Seam not support Flex directly?

http://seamframework.org/Community/DirectSeamSupportForFlex

Michael

13. May 2009, 14:04 America/New_York | Link

Hi William,

How would you compare GraniteDS with Flamingo? Knowing that I'm using Flamingo right now, why would I switch to GraniteDS?

Thanks,

14. May 2009, 00:10 America/New_York | Link

I'm not sure I can do a really fair comparison, but at least I can give a list of GraniteDS features that I think Flamingo does not have. I guess the Flamingo developers will correct me if I say something wrong :)

  • Simple remoting to Seam components hiding the use of Flex RemoteObject (and removing the need to constantly mess with services-config.xml) with a use very similar to the Seam remoting JavaScript API.
  • Synchronization of server-side context variables with a client-side context, integrated with Seam bijection. Context variables can then be used in Flex to bind to UI components. This is roughly equivalent but easier to use than the Flamingo binding service.
  • Flex paged collection component that integrate with the Seam Query component and can be bound to any Flex UI component (DataGrid for example).
  • Flex validators that integrate with server-side validation, either data based (Hibernate Validator) or control-based with status messages. I think Flamingo also have a validator that integrates with HV.
  • Full integration with Seam security with a Flex Identity component mirroring server-side methods: login/logout, hasRole, hasPermission. Flamingo provides good support for Seam security but it is even easier with GDS: for example a Flex component can be masked with
    <mx:Button ... visible="{identity.hasRole('admin')}"/>
  • Full integration with Seam events: Flex components can observe events raised by Seam components, either after a remote call or by server push.

Other features are not particularly tied to Seam but greatly simplify building Flex applications with a Seam/Spring backend :

  • Flexible AMF serialization supporting detached and lazy loaded JPA entities (last time I checked Flamingo AMF serialization was based on an early GraniteDS version and all advanded serialization features had been removed).
  • Support for server push, with good scalability when using comet support with Tomcat/JBossWeb, Jetty continuations or GlassFish V3 Grizzly connector.
  • Eclipse plugin and ant task to generate AS3 classes from a JPA data model.
  • Seam-like client application framework that simplifies building Flex applications and fully integrates with Seam on the server.

Most of these features are demonstrated in the seam-flexbooking and graniteds-tide-seam examples in the latest GDS 2.0 beta 2 distribution here.

To be honest there are also Flamingo features that GraniteDS does not provide (or not completely) :

  • The CRUD application generator that can build an initial project from a data model. We may provide later a modified seam-gen that generates a Flex application but it's not in our short-term plans.
  • It seems that Maven support is better in Flamingo. GraniteDS support for Maven is minimal but sufficient for most users (the jar and swc libraries are in a java.net repository).
  • Dynamic persistent methods in Flex. This is surely very handy, but it does not respect the base design principle of GraniteDS that the client should not directly control persistence (to ensure that services semantics and security are correctly enforced). And none of our users has ever requested this.
  • CallSets. However, GDS automatically bundles operations for the most useful cases, for example the Flamingo example with identity would be written with GDS as follows :
    identity.username = "Barack"; 
    identity.password = "Obama";
    identity.loggedIn;   // Calling the getter before the remote call indicates GDS that it should get the value after the call
    identity.login(loginResult);
    
    private function loginResult(event:TideResultEvent):void {
       if (identity.loggedIn) // The property has been correcly retrieved from the server
         ...
    }
  • The documentation is maybe better. GraniteDS documentation is still lacking in some parts but we try to improve it at each release.

At the end, I think the best way to have a more precise idea is to compare the implementations of the Seam booking example in Flex with GraniteDS and Flamingo. You can easily check that there is a lot less Flex code and configuration with GDS.

Regards,

William

21. May 2009, 16:13 America/New_York | Link

What's the advantage of Granite over Exadel's Flamingo? Any differences?

21. May 2009, 16:16 America/New_York | Link

Found some answers: http://seamframework.org/Community/FlamingoBringsFlexToYourSeamApp

12. Jun 2009, 15:40 America/New_York | Link

Hello,

see my tutorial for integrating Seam and Flex with FlamingoDS here.

Regards Michael

23. Jun 2009, 19:42 America/New_York | Link

Hi all,

GraniteDS 2.0.0.GA has just been released and is available for download here.

There are once again a lot of bug fixes and improvements in the Flex/Seam integration. The best way to get started is to have a look to the Flex port of the Seam hotel booking example that is available in the examples folder.

Regards,

William