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.
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:
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}; ...
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>
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> <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.
In order to initialize Seam, you must also customize your web.xml as follows:
<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>
It is possible to instruct GraniteDS to automatically search for Seam destinations in the classpath by:
<granite-config scan="true"> </granite-config>
@Name("personService") @RemoteDestination(id="person", source="personService", securityRoles={"user","admin"}) public class PersonServiceBean implements PersonService { ... }
The annotation supports the following attributes:
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 |
Explore Confluence |
Your Account |
Add Content |
|
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.6.0 Build:#913 Sep 27, 2007) |
|
|
|