Flamingo has 4 client Flex components designed for native integration with Seam and Spring: Validator, CallSet, Binding and SeamRemoteObject, and 3 client JavaFX components: Validator, ServiceFactory and SeamServiceFactory. Three of Flex components are implemented to be used either with AMF or Hessian protocol and thus, have the following versions:
Validator: EntityValidator and HessianEntityValidator
CallSet: CallSet and HessianCallSet
Binding: BindingService and HessianBindingService
SeamRemoteObject supports Seam conversations in Flex applications and has only one version that can be used only for AMF at the moment.
JavaFX components are implemented to be used with the Hessian protocol only:
Validator: EntityValidator
ServiceFactory
SeamServiceFactory
Table 5.1.
| Flex | JBoss Seam | Spring |
|---|---|---|
| Validator | yes | yes |
| CallSet | yes | yes |
| Binding | yes | yes |
| SeamRemoteObject | yes | n/a |
| JavaFX | ||
| EntityValidator | yes | yes |
| CallSet | planned | planned |
| Binding | yes | planned |
| ServiceFactory | yes | yes |
| SeamServiceFactory | yes | n/a |
See more about each component in the appropriate section.
In this chapter 4 client Flex components are described.
This component allows validating user input against Hibernate Validator annotations on the server. It is used in Flex applications which use Seam or Spring server configuration. There are 2 choices of the component, one for each of two protocols: EntityValidator for AMF and HessianEntityValidator for Hessian. The functionality is very similar to the <s:validate> Seam tag (see Seam Reference).
This component uses the AMF protocol. It replaces the former SeamValidator starting from deprecated version 1.0.2.
Here the properties and methods used by EntityValidator are described.
EntityValidator, used for the AMF protocol, contains 2 distinctive properties and a set of typical Flex validator properties:
Table 5.2.
| Element | Required | Description |
|---|---|---|
| id | No | The id of the component. It is specified only if creating the component in the .mxml file |
| destination | Yes | Flamingo distinctive property. This can be: a) full qualified class name of entity that contains a method annotated b) name of entity specified in the @Entity annotation, or simple class name if entity name is omitted c) name of the Seam component if specified for entity. In the example provided in the Sample Code section, valid values are person, Person and com.mycompany.myproject.PersonBean. For AMF, you need to add this destination to the "services-config.xml" file |
| validationTarget | Yes | Flamingo distinctive property. This is a property name of the Seam component or entity class you want to validate |
| source | Yes | Specifies the Flex client object containing the property to validate. |
| property | Yes | A String specifying the name of the property of the source object that contains the value to validate |
| required | No | If true, specifies that a missing or empty value causes a validation error. If false, no validation server call will be executed for the empty value. The default value of the parameter is false |
EntityValidator has only one method which is inherited from a standard Flex Validator component: "validate". This method executes a call to the server and returns a validation error message if there is any.
Seam or Spring component named com.exadel.flamingo.service.validator.entityValidator is used on the server side to manage validation processing. See Java documentation for class com.exadel.flamingo.service.validator.EntityValidatorImpl for more information.
To have Validator working for the Spring application add the following line into your Spring context file:
<context:component-scan base-package="com.exadel.flamingo.service"/>
See a sample below:
To see validation in action you need to add a Person.java file on the server with the following content:
package com.mycompany.myproject;
import org.hibernate.validator.Length;
import org.jboss.seam.annotations.Name;
import javax.persistence.Entity;
@Name("person")
@Entity(name="Person")
public class PersonBean {
private String lastName;
@Length(min=3, max=40)
public String getLastName() {
return lastName;
}
}Use this EntityValidator code sample in your .mxml file:
<flamingo:EntityValidator id="validator"
destination="person"
source="{valueId}"
validationTarget="lastName"
property="text" />
<mx:Form>
<mx:TextInput id="valueId" />
<mx:Button label="Validate" click="validator.validate()" />
</mx:Form>In this example when the "Validate" button is clicked, the validation request is sent to the server where text entered into the valueId field will be validated for the Hibenate Validator @Length annotation correspondence (and any other Validator annotation presented at lastName).
If the text entered does not meet the requirements, the error message will be displayed for the field. Please note that this request is asynchronous and you can create validator for each of, e.g., 10 fields of your form that will automatically start triggering at the focusOut event and show error messages independently.
Add destination person to the "services-config.xml" file as destination as if it is used for the RemoteObject component. See example in the AMF for Flex/Seam section of Chapter 3: Getting Started with Flamingo.
HessianEntityValidator has the same properties and methods as EntityValidator. It replaces the former SeamValidator starting from deprecated version 1.0.2. See the code sample for this component below.
An example of validation using the HessianEntityValidator component can be performed the same way as with the help of EntityValidator. Just use this code sample for your .mxml file:
<flamingo:HessianEntityValidator id="validator"
destination="seam/resource/hessian/person"
validationTarget="lastName"
source="{test}"
property="text" />
<mx:Form>
<mx:TextInput id="test" />
<mx:Button label="Validate" click="validator.validate()" />
</mx:Form>See a real example how to use the Validator component in the "validation" sample project in Flamingo bundle.
This component allows bundling of a set of operations which are propagated to the server. It is used in Flex applications with JBoss Seam and Spring server configuration.
This component uses the AMF protocol.
Here the properties, events and methods used by CallSet are described.
CallSet used for the AMF protocol contains the following properties:
Table 5.3.
| Property | Required | Description |
|---|---|---|
| id | No | The id of the component. It is specified only if creating the component in the .mxml file |
| destination | Yes | This is a destination specified in the "services-config.xml" file simply to identify channel to use and consequently servlet url mapping. Destination name itself is not relevant |
Each CallSet, in its turn, includes a number of Call components that have their own properties:
Table 5.4.
| Property | Required | Description |
|---|---|---|
| component | Yes | The Seam or Spring server component name the method of which will be called |
| method | Yes | The name of the method to be called |
| arguments | Yes | Parameters to pass to the method. If these parameters are constant, they can be specified when declaring the Call object. If parameters vary they can be specified with the send method call. Please note that each argument should be an array (see the sample code below: CallSet Code Sample) |
The CallSet component includes the following events:
Table 5.5.
| Event | Description |
|---|---|
| result | The result event is dispatched when a service call successfully returns. Returned value of each method invoked on the server is stored in ResultEvent passed to the result handler |
| fault | The fault event is dispatched when a service call fails. Handler for this event will never be called for HessianCallSet (see Known Issues for Hessian 2 in the "Supported Protocols" section) |
The CallSet component has the following methods:
Table 5.6.
| Method | Description |
|---|---|
| addCall(Call) | Adds a Call to the end of the Calls list of the CallSet |
| addCallAt(Number, Call) | Adds a Call to the specified position in the Call list of the CallSet |
| removeCallAt(Number) | Removes Call from the specified position from the Call list in the CallSet |
| send(...args) | Invokes server call for all Call methods specified in CallSet. Parameter is an array of arguments for each Call. The number of arguments should be equal to the number of Calls in the CallSet. If arguments are set during the CallSet object declaration, call send() without parameters in order to use declared arguments. If arguments are set and specified for the send call, the values in send take precedence |
Seam or Spring component named com.exadel.flamingo.service.callset.callSetManager is used on the server side to manage CallSet processing. See Java documentation for this class for more information.
To have CallSet working for the Spring application add the following line into your Spring context file:
<context:component-scan base-package="com.exadel.flamingo.service"/>
Use this CallSet code sample in your .mxml file:
<mx:Script>
<![CDATA[
private function loginResultHandler(event:ResultEvent):void
{
var results:Array = event.result as Array;
if (results[3])
{
Alert.show('Successfully logged in');
} else {
Alert.show('Login failure');
}
}
]]>
</mx:Script>
<flamingo:CallSet id="loginCallSet"
result="loginTestResultHandler(event)"
destination="callSet">
<flamingo:Call component="identity" method="setUsername"/>
<flamingo:Call component="identity" method="setPassword"/>
<flamingo:Call component="identity" method="login"/>
<flamingo:Call component="identity" method="isLoggedIn"/>
</flamingo:CallSet>
<mx:Button id="loginBtn" label="Login" click="loginCallSet.send(["flamingo"],["secret"],[],[])"/>This sample shows the way the CallSet component is used to bundle 4 server method calls in one server request to authenticate a user via the identity Seam component.
Add callSet destination to the "services-config.xml" file:
<services-config>
<services>
<service
id="binding-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="callSet"/>
<default-channels>
<channel ref="seam-amf"/>
</default-channels>
</service>
</services>
<channels>
<channel-definition id="seam-amf" class="mx.messaging.channels.AMFChannel">
<endpoint
uri="http://{server.name}:{server.port}/myapp/seam/resource/amf/"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
</services-config>Please note that the actual name of the identity Seam component mentioned is org.jboss.seam.security.identity. This works because Flamingo automatically processes EL expressions transferred from the client side.
Flamingo supports execution of the whole CallSet inside of one transaction for a project with EJB support. In order to do that, add the following string into the “components.xml” file:
<component name="com.exadel.flamingo.service.callset.callSetManager" class="com.exadel.flamingo.flex.callset.EJBCallSetManager"/>
See a real example how to use the CallSet component in the "callSet" sample project in Flamingo bundle.
HessianCallSet has the same properties, events and methods as CallSet. See the code sample for this component below.
<flamingo:HessianCallSet id="loginCallSet"
destination="seam/resource/hessian/"
result="loginTestResultHandler(event)">
<flamingo:SeamHessianCall component="identity" method="setUsername"/>
<flamingo:SeamHessianCall component="identity" method="setPassword"/>
<flamingo:SeamHessianCall component="identity" method="login"/>
<flamingo:SeamHessianCall component="identity" method="isLoggedIn"/>
</flamingo:HessianCallSet>
This component allows synchronization between JBoss Seam or Spring server objects and Flex client objects. There are 2 choices of the component, one for each of two protocols: BindingService for AMF and HessianBindingService for Hessian.
This component uses the AMF protocol.
If you use BindingService to bind an object that is an entity (has the javax.persistence.Entity annotation) there is a possiblity for you in Flamingo to automatically merge the content of the object into the database when committing it to the server.
For Seam, you need to have the managed persistence context (JPA) correctly configured and have option "flamingoConfig.bindingManagerPersistsEntity true" specified in the "seam.properties" file.
For Spring, you need to have Hibernate SessionFactory correctly configured and file "flamingoConfiguration.properties" with content bindingManager.persistEntities=true defined in classpath.
Add the following string to Spring configuration:
<util:properties id="flamingoConfiguration" location="classpath:flamingoConfiguration.properties"/>
Here the properties, events and methods used by BindingService are described.
BindingService used for the AMF protocol contains the following properties:
Table 5.7.
| Property | Required | Description |
|---|---|---|
| id | No | The id of the component. It is specified only if creating the component in the .mxml file |
| destination | Yes | The name of the Seam or Spring component you want to bind to on the server. For AMF, you need to add this destination to the "services-config.xml" file. For Hessian, a complete URL to the component including servlet path should be specified |
| source | Yes | The Flex client object you want to bind to the server object |
Seam or Spring component named com.exadel.flamingo.flex.binding.bindingManager is used on the server side to manage binding processing. See Java documentation for this class for more information.
To have Binding working for the Spring application add the following line into your Spring context file:
<context:component-scan base-package="com.exadel.flamingo.service"/>
Add the following Seam component:
package com.mycompany.myproject.seam;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
@Name("personBean")
@Scope(ScopeType.SESSION)
public PersonBean{
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}Add the following content for binding on Flex:
package com.mycompany.myproject.flex.vo
{
[RemoteClass(alias="com.mycompany.myproject.seam.PersonBean")]
[Bindable]
public class PersonVO
{
private var _firstName:String;
private var _lastName:String;
public function get firstName():String
{
return _firstName;
}
public function set firstName(value:String):void
{
_firstName = value;
}
public function get lastName():String
{
return _lastName;
}
public function set lastName(value:String):void
{
_lastName = value;
}
}
}Add the following mxml code:
<mx:Application creationComplete="init()">
<mx:Script>
<![CDATA[
import com.mycompany.myproject.flex.vo.PersonVO;
import mx.controls.TextInput;
[Bindable]
private var user:PersonVO;
private function init():void
{
user = new PersonVO();
user.firstName = "John";
user.lastName = "Smith";
}
]]>
</mx:Script>
<flamingo:BindingService id="personBinding"
destination="personBean"
source="{user}" />
<mx:TextInput text="{user.firstName}"/>
<mx:TextInput text="{user.lastName}"/>
<mx:Button label="Send data to server" click="personBinding.commit()"/>
<mx:Button label="Get data from server" click="personBinding.update()"/>
</mx:Application/>Add destination personBean to the "services-config.xml" file as destination as if it is used for the RemoteObject component. See example in the AMF for Flex/Seam section of Chapter 3: Getting Started with Flamingo.
File "commons-beanutils.jar" is needed to perform binding on the server, please make sure it is in classpath.
Binding synchronizes object with any level of hierarchy of nested objects/collections. In case if collection is sent from the server to the client using Hessian, the content of this collection will be deserialized into objects of the Object class, i.e. the original object class will not be restored (see Known Issues in the Supported Protocols section related to binding: "mx.collections.ArrayCollection", "Deserialization to ActionScript Classes").
Object structure on client side defines a level of hierarchy binding will be performed with.
In order to take the most advantage from binding, use [RemoteClass] metadata for AMF and hessianTypeName class variable for Hessian (see an example below). Otherwise objects coming from the client side to the server will be deserialized into HashMap and collections will be filled with HashMap objects if generics for collections are not used on the server.
Currently no "stale data" events are generated during the commit/update operations; objects are not merged but completely overwritten.
Flamingo supports binding inside of one transaction for a project with EJB support. In order to do that, add the following string into the "components.xml" file:
<component name="com.exadel.flamingo.flex.binding.bindingManager" class="com.exadel.flamingo.flex.binding.EJBBindingManager"/>
Flamingo allows to sync data from/to Seam components named using annotations @Name, @Out, @Factory, @DataModel and others with two exceptions: a) binding to @DataModel and @Factory is read only, b) binding to <mx:Model> is currently supported from the server to the client side only; i.e. the "commit" operation cannot be performed in both cases.
See a real example how to use the Binding component in the "binding" sample project in Flamingo bundle.
HessianBindingService has the same properties, events and methods as BindingService. See the code sample for this component below.
This component supports Seam conversations in Flex applications. SeamRemoteObject extends a standard RemoteObject, thus it can be used similarly. It is unlikely that more than one conversation will be used in any Flex application, so all objects of the RemoteObject class will share the same conversation ID. In order to have an ability to work with several conversations use the following methods of the SeamRemote object: SeamRemoteObject.getConversationId() and SeamRemoteObject.setConversationId().
Here is an example of usage of several SeamRemoteObject components in the context of one conversation:
Add files "ConversationStarter.java" and "ConversationStopper.java" on the server:
"ConversationStarter.java":
@Name("conversationStarter")
public class ConversationStarter {
@Begin
public void start() {
}
}"ConversationStopper.java":
@Name("conversationStopper")
public class ConversationStopper {
@End()
public void stop() {
}
}Use this code sample in your .mxml file:
<flamingo:SeamRemoteObject id="starter" destination="conversationStarter"/>
<flamingo:SeamRemoteObject id="stopper" destination="conversationStopper"/>
<mx:Form>
<mx:FormItem>
<mx:Button label="Start conversation" click="starter.start();" />
<mx:Button label="Stop conversation" click="stopper.stop();" />
</mx:FormItem>
</mx:Form>
Then specify conversationStarter and conversationStopper destination in the "services-config. xml" file.
When clicking on the "Start" button the conversation starts on the server, when "Stop" - the conversation is stopped. You can check this by clicking on the "Start" button twice: you will get an error message that the conversation is running already.
Here the events and methods used by SeamRemoteObject are described.
The SeamRemoteObject component includes the following events:
Table 5.10.
| Event | Description |
|---|---|
| result | The result event is dispatched when a service call successfully returns |
| fault | The fault event is dispatched when a service call fails |
In this chapter 3 client JavaFX components are described.
This component allows validating user input against Hibernate Validator annotations on the server. It is used in JavaFX applications which use Seam or Spring server configuration. The component is designed for the Hessian protocol only and is called: HessianEntityValidator.
This component uses the Hessian protocol.
Here the properties and methods used by HessianEntityValidator are described.
HessianEntityValidator has the following properties:
Table 5.12.
| Element | Required | Description |
|---|---|---|
| destination | Yes | This can be: a) full qualified class name of entity that contains a method annotated b) name of entity specified in the @Entity annotation, or simple class name if entity name is omitted c) name of the Seam component if specified for entity. In the example provided in the Sample Code section, valid values are person, Person and com.mycompany.myproject.PersonBean. For AMF, you need to add this destination to the "services-config.xml" file |
| source | Yes | Specifies the JavaFX client component containing the property to validate. This component should be derived from javax.swing.text.JTextComponent |
| property | Yes | A String specifying the name of the property of the source object that contains the value to validate |
| required | No | If true, specifies that a missing or empty value causes a validation error. If false, no validation server call will be executed for the empty value. The default value of the parameter is false |
| returnedMessage | No | Contains text in which the validation error is returned if there is any |
JavaFX HessianEntityValidator has the following methods:
Table 5.13.
| Method | Description |
|---|---|
| doValidation(String) | It executes validation call to the server taking into consideration class properties destination and property. The String type is the only value validated. A validation error message is returned if there is any |
| validate() | This method validates text in the visual component specified in the source property |
Seam or Spring component named com.exadel.flamingo.service.validator.entityValidator is used on the server side to manage validation processing. See Java documentation for class com.exadel.flamingo.service.validator.EntityValidatorImpl for more information.
To have Validator working for the Spring application add the following line into your Spring context file:
<context:component-scan base-package="com.exadel.flamingo.service"/>
See a sample below:
package com.exadel.flamingo.javafx;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.TextOrigin;
import javafx.ext.swing.SwingButton;
import javafx.scene.layout.VBox;
import javafx.scene.control.TextBox;
import com.exadel.flamingo.javafx.components;
var validator = HessianEntityValidator {
destination: "person"
property: "lastName"
}
var textField: TextBox = TextBox {
text: "test"
columns: 7
selectOnFocus:true
}
var sampleLabel = Text{
y: 8
font: Font { name:"sansserif", size: 12 }
fill: Color.BLACK
content: bind validator.returnedMessage
textOrigin: TextOrigin.TOP
}
var validateButton = SwingButton {
text: "Validate"
action: function(){
validator.validate();
}
}
Stage {
width: 300
height: 200
title: "Validation Sample"
scene: Scene {
content: VBox {
translateX: 5
translateY: 5
spacing: 10
content: [
HBox {
content: sampleLabel
spacing: 10
},
HBox {
content: textField
spacing: 10
},
HBox {
content: validateButton
spacing: 10
}]
}
}
}
In this example when the "Validate" button is clicked, the validation request is sent to the server where text entered into the textField field will be validated for the Hibenate Validator @Length annotation correspondence (and any other Validator annotation presented at lastName).
If there is any validation error message it will be displayed in the SimpleLabel.
See the server code sample in 5.1.1.1.3: Code Sample
This component allows synchronization between JBoss Seam server objects and JavaFX client objects. The component is designed for the Hessian protocol only and is called HessianBindingService.
HessianBindingService for JavaFX has the same properties, events and methods as BindingService and HessianBindingService for Flex. Please refer to the description of Binding provided for Flex and to the code sample provided for HessianBindingService.
Flamingo JavaFX Client Components includes class com.exadel.flamingo.javafx.ServiceFactory that helps easily create proxy objects on the client side. Use class SeamServiceFactory to create proxy objects supporting Seam conversations.
Table 5.14.
| Method | Description |
|---|---|
| setUrl(String_url) | Sets the base URL to access the server |
| getService(Class clazz, String componentName) | With the help of this method a proxy object is created for Seam component with the componentName name. clazz is a local interface of the Seam server component |
See samples how to use ServiceFactory in the JavaFX Hotel Booking demo.
The .jar file with Exadel Flamingo JavaFX Client Components includes a class that supports Seam conversations: com.exadel.flamingo.javafx.seam.SeamServiceFactory. This class is intended to create client proxy object that automatically supports conversations when performing a server call.
SeamServiceFactory has the following static methods:
Table 5.15.
| Method | Description |
|---|---|
| setUrl(String_url) | Sets the base URL to access the server |
| getService(Class clazz, String componentName) | With the help of this method a proxy object is created for Seam component with the componentName name that automatically supports conversations when executing remote calls. clazz is a local interface of the Seam server component |
Add files "ConversationStarter.java" and "ConversationStopper.java"on the server:
"ConversationStarter.java":
@Name("conversationStarter")
public class ConversationStarter {
@Begin
public void start() {
}
}
"ConversationStopper.java":
@Name("conversationStopper")
public class ConversationStopper {
@End()
public void stop() {
}
}
This is an example of the application that works with conversations:
package com.exadel.flamingo.javafx;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.ext.swing.SwingButton;
import javafx.scene.layout.VBox;
import com.exadel.flamingo.javafx.seam.SeamServiceFactory;
SeamServiceFactory.setUrl("http://localhost:8080/helloworld/seam/resource/hessian");
var buttonStart = SwingButton {
text: "Start conversation"
action: function(){
SeamServiceFactory.getService(ConversationStarter.class,
"conversationStarter").start();
}
}
var buttonStop = SwingButton {
text: "Stop conversation"
action: function(){
SeamServiceFactory.getService(ConversationStopper.class,
"conversationStopper").stop();
}
}
Stage {
width: 300
height: 200
title: "Validation Sample"
scene: Scene {
content: VBox {
translateX: 5
translateY: 5
spacing: 10
content: [
HBox {
content: buttonStart
spacing: 10
},
HBox {
content: buttonStop
spacing: 10
}]
}
}
}
When clicking on the "Start" button the conversation starts on the server, when "Stop" - the conversation is stopped. You can check this by clicking on the "Start" button twice: you will get an error message that the conversation is running already.
You can find examples how to use all components for AMF and Hessian in the "Hotel Booking" Seam demo developed with Flamingo: http://demo.flamingo.exadel.com/. You can compare Flamingo version with the original one and see how amazingly fast Flamingo demo works!