11.1. CRUD with Flash Builder 4

Flash Builder (earlier called Flex Builder) is the Adobe-supported Integrated development environment (IDE) for development of Flex and AS3 applications.

Flash Builder, from version 3 on, includes a CRUD code generation utility that generates the list and item detail views as a database table. This generated application works for Java, PHP, and ColdFusion server-side environments. That is, three different server-side components can be generated to support the CRUD operations.

The latest version of Flash Builder is Flash Builder 4, which as I write this book is in public beta. This new version of the IDE enhances the CRUD generation capabilities substantially from its earlier version. In this section, you will get a chance to see the various available features of this new and improved IDE. You can download the latest copy of Flash Builder from http://labs.adobe.com/technologies/flashbuilder4/. Flash Builder is a commercial product. You can apply your existing Flex Builder 3 licenses to the beta release or use the trial version, which is valid for 60 days.

In the first example, I will demonstrate CRUD generation for simple HTTP service endpoints.

11.1.1. CRUD with RESTful Endpoints

In this section, I will create a simple Flex application and wire it up to consume data from HTTPService endpoints. Such endpoints could typically adhere to the REST architectural style, which has gained in popularity over the past few years.

REST and associated concepts are explained in Chapter 1, in a section titled: "Leveraging Services to Access External Data." In case you are unsure of REST concepts, you could benefit from rereading parts of Chapter 1 that pertain to it.

I used a book catalog example earlier in this book to illustrate Spring and BlazeDS integration. I am going to reuse that example, with minor modifications, to illustrate the CRUD generation in this chapter.

For starters, let me describe what the book catalog application does. A book catalog maintains a list of books. For each book, it saves the following pieces of information:

  • ID — A unique identifier for the book. One could have used ISBN numbers to uniquely identify books. However, ISBNs are of two types: one has 10 digits, while the other has 13. From January 1, 2007 every book is supposed to have a 13-digit ISBN and so it could be considered as the unique ID. However, for simplicity sake I consider an internal numeric identifier.

  • Title

  • Author — I assume that there is only one author per book, in favor of reducing the domain complexity.

  • Price — All in a single currency.

To manipulate the book catalog records, that is, books, I create a service abstraction which has the following methods:

  • findAll — Returns a list of books

  • findById(int id) — Returns a particular book that matches the unique ID

  • create(Book item) — Creates a new book

  • update(Book item) — Updates a particular book record

  • remove(Book item) — Deletes a particular book record

Once I have the service class ready, I create a URL mapping to service method invocation. Mapping from URLs to service methods involves inclusion of a front controller that intercepts all requests that match a particular URL pattern. Once the request is intercepted at the front controller (fine-grained patterns, for example, reference specific method names or references), this leads to the invocation of specific service methods.

I create a URL mapping to service method calls using REST-style abstractions. So, the CRUD operations listed previously are mapped to URLs as follows:

The first two find calls are HTTP GET method calls and the three create, update, and delete calls are HTTP POST method calls. Purists may argue that adhering to REST, HTTP PUT and DELETE should be leveraged for create and delete methods. However, often because of resource security concerns the HTTP PUT and DELETE methods are not supported in production environments. In any case, these URLs are one possible representation and certainly alternatives are possible.

Once the URLs are identified, I am ready to generate a CRUD application using Flash Builder.

First, create a new Flex project. I will create a new project called HTTPServiceCRUD. When I create the Flex project I choose the Server Technology as None/Other, as I will rely on HTTPService to access data and save the modified data back into the store. You can route HTTPService calls through a BlazeDS server. This comes in handy when the destination does not define a crossdomain.xml security policy. In any case, I rely on an external directly accessed HTTPService in this example.

Once a project is created I choose Connect To HTTP from the Data menu. Figure 11-1 shows the screen where I make this selection.

This choice brings me to the Configure HTTP Service screen, which before providing any data is as shown in Figure 11-2. Once I provide all the information about the operation names and the corresponding URLs, the screen is as shown in Figure 11-3. For each POST HTTP method–based operation you can also define parameters and their data types.

Figure 11.1. Figure 11-1

Figure 11.2. Figure 11-2

Once you click the Finish button, a screen with suggestions to specify the return type for the service operation and to bind the service to UI components appears. The screen is shown in Figure 11-4.

At this stage, you will benefit from analyzing the generated code. If you browse to the services.BookService class, you will notice that the class extends _Super_BookService. The BookService class is meant to be the extension point where you can define additional behavior. The superclass of this service class is where all the generated code resides.

Figure 11.3. Figure 11-3

Figure 11.4. Figure 11-4

