graniteds.orgCommunity Documentation
The Spring framework is one of the most popular Java enterprise frameworks. It integrates on a common platform all the necessary services for building enterprise applications: persistence, transactions, security...
GraniteDS provides out-of-the-box integration with Spring 2.5+ and 3.0+ via either the RemoteObject API or the Tide API
to remotely call Spring services, and fully supports serialization of JPA entities from and to your Flex application, taking care of lazily loaded associations.
The support for JPA entity beans is covered in the section JPA and lazy initialization, so this section will only
describe how to call Spring beans from a Flex application. GraniteDS also fully supports Acegi Security / Spring Security 2.x / Spring Security 3.x.
The support for Spring is included in the library granite-spring.jar, so you always have to include this library in either
WEB-INF/lib or lib for an ear packaging.
Note that to provide a more native experience for Spring developers, the Spring support in GraniteDS can be configured directly in the Spring configuration
files (applicationContext.xml). Most features of GraniteDS can be configured this way, and it is still possible to fall back to the
default GraniteDS configuration files services-config.xml and granite-config.xml for unsupported features.
For a basic example with GraniteDS and Spring working together,
have a look to the graniteds_spring example project in the examples folder of the GraniteDS distribution
graniteds-***.zip and import it as a new Eclipse project.
It is perfectly possible to use the default setup for GraniteDS servlet in web.xml, but the recommended way when using Spring
is to configure a Spring MVC dispatcher servlet and handle incoming AMF requests. This will in particular allow configuring GraniteDS in the Spring
application context. You also need to setup the Spring request and application listeners but this is standard Spring configuration.
Note that this works only for the remoting servlet, but you still have to configure the Gravity servlet in the default way
because the Spring MVC dispatcher servlets cannot support non blocking I/O.
<!-- Path to Spring config file -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/conf/application-context.xml
</param-value>
</context-param>
<!-- Spring application listener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring listener for web-scopes (request, session) -->
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<!-- Spring MVC dispatcher servlet for AMF remoting requests -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/graniteamf/*</url-pattern>
</servlet-mapping>
You also have to add an empty file WEB-INF/dispatcher-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd>
</beans>
The Flex-side usage of the RemoteObject API is completely independent of the server technology, so everything described in
the Remoting chapter applies for Spring beans. This section will only describe the particular configuration
required in various use cases of Spring services.
All remoting examples from the Remoting chapter apply for Spring beans, here is a basic example with an annotated Spring service:
public interface HelloService {
public String hello(String name);
}
@Service("helloService")
@RemoteDestination(id="helloService", source="helloService")
public class HelloServiceImpl implement HelloService {
public String hello(String name) {
return "Hello " + name;
}
}
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.controls.Alert;
public function resultHandler(event:ResultEvent):void {
// Display received message
outputMessage.text = event.result as String;
}
public function faultHandler(event:FaultEvent):void {
// Show error alert
Alert.show(event.fault.faultString);
}
</mx:Script>
<!-- Connect to a service destination.-->
<mx:RemoteObject id="helloService"
destination="helloService"
source="helloService"
result="handleResult(event);"
fault="handleFault(event);"/>
<!-- Provide input data for calling the service. -->
<mx:TextInput id="inputName"/>
<!-- Call the Spring service, use the text in a TextInput control as input data.-->
<mx:Button click="helloService.hello(inputName.text)"/>
<!-- Display results data in the user interface. -->
<mx:Label id="outputMessage"/>
</mx:Application>
The main thing to note is the use of the source property in both the RemoteObject definition
and in the @RemoteDestination annotation that should match the name of the Spring bean (here in @Service).
Besides configuring the dispatcher servlet (see here), configuring GraniteDS in the Spring context
just requires adding the graniteds namespace and adding a flex-filter element:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:graniteds="http://www.graniteds.org/config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.graniteds.org/config http://www.graniteds.org/public/dtd/2.3.0/granite-config-2.3.xsd">
...
<graniteds:flex-filter url-pattern="/*"/>
</beans>
The actual url that will be listened to by the AMF processor is the combination of the url-pattern in the Spring context
and the servlet-mapping of the dispatcher servlet in web.xml.
The configuration described here maps GraniteDS on /graniteamf/* and is suitable in almost all cases.
When necessary, this configuration can be overriden or completed by the default configuration in services-config.xml described
in the next section.
In this case, the implicit configuration created by the MVC setup contains the following elements :
granite-servicespring-factorygraniteamf
The MVC setup automatically enables component scanning, so you can just annotate your Spring services with @RemoteDestination
and put an empty META-INF/services-config.properties file in your services jar or folder to tell GraniteDS where to look for services.
See last paragraph Automatic Configuration of Destinations.
Alternatively you can also declare the remote destinations manually in the Spring context:
<graniteds:remote-destination id="personService" source="personService"/>
You can also specify a secure destination by adding the list of roles required to access the destination:
<graniteds:remote-destination id="personService" source="personService">
<graniteds:roles>
<graniteds:role>ROLE_ADMIN</graniteds:role>
</graniteds:roles>
</graniteds:remote-destination>
The support for Spring Security is automatically enabled and the version of Spring Security is automatically detected.
However if you have configured many AuthenticationManagers, it will be necessary to instruct GraniteDS which one should be used
for authentication by adding the following line to your Spring configuration :
<graniteds:security-service authentication-manager="myAuthenticationManager"/>
With this declaration you can also provide various configuration elements for the Spring 3 security service implementation :
<graniteds:security-service
authentication-manager="myAuthenticationManager"
allow-anonymous-access="true"
authentication-trust-resolver="com.myapp.MyAuthenticationTrustResolver"
session-authentication-strategy="com.myapp.MySessionAuthenticationStrategy"
security-context-repository="com.myapp.MySecurityContextRepository"
security-interceptor="com.myapp.MySecurityInterceptor"
password-encoder="com.myapp.MyPasswordEncoder"
/>
Finally remember that as there is no services-config.xml, you will have to manually initialize the endpoints
for your client RemoteObjects (also see here) :
srv.destination = "personService";
srv.source = "personService";
srv.channelSet = new ChannelSet();
srv.channelSet.addChannel(new AMFChannel("graniteamf",
"http://{server.name}:{server.port}/{context.root}/graniteamf/amf"));
Configuring remoting for Spring services simply requires using the org.granite.spring.SpringServiceFactory service factory in
services-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service
id="granite-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="testBean">
<channels>
<channel ref="graniteamf"/>
</channels>
<properties>
<factory>springFactory</factory>
<source>springBean</source>
</properties>
<security>
<security-constraint>
<auth-method>Custom</auth-method>
<roles>
<role>ROLE_USER</role>
<role>ROLE_ADMIN</role>
</roles>
</security-constraint>
</security>
</destination>
</service>
</services>
<factories>
<factory id="springFactory" class="org.granite.spring.SpringServiceFactory" />
</factories>
<channels>
<channel-definition id="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>
The only thing that should be noted for Spring destinations is that you have to specify a source property specifying the name
of the remote Spring bean.
It is possible to instruct GraniteDS to automatically search for Spring destinations in the classpath by:
granite-config.xml (scanning is always enabled with a MVC setup).
<granite-config scan="true"/>
META-INF/services-config.properties marker file in all jars containing Spring services
org.granite.messaging.service.annotations.RemoteDestination
@RemoteDestination(id="personService", source="personService", securityRoles={"user","admin"})
public interface PersonService {
}
@Service("personService")
public class PersonServiceBean implements PersonService {
...
}
The annotation supports the following attributes:
id is mandatory and is the name of the destination as used from Flex
source is mandatory and should be the name of the Spring bean
service is optional when 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.
Using scanning allows to simplify your services-config.xml file, however it is recommended to use the MVC setup, so you don't even need one !
When not using the Spring MVC setup, you have to manually configure the integration of Spring Security in granite-config.xml.
Depending on the version of Spring Security you are using, you can use one of the 3 available security services:
Spring Security 3.x
<granite-config>
...
<!--
! Use Spring based security service.
!-->
<security type="org.granite.spring.security.SpringSecurity3Service"/>
</granite-config>
Spring Security 2.x
<granite-config>
...
<!--
! Use Spring based security service.
!-->
<security type="org.granite.messaging.service.security.SpringSecurityService"/>
</granite-config>
Acegi Security
<granite-config>
...
<!--
! Use Spring based security service.
!-->
<security type="org.granite.messaging.service.security.AcegiSecurityService"/>
</granite-config>
You may then secure your Flex destinations as shown earlier. Please refer to Acegi or Spring Security documentation for specific configuration details.
Note however that there are two main ways of securing the GraniteDS AMF endpoint:
Most of what is described in the Tide Remoting section applies for Spring, however GraniteDS also provides an improved integration with Spring services.
This is by far the easiest way to use Tide with Spring, it just consists in declaring the GraniteDS flex filter in the Spring context:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:graniteds="http://www.graniteds.org/config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.graniteds.org/config http://www.graniteds.org/public/dtd/2.3.0/granite-config-2.3.xsd">
...
<graniteds:flex-filter url-pattern="/*" tide="true"/>
</beans>
The flex-filter declaration will setup an AMF processor for the specified url pattern, and the tide attribute
specifies that you want a Tide-enabled service factory. Note that the actual url that will be listened to by GraniteDS is the combination of this
url-pattern with the servlet-mapping defined in web.xml for the dispatcher servlet.
Other configurations can be done with flex-filter:
tide-annotations is equivalent to tide-component annotated-with="" in granite-config.xml.
It allows to define the list of annotation names that enable remote access to Spring beans. @RemoteDestination is always
declared by default, but you can use any other one if you don't want a compilation dependency on the GraniteDS libraries.
tide-roles allows to define a list of security roles that are required to access the Tide remote destination.
In general it is not necessary to define this destination-wide security and only rely on Spring security for fine-grained access to individual beans.
security-service allows to specify the security service implementation.
exception-converters allows to define a list of server-side exception converters.
It's the equivalent to exception-converters in granite-config.xml.
amf3-message-interceptor allows to define a message interceptor.
You have to define the bean name of an existing bean implementing AMFMessageInterceptor.
Additional elements can also be configured in the Spring beans file:
tide-identity allows to declare the identity bean.
When using Spring Security ACL you can define here the necessary attributes acl-service, sid-retrieval-strategy
and object-identity-retrieval-strategy.
tide-persistence allows to declare the persistence implementation for your application.
It is not necessary when you have only one Spring transactionManager, otherwise just specify the name of
the transaction manager to use. Tide/Spring will automatically determine the kind of transaction management it should use (JTA, JPA or Hibernate API).
Note that in addition to these manual elements, any Spring bean implementing one of the GraniteDS interfaces SecurityService,
ExceptionConverter, AMFMessageInterceptor or TidePersistenceManager will be automatically
picked up and registered in the GraniteDS configuration.
If you don't use the MVC setup, you will have to use the standard GraniteDS configuration files instead of the Spring context, and setup these elements manually. You can safely skip this section if you choose the MVC setup.
tide-annotations section of granite-config.xml the conditions
used to enable remote access to Spring destinations (for example all beans annotated with a particular annotation).
org.granite.tide.spring.SpringServiceFactory service factory
in services-config.xml.
spring in services-config.xmlSpring.getInstance().getSpringContext()
instead of Tide.getInstance().getContext().
Here is a default configuration suitable for most cases:
<granite-config scan="true">
...
<tide-components>
<tide-component annotated-with="org.granite.messaging.service.annotations.RemoteDestination"/>
</tide-components>
</granite-config>
<services-config>
<services>
<service id="granite-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<!--
! Use "tideSpringFactory" and "my-graniteamf" for "ejb" destination (see below).
! The destination must be "spring" when using Tide with default configuration.
!-->
<destination id="spring">
<channels>
<channel ref="my-graniteamf"/>
</channels>
<properties>
<factory>tideSpringFactory</factory>
</properties>
</destination>
</service>
</services>
<!--
! Declare tideSpringFactory service factory.
!-->
<factories>
<factory id="tideSpringFactory" class="org.granite.tide.spring.SpringServiceFactory"/>
</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>
The destination named spring will be the one and only destination required for all Spring destinations.
You should also define the correct Spring security service in granite-config.xml, see here
for details.
You can use the property entity-manager-factory-bean-name to specify an EntityManagerFactory bean
that will be used for transparent remote lazy loading of collections.
Here is an example with a Spring JPA/Hibernate configuration:
<persistence-unit name="spring-pu">
...
</persistence-unit>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:mem:springds</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="spring-pu" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
If you use a plain Hibernate session instead of JPA, you cannot use entity-manager-factory-bean-name, you have to configure
a specific Tide persistence manager in the Spring context (assuming the bean name of the Hibernate session factory is
sessionFactory):
<!-- All this AOP stuff is to ensure the Tide persistence manager will be transactional -->
<aop:config>
<aop:pointcut id="tidePersistenceManagerMethods"
expression="execution(* org.granite.tide.ITidePersistenceManager.*(..))"/>
<aop:advisor advice-ref="tidePersistenceManagerMethodsTxAdvice"
pointcut-ref="tidePersistenceManagerMethods"/>
</aop:config>
<tx:advice id="tidePersistenceManagerMethodsTxAdvice"
transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<bean id="tidePersistenceManager"
class="org.granite.tide.hibernate.HibernateSessionManager" scope="request">
<constructor-arg>
<ref bean="sessionFactory"/>
</constructor-arg>
</bean>
When using Spring, the only difference on the client is that you have to use the Spring singleton. Here is a simple example of
remoting with an injected client proxy for an Spring service:
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="Spring.getInstance().initApplication()">
<mx:Script>
import org.granite.tide.spring.Spring;
import org.granite.tide.events.TideResultEvent;
import org.granite.tide.events.TideFaultEvent;
[In]
public var helloService:Component;
private function hello(name:String):void {
helloService.hello(name, resultHandler, faultHandler);
}
private function resultHandler(event:TideResultEvent):void {
outputMessage.text = event.result as String;
}
private function faultHandler(event:TideFaultEvent):void {
// Handle fault
}
</mx:Script>
<!-- Provide input data for calling the service. -->
<mx:TextInput id="inputName"/>
<!-- Call the web service, use the text in a TextInput control as input data.-->
<mx:Button click="hello(inputName.text)"/>
<!-- Result message. -->
<mx:Label id="outputMessage"/>
</mx:Application>
This is almost identical to the standard Tide API described in the Tide remoting section, and all other methods apply for Spring.
You can benefit from the capability of the Gas3 code generator (see here) to generate a strongly typed
ActionScript 3 client proxy from the Spring interface when it is annotated with @RemoteDestination.
In this case, you can inject a typesafe reference to your service and get better compile time error checking and auto completion in your IDE:
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="Spring.getInstance().initApplication()">
<mx:Script>
import org.granite.tide.spring.Spring;
import org.granite.tide.events.TideResultEvent;
import org.granite.tide.events.TideFaultEvent;
import com.myapp.service.HelloService;
[In]
public var helloService:HelloService;
private function hello(name:String):void {
helloService.hello(name, resultHandler, faultHandler);
}
...
</mx:Script>
...
</mx:Application>
It is possible to benefit from even more type safety by using the annotation [Inject] instead of In.
When using this annotation, the full class name is used to find the target bean in the Spring context instead of the bean name.
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="Spring.getInstance().initApplication()">
<mx:Script>
import org.granite.tide.spring.Spring;
import org.granite.tide.events.TideResultEvent;
import org.granite.tide.events.TideFaultEvent;
import com.myapp.service.HelloService;
[Inject]
public var myService:HelloService;
private function hello(name:String):void {
myService.hello(name, resultHandler, faultHandler);
}
...
</mx:Script>
...
</mx:Application>
GraniteDS provides a client-side component named identity that ensures the integration between the client RemoteObject
credentials and the server-side container security. It additionally includes an easy-to-use API to define runtime authorization checks on the Flex UI.
Enabling support for the client identity component requires to configure the corresponding server-side component in the Spring context:
<graniteds:tide-identity/>
If you want to integrate with Spring Security ACL authorizations, you will have to specify the name of the ACL service and optionally the Object ID retrieval strategy and SID retrieval strategy (see details on Spring Security ACL here):
<graniteds:tide-identity acl-service="myAclService"
object-identity-retrieval-strategy="myObjectIdentityRetrievalStrategory"
sid-retrieval-strategy="mySIDRetrievalStrategy"/>
The Flex identity component for Spring (of class org.granite.tide.spring.Identity) predictably provides two methods
login() and logout() that can be used as any Tide remote call:
private var tideContext:Context = Spring.getInstance().getSpringContext();
public function login(username:String, password:String):void {
tideContext.identity.login(username, password, loginResult, loginFault);
}
private function loginResult(event:TideResultEvent):void {
Alert.show(event.context.identity.loggedIn);
}
private function loginFault(event:TideFaultEvent):void {
Alert.show(event.fault);
}
public function logout():void {
tideContext.identity.logout();
}
Or with dependency injection:
[Inject]
public var identity:Identity;
public function login(username:String, password:String):void {
identity.login(username, password, loginResult, loginFault);
}
private function loginResult(event:TideResultEvent):void {
Alert.show(event.context.identity.loggedIn);
}
private function loginFault(event:TideFaultEvent):void {
Alert.show(event.fault);
}
public function logout():void {
identity.logout();
}
The identity component also exposes the bindable property loggedIn that represents the current authentication state.
As it is bindable, it can be used to choose between different views, for example to switch between a login form and the application view with a Flex
ViewStack component:
<mx:ViewStack id="main" selectedIndex="{identity.loggedIn ? 1 : 0}">
<views:LoginView id="loginView"/>
<views:MainView id="mainView"/>
</mx:ViewStack>
Finally the identity component is integrated with server-side role-based security and can be used to get information or show/hide UI
depending on the user access rights. It provides methods similar to the Spring Security jsp tags sec:ifAllGranted,
sec:ifAnyGranted, sec:ifNotGranted and sec:hasPermission.
<mx:Button id="deleteCategoryButton"
label="Delete Category"
enabled="{identity.ifAllGranted('ROLE_ADMIN')}"
click="productService.deleteCategory(category)"/>
<mx:Button id="deleteProductButton" label="Delete Product"
enabled="{productGrid.selectedItem}"
visible="{identity.hasPermission(productGrid.selectedItem, '8,16')}"
click="productService.deleteProduct(productGrid.selectedItem)"/>
With these declaration, the button labeled Delete Category will be enabled only if the user has the role ROLE_ADMIN
and the button Delete Product only if the user has the ACL permissions DELETE (code 8) or ADMINISTER (code 16) for the selected product.
Another possibility is to completely hide the button with the properties visible and includeInLayout, or any other
property relevant for the display of the UI component.
The three methods are:
ifAllGranted/ifAnyGranted: the user should have the specified role
ifNotGranted: the user should not have the specified role
hasPermission: the user should have the specified permission for the specified entity
This can also be used as any remote class with result and fault handlers:
public function checkRole(role:String):void {
identity.ifAllGranted(role, checkRoleResult, checkRoleFault);
}
private function checkRoleResult(event:TideResultEvent, role:String):void {
if (role == 'ROLE_ADMIN') {
if (event.result)
trace("User has admin role");
else
trace("User does not have admin role");
}
}
You can notice that the result and fault handlers have a second argument so you can use the same handler for many access check calls.
identity.ifAllGranted() will issue a remote call when it is called the first time, thus its return value cannot be used reliably
to determine if the use has the required role. It will always return false until the remote call result is received.
It is important to note that identity caches the user access rights so only the first call to ifAllGranted()
will be remote. If the user rights are changed on the server, or if you want to enforce security more than once per user session, you can clear
the security cache manually with identity.clearSecurityCache(), for example periodically with a Timer.
It is possible to configure the three kinds of Gravity topics directly in the Spring context instead of services-config.xml:
Simple Topic:
<graniteds:messaging-destination id="myTopic"/>
This declaration supports the properties no-local and session-selector (see the
Messaging Configuration section).
You can also define a secure destination by specifying a list of roles required to access the topic:
<graniteds:messaging-destination id="myTopic">
<graniteds:roles>
<graniteds:role>ROLE_ADMIN</graniteds:role>
</graniteds:roles>
<graniteds:messaging-destination/>
JMS Topic:
<graniteds:jms-messaging-destination id="myTopic"
connection-factory="ConnectionFactory"
destination-jndi-name="topic/MyTopic"
transacted-sessions="true"
acknowledge-mode="AUTO_ACKNOWLEDGE"/>
This declaration supports all properties of the default JMS declaration in services-config.xml except for non local initial context
environments (see the JMS Integration section).
ActiveMQ Topic:
<graniteds:activemq-messaging-destination id="myTopic"
connection-factory="ConnectionFactory"
destination-jndi-name="topic/MyTopic"
transacted-sessions="true"
acknowledge-mode="AUTO_ACKNOWLEDGE"
broker-url="vm://localhost"
create-broker="true"
wait-for-start="true"
durable="true"
file-store-root="/opt/activemq/data"/>
This declaration supports all properties of the default ActiveMQ declaration in services-config.xml except for non local initial context
environments (see the ActiveMQ Integration section).
Finally note that the Gravity singleton that is needed to push messages from the server (see here)
is available as a bean in the Spring context and can be autowired by type with @Inject or @Autowired :
@Inject
private Gravity gravity;