Scaffolding a Flex application from JPA entities

In the previous recipe, we saw how to set up a project to use Flex and Spring BlazeDS integration. In this recipe, we go a step further and scaffold a complete Flex application that interacts with BlazeDS to perform CRUD operations on the JPA entities.

Getting ready

This recipe is an extension of the previous recipe, Getting started with Flex application development; therefore, perform the steps described in the previous recipe to set up the flightapp_flex project to use the Flex and Spring BlazeDS integration.

Start the Roo shell from the C: oo-cookbookch05-flex directory—the directory in which the flightapp_flex project was created when you went through the Getting started with Flex application development recipe.

How to do it...

To scaffold a flex application, follow the steps given here:

  1. Execute the flex remoting all command, as shown here:
    .. roo> flex remoting all --package ~.flex
    Created SRC_MAIN_JAVAsample
    ooflightappflex
    Created ..FlightDescriptionService.java
    Created ..FlightDescriptionService_Roo_Service.aj
    ..
    Created ROOTsrcmainflexsample
    ooflightappdomain
    Created ..FlightDescription.as
    
    Updated ROOTsrcmainflexflightapp_flex_scaffold.mxml
    Updated ROOTsrcmainflexflightapp_flex_scaffold-config.xml
    
    Created ROOTsrcmainflexsample
    ooflightapppresentation
    flightdescription
    Created ..FlightDescriptionEvent.as
    Created ..FlightDescriptionView.mxml
    Created ..FlightDescriptionForm.mxml
    
  2. The output shown here has been organized such that the directory which is created by Roo comes first, followed by the files that are created in the directory. The Spring Roo shell will not show the output as it has been shown above. For brevity, the output shows only the files that were created corresponding to the FlightDescription JPA entity.
  3. Exit the Roo shell and execute mvn install from the directory containing the flightapp_flex project to build the flightapp_flex project:
    C:
    oo-cookbookch05-flex>mvn install
    
  4. Execute the tomcat:run goal (from the directory containing the flightapp_flex Roo project) of the Tomcat Maven plugin to start the embedded Tomcat instance:
    C:
    oo-cookbookch05-flex>mvn tomcat:run
    
  5. Open the web browser and access the flightapp_flex_scaffold.html file, which acts as the HTML wrapper for our Flex application: http://localhost:8080/flightapp_flex/flightapp_flex_scaffold.html. If Flash Player 10 or above is not already installed for your web browser, you'll be asked to install it. It is also recommended that you install Flash Debugger for your web browser to view any exceptions raised while interacting with the Flex application. If you see the following Flex application user interface, then it means you have successfully deployed your Flex application on Tomcat:
    How to do it...
  6. This screenshot shows the list of JPA entities that can be managed using the Flex application. As the flightapp_flex project contained Flight and FlightDescription entities, they are shown in the list.
  7. To perform CRUD operations on the FlightDescription and Flight entity instances, double-click the JPA entity name in the list. The following screenshot shows the screen that is displayed when you double-click the FlightDescription item in the list:
    How to do it...

How it works...

The flex remoting all command is processed by the Flex add-on of Spring Roo.

Flex clients interact with server-side BlazeDS remoting destinations (which are Java objects) via BlazeDS RemotingService . As we are using Spring BlazeDS integration, remoting destinations are configured as Spring service components, and the RemotingService is configured with sensible defaults by the <message-broker> element of Spring's flex schema (refer SRC_MAIN_WEBAPPWEB-INFspringflex-config.xmlfile). The package argument of the flex remoting all command specifies the package in which the remoting destinations are created.

Note

It is important to note that Flex clients interact with messaging destinations (which could be a JMS queue or topic) using the MessageService and with remoting destinations (Java objects) using the RemotingService.

The following table describes the important directories and files that are created when the flex remoting all command is executed:

Directory / file

Description

SRC_MAIN_JAVAsample ooflightappflex

Contains remoting destinations created by Roo corresponding to each JPA entity in the flightapp_flex application for which a remoting destination doesn't exist. This directory is created based on the package argument value of the flex remoting all command.