In the constructor of _Super_BookService, operations for each of the five mapped methods are created. The parameters and Http method type is set for each operation. All defined operations are added to an Array called "operations". For illustration, the operation creation and initialization code for the five methods in the _Super_BookService constructor is as follows:

_serviceControl = new HTTPMultiService();
var operations:Array = new Array();
var operation:Operation;
var argsArray:Array;

operation = new Operation(null, "findAll");
operation.url = "http://www.shashanktiwari.com/books";
operation.method = "GET";
operation.resultType = Object;
operations.push(operation);

operation = new Operation(null, "findById");
operation.url = "http://www.shashanktiwari.com/books/1234";

operation.method = "GET";
operation.resultType = Object;
operations.push(operation);

operation = new Operation(null, "create");
operation.url = "http://www.shashanktiwari.com/books/1234";
operation.method = "POST";
operation.contentType = "application/xml";
operation.resultType = Object;
operations.push(operation);

operation = new Operation(null, "update");
operation.url = "http://www.shashanktiwari.com/books/1234";
operation.method = "POST";
operation.contentType = "application/xml";
operation.resultType = Object;
operations.push(operation);

operation = new Operation(null, "remove");
operation.url = "http://www.shashanktiwari.com/books/1234";
operation.method = "POST";
argsArray = new Array("id");
operation.argumentNames = argsArray;
operation.contentType = "application/xml";
operation.resultType = Object;
operations.push(operation);

_serviceControl.operationList = operations;

Next, let's peek into one of the service method implementations. The findAll method implementation is as follows:

public function findAll() : AsyncToken
{
    var _internal_operation:AbstractOperation =
        _serviceControl.getOperation("findAll");
    var _internal_token:AsyncToken =
        _internal_operation.send() ;

    return _internal_token;
}

Now that the service is created you could choose any of the following Data menu items to generate the views:

  • Bind to data — You could bind a DataGrid, List, TextField, or any other valid component to bind it to the data that the service retrieves.

  • Generate Form — Bind the details editable view to a form.

  • Generate Details Form — Bind the details editable view to a form. You could first bind the list view and then generate the details form for the items in the list.

I generate a simple form to create a new item in the book catalog. In order to generate a form, I choose Generate Form from the Data menu. The first screen is as shown in Figure 11-5. Since no return type has been configured yet, you are given a chance to configure the method return type. On clicking the Configure Return Type button, you will see a screen like the one in Figure 11-6. You can either use an existing AS3 type or create a new custom type to configure the return type for the method. It's the create method, and I choose to go with Boolean return type. I would like my service to tell me if the create method was able to successfully create an item or not. I make my choice as shown in Figure 11-6.

Figure 11.5. Figure 11-5

Figure 11.6. Figure 11-6

As I move forward after specifying the return type, I am presented with a screen to define the property control mapping. See Figure 11-7 to understand what it looks like.

At this stage, you may want to view the details screen, which is shown in Figure 11-8. You will notice a form for creating a new book item. You will also notice a check box that binds to the returned Boolean value of the create method call. If a new book item is created successfully a "true" value is returned, which shows up as a selection on the check box. So far the service data and all the views are not wired enough to make things work seamlessly, but service methods for the CRUD calls have been identified and a detail screen has been generated. The moment the server-side RESTful service is available and the list views are generated, the complete application will be ready as far as the essential CRUD features go.

Figure 11.7. Figure 11-7

Figure 11.8. Figure 11-8

The illustration so far has presented the code generation strategy with CRUD applications. The server side has relied exclusively on HTTPService, which is agnostic to the way that a Flex application that consumes the service is actually built. Now we move to code generation for a SOAP WebService to reinforce the concept that the code generation feature is both pervasive and comprehensive. Code generation for Web Services based on WSDL was available in Flex Builder 3 as well.

11.1.2. Generating Client Code for WebService Consumption

I choose a free web service from CDYNE that returns the weather data for a particular place identified by the zip code. Details about the web service can be obtained at http://wiki.cdyne.com/wiki/index.php?title=CDYNE_Weather. The WSDL for this web service is accessible at http://ws.cdyne.com/WeatherWS/Weather.asmx?wsdl.

You can choose to go with an alternative web service. Just make sure to point to the appropriate WSDL. Code generation works off the WSDL.

Figure 11-9 shows the screen where the WSDL URI and service name are specified. This screen is brought up when you choose the Connect to WebService option on the Data menu.

Figure 11.9. Figure 11-9

On WSDL introspection, the code generator discovers three methods for the CDYNE weather service, namely:

  • GetWeatherInformation

  • GetCityForecastByZIP

  • GetCityWeatherByZIP

