Dashboard > Documentation > ... > 5. Integration with Server Frameworks > 3. Seam Services

View Info

3. Seam Services

 Documentation Summary
 Page Summary

Introduction

Granite Data Services lets your Flex application connect to JBoss Seam services with full conversation and task (jBPM) support.

It also brings support for Identity security.

For a basic sample with Granite DS/Seam/Identity/EJB 3 entity beans working together, download graniteds-seam-1.2.0.zip and import it as a new Eclipse project. Please note that this sample project is a quick port of the graniteds-ejb3-1.2.0.zip and does not show any advanced conversation/task support for now.

Flex Classes and Sample Usage

To connect to your Seam services and maintain a conversation or task id, you need to use a specific GDS RemoteObject org.granite.seam.SeamRemoteObject and compile your MXML/AS sources with the granite-seam.swc library.

Here is an overview of the SeamRemoteObject class:

SeamRemoteObject.as
public dynamic class SeamRemoteObject extends SecureRemoteObject {
    ...
    public function get conversation():Conversation {...}
    public function set conversation(conversation:Conversation):void {...}

    public function get task():Task {...}
    public function set task(task:Task):void {...}
    ...
}

Basically, Conversation and Task only encapsulate an id. Since SeamRemoteObject extends SecureRemoteObject, you may use all security features as explained here.

You must finally use a specific SeamOperation in conjunction with SeamRemoteObject, otherwise your conversation/task id won't be serialized:

...
import org.granite.seam.SeamRemoteObject;
import org.granite.seam.SeamOperation;
...
srv = new SeamRemoteObject("mydestination");
var operation:SeamOperation = new SeamOperation();
operation.name = "myMethod";
operation.addEventListener(ResultEvent.RESULT, onMyMethodResult);
srv.operations = {myMethod: operation};
...

Seam Services Configuration

To use Seam services in your Flex application, you must configure a seam specific service factory and refer to it in your destinations:

<services-config>

    <services>
        <service id="granite-service"
            class="flex.messaging.services.RemotingService"
            messageTypes="flex.messaging.messages.RemotingMessage">
            <!--
             ! Use "seamFactory" and "my-graniteamf" for "person" destination (see below).
             !-->
            <destination id="person">
                <channels>
                    <channel ref="my-graniteamf"/>
                </channels>
                <properties>
                    <factory>seamFactory</factory>
                    <source>personService</source>
                </properties>
            </destination>
        </service>
    </services>

    <!--
     ! Declare seamFactory service factory.
     !-->
    <factories>
        <factory id="seamFactory" class="org.granite.seam.SeamServiceFactory" />
    </factories>

    <!--
     ! Declare my-graniteamf channel.
     !-->
    <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>
    </channels>

</services-config>

Identity Security Service Configuration & Usage

Seam comes with a powerful security system named Identity. To enable Identity based security, you must customize your components.xml file by adding the following line (other configurations are of course possible, please refer to Seam documentation):

<security:identity jaas-config-name="other"/>

Then, you must configure a message interceptor which will handle the conversation and task request parameters and tell Granite to use the Seam specific security service:

granite-config.xml
<granite-config>

   <amf3MessageInterceptor type="org.granite.seam.SeamInterceptor"/>

   ...

   <!--
    ! Use Seam based security service.
    !-->
    <security type="org.granite.seam.security.SeamSecurityService"/>

</granite-config>

Finally, you'll be able to use the @Restrict security annotation as shown here:

...
@Stateless
@Name("mySeamService")
@Scope(ScopeType.EVENT)
@Local(PersonService.class)
@Restrict("#{s:hasRole('user') or s:hasRole('admin')}")
public class MySeamServiceBean implements MySeamService {
    ...
    public List<?> findAllThings() {...}

    @Restrict("#{s:hasRole('admin')}")
    public List<?> deleteThing(Thing thing) {...}
    ...
}

While findAllThings method may be used by any authenticated user with the "user" or "admin" role, the deleteThing method is restricted to only users with the "admin" role.

Please note that if you are using this SeamSecurityService, you can't use standard J2EE role based security as described here (@SecurityDomain and @RolesAllowed): Seam Identity does not propagate Principal to session beans, you must only use @Restrict annotations.

General Web Configuration (web.xml)

In order to initialize Seam, you must also customize your web.xml as follows:

web.xml
<web-app version="2.4" ...>
    ...
    <!--
     ! Seam global parameters.
     !-->
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    <context-param>
        <param-name>facelets.DEVELOPMENT</param-name>
        <param-value>true</param-value>
    </context-param>

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

    <!--
     ! AMF & Seam filters (order is important!)
     !-->
    <filter>
        <filter-name>AMFMessageFilter</filter-name>
        <filter-class>org.granite.messaging.webapp.AMFMessageFilter</filter-class>
    </filter>
    <filter>
        <filter-name>Seam Filter</filter-name>
        <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
    </filter>

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

    <!--
     ! Faces & AMF servlets.
     !-->
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <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>Faces Servlet</servlet-name>
        <url-pattern>*.seam</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>AMFMessageServlet</servlet-name>
        <url-pattern>/graniteamf/*</url-pattern>
    </servlet-mapping>
    ...
</web-app>

Automatic Configuration of Destinations

It is possible to instruct GraniteDS to automatically search for Seam destinations in the classpath by:

  • Enabling the automatic scanner :
    <granite-config scan="true">
    </granite-config>
  • Adding a META-INF/services-config.properties file in all jars containing Seam components
  • Annotating the Seam service with org.granite.messaging.service.annotations.RemoteDestination
    @Name("personService")
    @RemoteDestination(id="person", source="personService", securityRoles={"user","admin"})
    public class PersonServiceBean implements PersonService {
      ...
    }

The annotation supports the following attributes:

  • id is mandatory and is the destination name.
  • source is mandatory and should be the name of the Seam component.
  • service is optional if there is only one service for RemotingMessage defined in services-config.xml. Otherwise this should be the name of the service.
  • channel is optional if there is only one channel defined in services-config.xml. Otherwise this should be the id of the target channel.
  • channels may be used instead of channel to define a failover channel.
  • factory is optional if there is only one factory in services-config.xml. Otherwise this should be the factory id.
  • securityRoles is an array of role names for securing the destination.

The configuration of the service, factory, and channel are still needed, but this allows to avoid the tedious destination definitions with simple configurations.

This requires a little more work on the Flex client because of the absence of destination definitions in services-config.
You then have to create your RemoteObjects with one of the following ways:

srv.endpoint = ServerConfig.getChannel("my-graniteamf").endpoint;
srv.destination = "personService";
srv.channelSet = new ChannelSet();
srv.channelSet.addChannel(ServerConfig.getChannel("my-graniteamf"));
srv.destination = "personService";
srv.channelSet = new ChannelSet();
srv.channelSet.addChannel(ServerConfig.getChannel("my-graniteamf"));

Browse Space
- Pages
- Labels
- Attachments
- Mail
- Bookmarks
- News
- Activity
- Advanced

Explore Confluence
- Popular Labels
- Notation Guide

Your Account
Log In

Other Features

View a printable version of the current page.

Add Content
- Add Comment


Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.6.0 Build:#913 Sep 27, 2007)
Bug/feature request - Contact Administrators

SourceForge.net Logo
Copyright © 2007-2008 Adequate Systems. All Rights Reserved.