ROOTsrcmainflexsample ooflightappdomain

Contains Roo-generated ActionScript classes that map to JPA entities in the flightapp_flex application.

ROOTsrcmainflexsample ooflightapppresentationflightdescription

Contains MXML files and ActionScript classes for performing CRUD operations on the FlightDescription JPA entity. The name of the directory is derived from the name of the JPA entity.

ROOTsrcmainflexsample ooflightapppresentationflight

Contains MXML files and ActionScript classes for performing CRUD operations on the Flight JPA entity. The name of the directory is derived from the name of the JPA entity.

When the flex remoting all command is executed, it creates a remoting destination (which is also Spring's service component) corresponding to each JPA entity in the application for which a remoting destination doesn't already exist. A remoting destination defines methods to perform CRUD operations on the corresponding JPA entity. The following code listing shows the remoting destination, FlightDescriptionService class, created by Roo corresponding to the FlightDescription JPA entity:

FlightDescriptionService.java


package sample.roo.flightapp.flex;

import org.springframework.flex.roo.addon.RooFlexScaffold;
import sample.roo.flightapp.domain.FlightDescription;
import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.stereotype.Service;

@RooFlexScaffold(entity = FlightDescription.class)
@RemotingDestination
@Service
public class FlightDescriptionService {
}

In this code, @RooFlexScaffold annotation instructs Roo to generate a corresponding AspectJ ITD file. This AspectJ ITD file introduces methods into the FlightDescriptionService class for performing CRUD operations on the FlightDescription entity. The entity attribute of @RooFlexScaffold annotation specifies the JPA entity managed by the FlightDescriptionService class. The @RemotingDestination annotation of Spring indicates that FlightDescriptionService class is exported as a remoting destination.

Spring-managed MessageBroker is responsible for routing messages received from the Flex clients to RemotingService, which in turn invokes the method on the Spring-managed remoting destination. The @Service annotation indicates that FlightDescriptionService represents Spring's service component. The use of the @Service annotation ensures that FlightDescriptionService is auto-registered with Spring's web application context, using the classpath scanning feature of Spring (refer to the <component-scan> element defined in the webmvc-config.xml file).

The following code listing shows the AspectJ ITD file created corresponding to the @RooFlexScaffold annotation in the FlightDescriptionService class:

FlightDescriptionService_Roo_Service.aj
package sample.roo.flightapp.flex;

import java.lang.Long;
import java.util.List;
import sample.roo.flightapp.domain.FlightDescription;

privileged aspect FlightDescriptionService_Roo_Service {
    
  public FlightDescription 
       FlightDescriptionService.show(Long id) {
    ...
    return FlightDescription.findFlightDescription(id);
  }
    
  public List<FlightDescription> 
       FlightDescriptionService.list() {
    return FlightDescription.findAllFlightDescriptions();
  }
  ...
}

This code shows that FlightDescriptionService_Roo_Service.aj introduces CRUD operations for the FlightDescription JPA entity in the FlightDescriptionService class. Though not shown in the above code, pagination support is also introduced for reading the list of FlightDescription JPA entities.

The name of the AspectJ ITD file corresponding to the @RooFlexScaffold annotation has the following naming convention: <JPA-entity-name>Service_Roo_Service.aj, where <JPA-entity-name> is the name of the JPA entity specified by the entity attribute of the @RooFlexScaffold annotation.

Invoking Spring-managed remoting destination methods from the Flex client may require sending and receiving objects. For instance, the show method of FlightDescriptionService returns a FlightDescription object and the create method accepts a FlightDescription object. Flex allows exchanging data between the Flex client and remoting destination method by auto-converting the ActionScript object to the Java object and vice versa. As the Flex client in the flightapp_flex application exchanges flight description details with the FlightDescriptionService remoting destination, Roo generates ActionScript classes corresponding to the JPA entity managed by FlightDescriptionService. The following code shows the Roo-generated FlightDescription.as ActionScript class corresponding to the FlightDescription JPA entity:

FlightDescription.as
package  sample.roo.flightapp.domain{
[RemoteClass(alias="sample.roo.flightapp.domain.FlightDescription")]
   public class FlightDescription {
      public var destination:String;
      public var id:Number;
      public var origin:String;
      public var price:Number;
      public var version:Number;
   }
}

This code shows that the FlightDescription.as ActionScript class defines the same attributes as the corresponding FlightDescription JPA entity. The [RemoteClass] metadata tag specifies the remote Java object to which the ActionScript object maps. The alias attribute specifies the fully-qualified class name of the remote Java object to which the ActionScript object maps.

Roo creates ActionScript and MXML files corresponding to each JPA entity so that CRUD operations can be performed on JPA entities from the scaffolded Flex user interface. The following table describes each of these Roo-generated files (located in ROOTsrcmainflexsample ooflightapppresentationflightdescription and ROOTsrcmainflexsample ooflightapppresentationflight directories):

File

Description

<JPA-entity-name>Event.as

Subclass of flash.events.Event that defines different event types, like create, edit, and delete events that are generated when a JPA entity is created, edited, or modified. In flightapp_flex project, FlightEvent.as and FlightDescriptionEvent.as represent event classes.

<JPA-entity-name>View.mxml

MXML file that shows the list of entity instances and options to create, edit, and delete entity instances. In the flightapp_flex project, FlightView.mxml and FlightDescriptionView.mxml MXML files show list of Flight and FlightDescription entity instances, respectively, and options to create, edit, and delete the entity instances.

<JPA-entity-name>Form.mxml

The MXML file that shows the form for creating entity instances. In the flightapp_flex project, FlightForm.mxml and FlightDescriptionForm.mxml files show the form for creating Flight and FlightDescription JPA entity instances, respectively.

The following code shows the FlightDescriptionEvent.as ActionScript class createdby Roo:

package sample.roo.flightapp.presentation.flightdescription 
{
  import flash.events.Event;
  import sample.roo.flightapp.domain.FlightDescription;

  public class FlightDescriptionEvent extends Event {
   public static const CREATE:String = 
                              "flightDescriptionCreate";
   public static const UPDATE:String = 
                              "flightDescriptionUpdate";
   public static const DELETE:String = 
                              "flightDescriptionDelete";

   public var flightDescription:FlightDescription;
        
   public function FlightDescriptionEvent(type:String, 
     flightDescription:FlightDescription, 
     bubbles:Boolean = true, cancelable:Boolean = false){
       this.flightDescription = flightDescription;
       super(type, bubbles, cancelable);
     }
   }
}

The FlightDescriptionEvent class is a subclass of the flash.events.Event class and defines three different types of events: flightDescriptionCreate, flightDescriptionUpdate, and flightDescriptionDelete. The FlightDescription ActionScript object (which corresponds to the FlightDescription JPA entity on the server-side) represents the payload carried by the FlightDescriptionEvent event type.

As mentioned earlier, in the flightapp_flex application, flightapp_flex_scaffold.mxml file defines the initial user interface of the application. When the flex remoting all command was executed, we saw in the output that the flightapp_flex_scaffold.mxml file was updated. The following code shows the modification that was made by Roo to the flightapp_flex_scaffold.mxml file:

flightapp_flex_scaffold.mxml
...
<fx:Declarations>
  <s:ArrayList id="entities">
    <fx:String>FlightDescription</fx:String>
    <fx:String>Flight</fx:String>
  </s:ArrayList>
  
  ...
 </fx:Declarations>
  ...
  <s:Panel id="entityPanel" title="Entity List" height="100%">
   <s:List id="entityList" dataProvider="{entities}" 
      width="100%" height="100%" 
     toolTip="Double-Click the selected Entity" 
     doubleClickEnabled="true" 
     doubleClick="entityList_doubleClickHandler(event)"/>
  </s:Panel>
 </s:Group>

If you compare this code with the code of the flightapp_flex_scaffold.mxml file that we saw in the previous recipe, you'll notice that the only change that happened is the addition of the <fx:String> elements to the <ArrayList>. Roo creates an <fx:String> element corresponding to each JPA entity in the application. By default, the value of the <fx:String> element is the simple name of the corresponding JPA entity. As the <List> component makes use of <ArrayList> as its data provider, the <List> component now displays Flight and FlightDescription list items in the user interface, as shown here:

How it works...

This screenshot shows that Roo doesn't generate a list item corresponding to the finder method, findFlightDescriptionsByDestinationAndOrigin, defined in FlightDescription JPA entity.

When you double-click an item in the list shown above, it invokes the entityList_doubleClickHandler ActionScript method defined in the flightapp_flex_scaffold.mxml file, which displays the user interface generated either by FlightView.mxml or FlightView.mxml, depending upon the list item double-clicked. The following code shows the entityList_doubleClickHandler method:

protected function 
   entityList_doubleClickHandler(event:MouseEvent):void { 
  ..
  var selectedEntity:String = entityList.selectedItem;
  var selectedEntityPackage:String = 
    selectedEntity.toLowerCase();

  var viewClass:Class = 
    getDefinitionByName("sample.roo.flightapp.presentation."
    + selectedEntityPackage+"::"+selectedEntity+"View") 
    as Class;
    if (viewClass != null) {
     var newView:UIComponent = UIComponent(new viewClass());
     ...
     mainGroup.addElement(newView);
    }
  ...
}

As MXML files are compiled into ActionScript classes, FlightDescriptionView.mxml and FlightView.mxml files are converted to FileDescriptionView and FlightView ActionScript classes, respectively. The entityList_doubleClickHandler method obtains the selected item value from the list (which is either FlightDescription or Flight) and appends 'View' string to it—making the concatented value to FlightDescriptionView or FlightView. The entityList_doubleClickHandler then creates an instance of FlightDescriptionView or FlightView and adds it to the main user interface.

The following sequence diagram summarizes the role played by the entity_doubleClickHandler method:

How it works...

It is important to note that the entityList_doubleClickHandler method of the flightapp_flex_scaffold.mxml file never directly references either the FlightView or FlightDescriptionView ActionScript class. In fact, FlightView and FlightDescriptionView classes are not referenced by any other MXML or ActionScript class in the flightapp_flex project. The side-effect of this is that the Flex compiler doesn't include FlightDescriptionView and FlightView in the generated SWF file. To instruct Flex compiler to include FlightDescriptionView and FlightView ActionScript classes, Roo adds their fully-qualified name in the flightapp_flex_scaffold-config.xml file, as shown here:

flightapp_flex_scaffold-config.xml
<flex-config xmlns="http://www.adobe.com/2006/flex-config">
  <includes append="true">
	<symbol>sample.roo.flightapp.presentation.flightdescription.FlightDescriptionView
   </symbol>
   <symbol>
      sample.roo.flightapp.presentation.flight.FlightView
   </symbol>
  </includes>
</flex-config>

The <symbol> elements specify the ActionScript classes that should be included in the generated SWF file by the Flex compiler.

The FlightDescriptionView.mxml shows a New FlightDescription button, and if clicked, it invokes the showForm method. The showForm method of FlightDescriptionView.mxml shows the form (represented by FlightDescriptionForm.mxml) for creating FlightDescription entity instances, as shown here:

How it works...

The following sequence diagram shows what happens behind the scenes when you click on the New FlightDescription button:

How it works...

This sequence diagram shows that the showForm method creates FlightDescriptionForm and FlightDescription objects. The FlightDescription object (which corresponds to FlightDescription JPA entity) acts as the form-backing object that we see in web applications. The showForm methods sets the FlightDescription object in the FlightDescriptionForm instance. Also, showForm adds an event listener for the FlightDescriptionEvent.CREATE event to FlightDescriptionForm.

The following code shows the showForm method:

private function showForm
  (flightDescription:FlightDescription = null):void {
 var form:FlightDescriptionForm =  
   PopUpManager.createPopUp(this, FlightDescriptionForm, true) 
   as FlightDescriptionForm;
 .. 
 form.flightDescription = flightDescription != null ?  
 flightDescription : new FlightDescription();

 form.addEventListener(FlightDescriptionEvent.CREATE,   
   flightDescriptionView_flightDescriptionCreateEventHandler);
}

This code shows that, the addEventListener method accepts the type of event that FlightDescriptionForm object listens to, which is FlightDescriptionEvent.CREATE. The addEventListener also accepts the name of the handler method that is invoked when the event is received by the FlightDescriptionForm object. So, if the FlightDescriptionEvent.CREATE event is received by the FlightDescriptionForm object, it results in the invocation of the flightDescriptionView_flightDescriptionCreateEventHandler method. We'll come back to the handler method, but first let's look at how the FlightDescriptionEvent.CREATE event is generated.

The following sequence diagram shows that the FlightDescriptionEvent.CREATE event is generated when the user presses the Save button to create a FlightDescription JPA entity instance:

How it works...

This sequence diagram shows that when the Save button is clicked, it results in the invocation of the processSave method defined in FlightDescriptioForm.mxml. The processSave method validates the form data entered by the user using the mx.validators.Validator. If the data validation succeeds, form data is set in the FlightDescription ActionScript object. The processSave method now creates a FlightDescriptionEvent event of type FlightDescriptionEvent.CREATE and passes the FlightDescription ActionScript object as the payload of the event. Invoking the dispatchEvent method results in dispatching the newly created event to listeners.

So, after receiving the FlightDescriptionEvent.CREATE event, flightDescriptionView_flightDescriptionCreateEventHandler is invoked, as explained earlier. The following code shows the flightDescriptionView_flightDescriptionCreateEventHandler method, which invokes the FlightDescriptionService's create method to create an instance of the FlightDescription JPA entity:

protected function 
  flightDescriptionView_flightDescriptionCreateEventHandler
   (event:FlightDescriptionEvent):void {
    flightDescriptionService.create(event.flightDescription);
}
...   

The flightDescriptionService object in the previous code represents a mx.rpc.remoting.RemoteObject, which is used by Flex clients to access remoting destinations. RemoteObject is defined in FlightDescriptionView.mxml using the <RemotObject> tag, as shown here:

<s:RemoteObject channelSet="{remotingChannels}" 
   destination="flightDescriptionService" 
   fault="flightDescriptionService_faultHandler(event)" 
   id="flightDescriptionService">
 ...
</s:RemoteObject>

In this code, {remotingChannels} identifies the ChannelSet to use for communication with server-side Java objects. We saw in the previous recipe that remoting channels used by the flightapp_flex application are defined in the flightapp_flex_scaffold.mxml file using the <ChannelSet> tag. The destination attribute specifies the remoting destination that is accessed via RemoteObject.

There's more...

The Flex Add-on provides round-tripping support, that is, modifications to JPA entities are propagated to MXML and ActionScript files.

Flex Addon doesn't provide any support for controlling the methods that form a part of the Spring-managed remoting destinations. For instance, you can't control the methods that are part of the FlightDescriptionService_Roo_Service.aj file using @RooFlexScaffold annotation.

If you want that a method in the Spring-managed remoting destination is not accessible to Flex clients, then all you need to do is to either perform push-in refactoring or define the method in the corresponding Java class and add the @RemotingExclude annotation of Spring to the method.

Spring Roo makes use of JSR 303 annotations specified in the JPA entity to add Flex validators in the MXML files. For instance, if a JPA entity field specifies @NotNull JSR 303 annotation then Roo adds a Flex StringValidator or Numbervalidator that checks that the field on the form is not blank. Note that Flex addon support for JSR 303 annotations is limited.

See also

  • Refer to the Getting started with Flex application development to see how you can set up Flex for your Roo project
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.247.181