Figure 11-10 shows the screen where the methods after introspection are shown. I select all three methods and click the Finish button. Again, client-side service methods are generated and you have the opportunity to bind list view and item details screens to the service methods. In this example, the supported operations were not CRUD operations. However, if your web service supports CRUD operations, then the code generation process will be similar.

I will just give you a peek into the generated constructor of _Super_CDYNE_Weather and leave the rest for you to discover. Here is the code:

_serviceControl = new WebService();
SchemaTypeRegistry.getInstance().registerClass(new QName("http://ws.cdyne.com/
   WeatherWS/", "ForecastReturn"), ForecastReturn);
SchemaTypeRegistry.getInstance().registerClass(new QName("http://ws.cdyne.com/
   WeatherWS/", "temp"), Temp);
SchemaTypeRegistry.getInstance().registerClass(new QName("http://ws.cdyne.com/
   WeatherWS/", "Forecast"), Forecast);
SchemaTypeRegistry.getInstance().registerClass(new QName("http://ws.cdyne.com/
   WeatherWS/", "WeatherReturn"), WeatherReturn);
SchemaTypeRegistry.getInstance().registerClass(new QName("http://ws.cdyne.com/
   WeatherWS/", "WeatherDescription"), WeatherDescription);
SchemaTypeRegistry.getInstance().registerClass(new QName("http://ws.cdyne.com/
   WeatherWS/", "POP"), POP);

var operations:Object = new Object();
var operation:Operation;

operation = new Operation(null, "GetWeatherInformation");
operation.resultElementType = WeatherDescription;
operations["GetWeatherInformation"] = operation;

operation = new Operation(null, "GetCityForecastByZIP");
operation.resultType = ForecastReturn;
operations["GetCityForecastByZIP"] = operation;

operation = new Operation(null, "GetCityWeatherByZIP");
operation.resultType = WeatherReturn;
operations["GetCityWeatherByZIP"] = operation;

_serviceControl.operations = operations;
_serviceControl.service = "Weather";
_serviceControl.port = "WeatherSoap";
_serviceControl.wsdl = "http://ws.cdyne.com/WeatherWS/Weather.asmx?wsdl";
_serviceControl.loadWSDL();

Figure 11.10. Figure 11-10

As you walk through the code you will notice that XML schema for data types is registered as specific AS3 classes. Then web service operations are created and initialized for each of the three functions. Finally, the service, port and WSDL properties of the _serviceControl are set. By the end of the constructor, the service class is instantiated and initialized for use.

After looking at HTTPService and WebService, I turn my attention to remoting service destinations that allow more effective RPC over AMF, as opposed to the HTTPService and WebService options.

11.1.3. Generating CRUD with Remoting Service Destinations

Flash Builder 4 brings automated CRUD generation and client-side data management to Flex and Java applications that use BlazeDS. This increases the developer productivity and brings some of the built-in features that only LCDS users have enjoyed until now. You have already seen some of the code generation capabilities, in the context of HTTPService and WebService, in the last couple of sections.

In order to understand the code generation and the client-side data management features, follow along as I create a simple application that leverages the new features.

First, download the latest nightly build of BlazeDS. The latest code in the BlazeDS subversion trunk is version 4.0, which will continue to evolve till the next release. You can download the nightly builds of SVN trunk from http://opensource.adobe.com/wiki/display/blazeds/download+blazeds+trunk.

The download is available as a zip file archive. I expanded the zip archive to get the blazeds.war file in the distribution. I deployed this blazeds.war file as blazeds4 in the tomcat installation I have from the BlazeDS turnkey download. Deploying the downloaded blazeds.war as blazeds4 involved the following two steps:

  • Creating a folder called blazeds4 in the Tomcat webapps folder

  • Extracting the contents of blazeds.war into the blazeds4 folder

You could also deploy the latest version of BlazeDS is any other application server of your choice.

Now that the latest version of BlazeDS is deployed, make a few small configuration changes before starting on coding up the server-side services.

Next, open blazeds4WEB-INFweb.xml in your favorite code editor. You will notice a section on the RDSDispatcherServlet that by default is commented out. Go ahead and uncomment the portion that pertains to the RDSDispatcherServlet. This Java Servlet enables the remoting service class introspection and code generation that I will illustrate soon. The RDSDispatcherServlet configuration is as follows:

<servlet>
        <servlet-name>RDSDispatchServlet</servlet-name>
              <display-name>RDSDispatchServlet</display-name>
        <servlet-class>flex.rds.server.servlet.FrontEndServlet</servlet-class>
              <init-param>
                      <param-name>useAppserverSecurity</param-name>
                      <param-value>false</param-value>
              </init-param>
        <load-on-startup>10</load-on-startup>
    </servlet>

    <servlet-mapping id="RDS_DISPATCH_MAPPING">
        <servlet-name>RDSDispatchServlet</servlet-name>
        <url-pattern>/CFIDE/main/ide.cfm</url-pattern>
    </servlet-mapping>

The useAppserverSecurity default value is true. You may set that to false to avoid the application server authentication as a requirement for using the CRUD generation and the client-side data management with BlazeDS.

Next, let's write up the server-side service classes. I create the following classes:

  • Book.java — A bean type model class that contains the attributes and accessor methods for a book.

  • IBookService.java — An interface that defines the five CRUD methods, namely findAll, findById, create, update, and remove.

  • BookService.java — A service class that implements the IBookService interface and provides an implementation of a service that interacts with a book catalog.

  • HsqldbDao.java — I also create a data access object class to access an HSQLDB database. You can create your own data access object to access an alternative data store.

I will not show the code for all the implementation classes here but only show the IBookService interface to provide you a view into the available methods, their parameters, and return types. IBookService.java source is as follows:

package problazeds.ch11;

import java.util.List;

public interface IBookService
{
    public List<Book> findAll();

    public Book findById(int id);

    public boolean create(Book item);

    public boolean update(Book item);

    public boolean remove(Book item);


}

Once all the Java classes are coded, I compile them and copy over the compiled code to the blazeds4WEBINFclasses folder within a folder structure that matches the packages hierarchy. In this particular example, all classes are copied over to the problazedsch11 folder within the WEB-INFclasses folder.

Next I configure the service class as a remoting service destination. I create the following entry in remoting-config.xml, which you know is included in the services-config.xml file that the BlazeDS MessageBrokerServlet reads on startup. The remoting service configuration for the BookService class is:

<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service"
    class="flex.messaging.services.RemotingService">

<adapters>
        <adapter-definition id="java-object" class="flex.messaging.services.
           remoting.adapters.JavaAdapter" default="true"/>
    </adapters>

    <default-channels>
        <channel ref="my-amf"/>
    </default-channels>

    <destination id="bookService">
        <properties>
            <source>problazeds.ch11.BookService</source>
            <scope>application</scope>
        </properties>
        <adapter ref="java-object"/>
    </destination>

</service>

This gets the server side ready. Next, I create a Flex application to consume these server-side services.

Using Flash Builder 4, I create a new Flex project. I call it RemotingServiceCRUD. You can choose a name that you like or go with my choice. I choose BlazeDS as the Server Technology. Look at Figure 11-11 to see what the initial screen looks like.

Figure 11.11. Figure 11-11

On clicking the Next button, a screen to specify the server location comes up. You need to specify the following information in this screen:

  • Root folder — The root of the web application where the BlazeDS server side is deployed. In my case, the value is C:applicationslazeds_b1_020108 omcatwebappslazeds4. You can browse to the folder where your web application is deployed, which provides a convenient way to choose the location.

  • Root URL — The URL at which the application is available. In my case the value is http://localhost:8400/blazeds4. I am using the BlazeDS turnkey distribution that listens for HTTP requests by default on port 8400. Make sure to specify the URL correctly.

  • Context root — The context root for the web application, which is the same as the web application name; in my case, this is blazeds4.

After you have specified the information, you can validate the configuration settings. Start up your server before you validate the configuration. Also, turn off any antivirus programs that might not allow connections from an Eclipse instance. On this screen, you also have the option to specify the output folder, which you are most likely to leave as the default value. The screen where you provide the server location information is shown in Figure 11-12.

Figure 11.12. Figure 11-12

Clicking Next takes you to the screen that confirms the Flex application name. After confirming the value for the application name and optionally providing an output folder, the Flex project is created.

Once a Flex project is created, select the Connect to BlazeDS option from the Data menu. Figure 11-13 shows how you make this selection.

Figure 11.13. Figure 11-13

You will be prompted with an authentication screen asking you to provide the credentials to authenticate with RDS. Select the No password required check box and click OK. You will be taken to the screen that will let you import the BlazeDS services. The authentication screen before and after the No password required selection is shown in Figures 11-14 and 11-15.

Figure 11.14. Figure 11-14

Figure 11.15. Figure 11-15

The Import BlazeDS/LCDS Service screen, shown in Figure 11-16, is where you choose the services and generate the client-side data management classes.

Figure 11.16. Figure 11-16

All the remoting service destinations configured in remoting-config.xml are available to be imported into your Flex application. In my simple example, I have only one service, called BookService, and that is available to be wired in to the Flex user interface. You also have to give your service a name, which I have chosen as "bookService". You could choose a different name. Figure 11-17 shows the choices I made.

Figure 11.17. Figure 11-17

Once I click the Finish button, a screen comes up suggesting that I configure return types for services and bind service operations to UI components.

The Data/Services view lists all the five CRUD methods. The Data/Services view is shown in Figure 11-18.

Figure 11.18. Figure 11-18

At this stage, you may also want to peek into the generated code. Browsing to the services.bookService folder in the project source, you will notice the following AS3 classes:

  • _BookEntityMetadata

  • _Super_Book

  • _Super_BookService

  • Book

  • BookService

As you saw earlier in the discussion of the HTTPService and WebService, Book and BookService extend _Super_Book and _Super_BookService, respectively. The constructor for _Super_BookService adds the five CRUD operations as follows:

_serviceControl = new RemoteObject();

         var operations:Object = new Object();
         var operation:Operation;

         operation = new Operation(null, "findAll");
                operation.resultElementType = Object;
         operations["findAll"] = operation;
         operation = new Operation(null, "findById");
                operation.resultType = Book;
         operations["findById"] = operation;
         operation = new Operation(null, "remove");
                operation.resultType = Boolean;
         operations["remove"] = operation;
         operation = new Operation(null, "update");
                operation.resultType = Boolean;
         operations["update"] = operation;
         operation = new Operation(null, "create");
                operation.resultType = Boolean;
         operations["create"] = operation;
         _serviceControl.operations = operations;
                _serviceControl.convertResultHandler = TypeUtility.convertResultHandler;

               _serviceControl.destination = "bookService";

The Book attributes are managed through the generated _BookEntityMetadata class. Property maps in this class are initialized as follows:

if (model_internal::dependentsOnMap == null)
        {
            // dependents map
            model_internal::dependentsOnMap = new Object();
            model_internal::dependentsOnMap["id"] = new Array();
            model_internal::dependentsOnMap["author"] = new Array();
            model_internal::dependentsOnMap["title"] = new Array();
            model_internal::dependentsOnMap["price"] = new Array();

            // collection base map
            model_internal::collectionBaseMap = new Object()
        }

        model_internal::_instance = book;

Now, let's put this generated code to work. I will create a DataGrid next and bind the findAll method that returns the list of books as the data provider for the grid. I will be able to do all of this with a few clicks and with no hand-coding.

Change to the design view and drag a DataGrid from the Data Controls to the main application MXML file. The screen will be as shown in Figure 11-19.

Figure 11.19. Figure 11-19

Then right-click on the DataGrid and select Bind To Data from the context menu choices. See Figure 11-20.

Figure 11.20. Figure 11-20

You will be presented with a view to choose the service operations. I choose findAll as the operation to get the list of books. See Figure 11-21.

I also have the option to specify a return type. If you choose to specify a return type by clicking the Configure Return Type button, you will be presented with a screen where you can choose an existing AS3 data type or define a custom AS3 data type. I choose an existing Books[] as the return type. Once the return type is specified, you will see a screen like the one in Figure 11-22.

Once I make all the selections and confirm, the DataGrid automatically updates with the correct fields and is wired up with the RemoteObject. The automatically generated grid as viewed in the design view is shown in Figure 11-23.

Figure 11.21. Figure 11-21

Figure 11.22. Figure 11-22

Figure 11.23. Figure 11-23

That's it! You have the list view fully generated and ready for use. Similarly, you could generate the detail views as well.

These new code generation and client-side data management features enhance developer productivity and provide a means to create Flex application rapidly. The code generation, although static, allows for versioning and maintenance to keep pace with changing requirements.

Prior to Flash Builder 4, Flex Builder 3 supported the generation of simple CRUD applications by pointing to a database. In addition, Clear Data Builder, a code generator from Clear Toolkit, an open source framework and component library, had a way to generate CRUD applications basis xDoclet annotations of SQL on server side methods for the CRUD operations. Clear Toolkit is available at http://sourceforge.net/projects/cleartoolkit/. If you are interested in finding out the details on how the Clear Toolkit generates SQL-based CRUD applications, read a document titled "Cooking RIA CRUD with Flex and BlazeDS," which is available online at http://www.myflex.org/demos/Cooking_CRUD.pdf.

Code generation that does not require SQL, but is rather based on Java data transfer objects (DTOs), is described in http://sourceforge.net/projects/cleartoolkit/files/ClearToolkitDocs/GeneralDocs/CDB31_release_notes.pdf.

Next, we view a couple of options of auto-generation of AS3 model objects, basis their server side counterparts, and basis an XML Schema.

..................Content has been hidden....................

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