3. Seam Services

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-2.0.0.GA.zip and import examples/graniteds_seam as a new Eclipse project. Please note that this sample project is a quick port of the examples/graniteds_ejb3 and does not show any advanced conversation/task support for now.

Flex Classes & 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 will not 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>

   <amf3-message-interceptor 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 cannot use standard Java EE 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.

As shown below, the service, factory and channel sections are still required in your services-config.xml file, but the service part is shortened by removing all destination 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"));

Comments

Anonymous says:

The <a href="http://lowest-rate-loans.com/topics/business-loans">business loans</a> suppose to be important for people, which would like to organize their own career. By the way, it is easy to receive a financial loan.


Browse Space

- Pages
- Blog
- Labels
- Attachments
- Bookmarks
- Mail
- Advanced

Explore Confluence

- Popular Labels
- Notation Guide

Your Account

Log In

Other Features

Add Content


Copyright © 2011 Granite Data Services S.A.S. All Rights Reserved.