Skip to main content

skip to main content

developerWorks  >  Sample IT projects | Web development  >

Introducing Project Zero, Part 1: Building RESTful services for your Web application

Explore a powerful, yet simple, platform to develop and execute modern Web applications

developerWorks
Document options

Document options requiring JavaScript are not displayed

Discuss

Sample code


Rate this page

Help us improve this content


Level: Introductory

Roland Barcia (barcia@us.ibm.com), Senior Technical Staff Member, IBM 
Steve Ims ( steveims@us.ibm.com), Senior Technical Staff Member, IBM

09 Oct 2007

In this first installment in the Project Zero series, get a hands-on, guided tour of the project's innovations to create, assemble, and deploy powerful Web applications. First, you are introduced to the community-driven Project Zero and its conventions for creating RESTful Web services. Using a step-by-step example, you set up the environment, create a Zero project, build a RESTful service to expose data, test your application, and import a sample application to consume the RESTful services.

Introduction

Project Zero is an IBM incubator project, focused on agile development of Web 2.0 applications following Service-Oriented Architecture (SOA). Web 2.0 applied to SOA allows Web artifacts to extend the reach of SOA. Think of this as Web-extended SOA.

Project Zero introduces a simple environment for creating, assembling, and executing applications based on popular Web technologies. The Project Zero environment includes a scripting run time for Groovy and PHP, with application programming interfaces optimized for producing Representational State Transfer (REST)-style services, integration mashups, and rich Web interfaces. Project Zero is an incubator project started within IBM® that focuses on agile development of the next generation of dynamic Web applications.

Project Zero is now being developed openly using a community-driven commercial development process.

Web-extended SOA is a subset of SOA focused on Hypertext Transfer Protocol (HTTP) and basic RESTful principles. Web-extended SOA advocates the use of design patterns that have made the Web a success, so it makes sense, and is to our collective benefit, to follow this pattern with application design. Benefits include:

  • Scalability, through caching and stateless interactions
  • Simplicity, with prerequisites that are typically HTTP and XML or JavaScript Object Notation (JSON) parsing and rendering
  • A wide-reaching "network effect" from common standards; for example, sites can consume or aggregate Atom or RSS feeds without having to know details about the content

Project Zero's goals are both technical and social. The technical goals are to provide a scalable platform that simplifies application development in three important dimensions:

Create
Simplify development with support for scripting languages (currently Groovy and PHP), conventions that promote RESTful patterns, and catalogs of reusable assets.
Assemble
Enable rapid access and aggregation of disparate services into unified applications, including data flows, orchestrations, and custom mediations.
Deploy
Provide an application-centric run-time environment based upon the well-known and stable Java™ Virtual Machine (JVM), which is optimized for agile development (small footprint, fast restart).

The social goals relate to the development process itself. Zero will be developed in the open, as community-driven commercial development (CD/CD). The user community will be able to observe and influence technical decisions for Zero. Users also have direct access to the Zero development team and the source code itself. This level of transparency for commercial software development is somewhat new for IBM; we hope it leads to a highly effective offering.

In keeping with CD/CD, all the information about Zero is available at www.projectzero.org. This series of articles won't reveal new information about Zero, but will give a structured introduction to the underlying concepts.



Back to top


RESTful services

The term REST describes a design pattern for implementing networked systems. REST is neither a technology nor a standard; it's an architectural style for exposing resources over the Web. The RESTful architecture adheres to several principles:

  • Requests are client-server, and by nature, use a pull-based interaction style. Consuming components pull representations of state from the server.
  • Requests are stateless. Each request from client to server must contain all the information needed to understand the request and cannot take advantage of any stored context on the server.

    REST does not necessarily mean there is no state on the middle tier; it means the state to fulfill the request for a resource is not dependent on that state.

  • Clients and server adhere to a uniform interface. All resources are accessed with a generic interface in the Web-extended SOA world—HTTP along with the HTTP methods: GET, POST, PUT, DELETE.
  • Clients access named resources. The system comprises resources that are named using a URL, such as an HTTP URL.

Representational State Transfer (REST) is a style of software architecture for distributed hypermedia systems, such as the World Wide Web.

REST is the key technology for representing services on the Web. It is key to understand that REST works best when exposing data-based services. These data services can then be mixed and matched to build new applications (often called mashups). The following example shows how a client sees a RESTful service.

With http://<host>/customer:

  • GET: Returns list of customers
  • POST: Creates Customer record

With http://<host>/customer/roland:

  • GET: Returns Roland customer record
  • PUT: Updates Roland record
  • DELETE: Deletes Roland record

In this example, the resource being exposed is Customer. The Customer is represented by the URI /customer. Specific customers are represented by appending an identifier to Customer, such as /customer/ims. The HTTP header methods define the intent of accessing the resource.



Back to top


Project Zero core programming concepts

Project Zero is the foundation of a new, specialized platform that aligns Web 2.0 and SOA to support the next generation of Web-based business applications. This section covers some core concepts. The Project Zero Developer's Guide (see Resources) provides more details on these concepts.

Scripting and Java as the system language

A major trend in simplified development is scripting languages. Zero aims to help reduce the overhead of developing services by providing simplified application program interfaces (APIs) around scripting. The default scripting language is Groovy, which is based on Java and enables Java programmers to easily transition to Groovy. Through an extension module, Project Zero also supports PHP as a scripting language.

Events

Zero is an event-based system. All the key behavior of the system is exposed to the application as a set of events, with the appropriate event state. As an application developer, your main job is to provide a set of handlers that hook into the well-known system events to achieve desired application behavior. Standard Zero events are meaningful activities of interest to applications.

For example, an HTTP request through the system will emit a set of events a developer can write handlers for. Figure 1 shows this concept, with opportunities to hook in events to handle security aspects, or a particular HTTP method (GET | POST) event. (For more on event handling, see the event-processing section of the Project Zero Developer’s Guide .


Figure 1. Events
Events

Global context

Event handlers in Project Zero do not have explicit input and output parameters, such as request and response, respectively. Because all event handlers in Project Zero cannot maintain a variable state across invocations and are therefore stateless, Project Zero provides the global context as a means to access and maintain all states. The global context provides all of the interesting data about the current event to the application, as well as the mechanism to store and share information between components of the application.

The global context is scoped and divided into a set of zones, where each zone maintains data with different visibility and with a different life cycle, as shown in Figure 2. For example, the user zone contains the session state for a given client, is visible only for that client, and maintains the data until the user becomes inactive.

The request zone contains the state of the currently active request, is visible only to components executed for that request, and the state is only maintained until the end of that request.


Figure 2. Global context
Figure 2. Global context


Back to top


Conventions and the application directory structure

The Zero environment provides several conventions that, when followed, greatly simplify the development of Zero applications and minimize the configuration information that must be specified. The goal of Zero is to have as little configuration information as possible. Some of the conventions are common and expected. For example, you can place a script in the public folder of your application and run that script in response to an HTTP resource with no configuration data.

Other conventions are more tailored to a particular pattern. Figure 3 shows an example of storing a Groovy script under a particular folder. This approach automatically registers the methods in this folder to respond to HTTP REST events. Later in this article, you'll learn how the RESTful pattern is used to quickly develop RESTful services to expose your data. For more information, see the Virtual Directory section of the Project Zero Developer's Guide .


Figure 3. Virtualized directories
Figure 3. Virtualized directories


Back to top


Example scenario

You're almost ready to build your first RESTful service using the Zero platform. Let's walk through the concepts first, using the following example.

Overview

Throughout this series you will build on a common example to learn various concepts. The theme for the example focuses on rebate incentives. Consumers are always looking to qualify for incentive rebates, and providers need to make incentives available. The use case diagram in Figure 4 shows the various activities. In this article, you'll focus on the incentive provider role and the incentive management use case.


Figure 4. Use case
Figure 4. Use case

A provider will need a way to enter and maintain incentives into the system; an incentive is the major piece of data that we're interested in. Figure 5 shows the data model for the incentive application.


Figure 5. Data model
Figure 5. Data model

You will start with a single table. In future articles, we'll expand the data model to have relationships, and explore more complex data using the REST paradigm.

Design your RESTful endpoints

Now that the data set is outlined, you'll begin by mapping your data onto a RESTful namespace. It's usually very helpful to create a table for a particular entity to map the resource. Table 1 shows an example of a RESTful mapping to our resource. You will be building this RESTful service.


Table 1. REST Data
Resource URI Method Representation Description
Incentive list /incentiveGETJSON array of objectsRetrieve a list of incentives
Incentive /incentivePOSTJSON objectCreate a new incentive
Incentive /incentive/<incentiveId>GETJSON objectRetrieve an individual incentive
Incentive /incentive/<incentiveId> PUT JSON object Update a single incentive
Incentive /incentive/<incentiveId> DELETE Delete a single incentive

JSON is the chosen format to represent the data because we'll be using a rich Internet application (RIA) as a front end to the system. Most Ajax-based toolkits understand JSON very well, since JavaScript is the main programming language for Ajax in the browser. (For more details about JSON, see Resources.)

System requirements

To run the samples in this article, you will need the following:

  • Eclipse 3.2 or higher. We used the Eclipse 3.3 release.
  • Project Zero Java and Groovy Plug-in for Eclipse.

    This example was built using the M1 Release of Zero. Make sure you set your Eclipse Update Site to http://www.projectzero.org/update/zero.eclipse.M1.

    You will not need the PHP Plug-in for this exercise.

  • The download zip file attached to this article. Extract it to your C: drive.
  • Derby Network Database.
  • Derby Plug-in for Eclipse.
  • Firefox browser.

    Although you can use IE for this exercise, we're using a Firefox plug-in to test the POST/PUT/DELETE requests. If you use IE, you can test the GET requests in the browser and then test the services using the UI client you'll import later in the article.

  • POSTER plug-in for Firefox.

Other useful tools are:



Back to top


Build your first RESTful service with Project Zero

Now that we've covered a bit about RESTful mapping, it's time to build the example.

  1. First, you'll create a Zero project, as follows.
    1. From the Eclipse Main Menu, select New > Project as shown in Figure 6.

      Figure 6. Create a new project
      Figure 6. Create a new project

    2. From the Project Wizard, select Zero > Project Zero Application. Click Next, as shown in Figure 7.

      Figure 7. Project Zero Application
      Figure 7. Project Zero

    3. Name the project RebateIncentiveServices, and click Finish.

      Figure 8. RebateIncentiveServices
      Figure 8. Rebate Incentive Services

  2. In the next step you'll examine the Project Zero directory structure and tooling.
    1. Figure 9 gives an overview of several important directories in a Zero project. The highlighted folders are the different areas you can code. Most of these directories are located under the app folder of the project. In the Project Explorer view of the Java perspective, these directories appear as Java source folders.

      Figure 9. Application directory structure
      Figure 9. Application directory structure

      Java
      The Java folder is where you can provide Java code to be used for your application. You can write Java-based handlers and place them there.
      Public
      The public folder is where you put all artifacts you want to be served to a browser. Examples include HTML files, JavaScript files, Groovy files, and templates that can be executed at the browser, or PHP scripts.
      Resources
      The /app/resources folder contains scripts (Groovy or PHP) that will be invoked in response to RESTful invocations. They respond to the various HTTP methods. Scripts in this directory are automatically registered as handlers. You'll be using this directory in the example.
      Errors
      The /app/errors folder will contain scripting template files, such as Groovy templates that are rendered automatically based on errors. The naming pattern of the file defines what response is rendered. For example, error5xx.gt is a Groovy template that will be invoked in response to a server 500 error.
      Scripts
      The /app/scripts directory allows you to define Groovy scripts or classes that are private in nature (much like the Java directory). Here you can define GroovyBeans or methods that can be invoked by public or resource Groovy scripts. This approach lets you follow a model-view-controller (MVC) pattern when building your application.
      Views
      The /app/views directory is where you put template files that can be rendered in response to some event. Unlike scripts in the public directory (which are run based on direct URL access), these views can be executed in response to another script. A controller script can access some back-end logic, and then forward control to the view scripts to render it.

      You can get more details about the application directory structure in the Project Zero Developer’s Guide (see Resources).

    2. Figure 10 highlights the Config directory, which contains important files needed by your Zero application.

      Figure 10. Config directory
      Figure 10. config directory

      Ivy.xml
      The Zero platform uses the Ivy framework to maintain dependencies. Zero applications are packaged into packages. Your ivy.xml allows you to define which packages you depend on. Zero packages are stored in an Ivy repository and the Ivy run time resolves these packages.

      Ivy is a tool for managing (recording, tracking, resolving, and reporting) project dependencies. It is characterized by:

      • Flexibility and configurability

        Ivy is essentially process-agnostic and is not tied to any methodology or structure. It provides the necessary flexibility and configurability to be adapted to a broad range of dependency management and build processes.

      • Tight integration with Apache Ant

        While available as a stand-alone tool, Ivy works particularly well with Apache Ant, providing several powerful Ant tasks ranging from dependency resolution to dependency reporting and publication.

      See Apache incubator, or the Dependency and Packaging section of the Project Zero Developer's Guide, for more information about Ivy.

      logging.properties
      The logging.properties file Is where you can configure Java logging properties. Zero uses Java Development Kit (JDK) logging. (Get more information on Zero logging in the Logging section of the Project Zero Developer's Guide.)
      Zero.config
      The zero.config file defines the main configuration file in a Zero application. It is where you configure artifacts such as handlers, security, data sources, and any other configuration you need. You can have more than one zero.config file. You'll define some database configuration in the example using the zero.config. Because the example will use the /app/resources folder, you will not configure handlers explicitly, but rely on Zero's predefined handlers for REST invocation. (For more details on configuration, see the Configuration section of the Project Zero Developer's Guide.)

      Figure 11 highlights aspects of the Eclipse tooling. The Zero plug-in provides tools that help you to manage your dependencies. It will allow you to manage local and remote repositories the Ivy framework can use to download and resolve dependencies of your Zero application. Resolving a dependency means adding a package to your Zero application.



      Figure 11. Dependency management
      Figure 11. Dependency management

      Manage repositories
      Provides a tool to view your local repository and download packages from remote repositories, as shown in Figure 12.


      Figure 12. Manage repository
      Figure 12. Manage repository

      Resolve icon
      The resolve icon will resolve dependencies within your workspace from both your local and configured remote repositories.
      Resolve menu item
      The resolve menu item will resolve dependencies from your local repositories.
  3. In order to build your RESTful service, you need to create a table in the database. A database-setup script is provided for the example. In the exercise, use the network version of Derby. (Remember, we've also installed Derby Plug-in for Eclipse.)
    1. Right-click RebateIncentiveServices and select Import, as shown in Figure 13.

      Figure 13. Import artifacts
      Figure 13. Import artifacts



    2. Figure 14. File system
      Figure 14. File system

    3. Assuming you extracted the sample code download zip file to the C drive, C:\ProjectZeroArticleSeries\Part1 should be in the From directory field. The Into folder field should be RebateIncentiveServices. Select the dbscripts folder, as shown in Figure 15, and click Finish.

      Figure 15. DB scripts
      Figure 15. DB scripts

    4. You should see a folder in the project called dbscripts. Within the folder, open Incentives.sql. The script creates the incentive table and insert two records into the table.

      Figure 16. Incentives.sql
      Figure 16. Incentives.sql

      The script is shown in Listing 1.



      Listing 1. Database scripts
                                  
      CONNECT 'jdbc:derby://localhost:1527/INCENTIVEDB;create=true;';
      
      drop
                                  table Incentive;
      
      create
                                  table Incentive (
      		incentiveid INTEGER
                                  NOT
                                  NULL GENERATED ALWAYS AS IDENTITY,
      		name VARCHAR(256) NOT
                                  NULL,
      		description VARCHAR(256) NOT
                                  NULL,
      		providername VARCHAR(50) NOT
                                  NULL,
      		incentivetype VARCHAR(128),
      		validfrom TIMESTAMP,
      		validto TIMESTAMP,
      		website VARCHAR(256)
      );
      
      alter
                                  table Incentive ADD
                                  CONSTRAINT Incentive_PK PRIMARY
                                  KEY (incentiveid);
      
      INSERT
                                  INTO Incentive (name,description, providername,incentivetype,validfrom,validto,website) 
      |-------20--------30--------40--------50--------60--------70--------80--------9|
      |-------- XML error:  The previous line is longer than the max of 90 characters ---------|
                      values ('Key Account Energy Efficiency Grant Program',
      'Alameda P&T offers its commercial customers grants of up to $25,000
       for energy efficient building design and equipment in new commercial
       construction, or other approved unique energy efficient projects.',
      'Alameda Power and Telecom','Energy',
      TIMESTAMP('2007-06-22 00:00:00.000'),
      TIMESTAMP('2007-10-30 00:00:00.000'),
      'http://www.alamedapt.com/electricity/com_savings.html' );
      
      INSERT
                                  INTO Incentive (name,description, providername,incentivetype,validfrom,validto,website) 
      |-------20--------30--------40--------50--------60--------70--------80--------9|
      |-------- XML error:  The previous line is longer than the max of 90 characters ---------|
                      values (
      'Power Management for Personal Computer (PC) Networks',
      'Avista Utilities Power Management for Personal Computer (PC) 
      Networks offers incentives to commercial customers.',
      'Avista Utilities','Energy',
      TIMESTAMP('2007-09-01 00:00:00.000'),
      TIMESTAMP('2008-06-30 00:00:00.000'),
      'http://www.avistautilities.com/saving/conservation/power_management.asp'  );
      
      

    5. Assuming you installed the Apache Derby Plug-in for Eclipse, right-click the project, as shown in Figure 17, and select Apache > Add Apache Derby nature.

      Alternatively, you can start Derby using the command line and run ij manually.



      Figure 17. Apache Derby Plug-in


    6. Right-click the project again, and select Apache Derby > Start Derby Network Server, as shown in Figure 18.

      Figure 18. Start Derby network server
      Figure 18. Start Derby Network Server

    7. Examine the console to ensure the database is up and running.

      Figure 19. Running Derby database
      Figure 19. Running Derby Database

    8. Right-click the Incentive.sql script and select Apache Derby > Run sql script running 'ij'. (This is the command-line tool for running Derby database scripts.)

      Figure 20. Running SQL scripts using ij
      Figure 20. Running SQL scripts using ij

    9. Examine the console to ensure the table is created and the records are inserted.

      Figure 21. Database script results
      Figure 21. Database script results

  4. Earlier, you looked at the ivy.xml file. When creating a Zero project, you get the core Zero package and the Webtools package. The core contains the necessary libraries to create event handlers and RESTful services, and to interact with the global context, and security. The Web Tools project contains a set of useful tools, such as a default index page, a request inspector, error-finding tools, and others. You can find more details in the Developer Web tools section of the Project Zero Developer's Guide (see Resources).

    In this step you add two packages to the application. The data access libraries, as well as the Derby client Java Archive (JAR) files, need to contact the database.

    1. Open the ivy.xml file, as shown in Figure 22.

      Figure 22. ivy.xml
      Figure 22. ivy.xml

    2. This step opens the ivy.xml editor. Click Add, as shown in Figure 23.

      Figure 23. Add Zero Packages
      Figure 23. Add Zero Packages

    3. Find the zero:zero.data package, as shown in Figure 24. Ensure the filter is set to Latest minor version and click OK.

      Figure 24. zero.data package
      Figure 24. zero.data package

    4. Repeat the previous step and add org.apache.derby:derbyclient. This step adds the Java Database Connectivity (JDBC) client JARs needed to connect to Derby.

      Figure 25. Derby client
      Figure 25. Derby client

    5. Select the Update dependencies icon. The tool reads the ivy.xml and looks for the latest version of the remote and local repositories. (Later in this example, you'll use the Resolve option.)

      Figure 26. Update dependencies
      Figure 26. Update Dependencies

    6. Click OK to allow the tool to check for remote versions.

      Figure 27. Select dependencies to run
      Figure 27. Select Dependencies to Run

  5. Now that the application has the necessary libraries, you need to set up the database configuration at run time. The zero.config file uses an INI style of configuration. The content of a config/zero.config file is organized into "stanzas" of related key/value pairs.

    Stanzas are associated with directives, such as "store to the global context" and "include another configuration file." Although one of Project Zero's goals is to minimize the amount of configuration needed to run an application, some configuration is needed.

    1. Expand the Config folder and open the zero.config file, as shown in Figure 28.

      Figure 28. zero.config
      Figure 28. zero.config

    2. Figure 29 shows the stanza to be added.

      Figure 29. Configure database
      Figure 29. Configure database

      Notice the stanza begins with a directive. In this case, we point to a location where we weigh the key/value pairs to be stored. The test is printed in Listing 2. You can also paste it from C:\ProjectZeroArticleSeries\Part1\dbconfig.txt.



      Listing 2. Database configuration
                                  
      [/app/db/incentiveDB/config]
      class=org.apache.derby.jdbc.ClientDataSource
      serverName=localhost
      portNumber=1527
      databaseName=INCENTIVEDB
      connectionAttributes=create=true
      

      The Project Zero data libraries will read this configuration when accessed. Notice in Figure 29 the highlighted incentiveDB name after the /app/db. This will be the name used in the code. You'll see this in a bit when you build RESTful services.



Back to top


Create a RESTful service to expose data

At this point it's time to build the RESTful service to expose the incentive data. There are several ways to build services in Project Zero. One goal is to leverage the built-in support for automatically exposing Groovy scripts as a RESTful service.

You will be using the Eclipse plug-in for Project Zero. Keep in mind that these conventions are also available outside of Eclipse using the command-line version of Zero. You will likely discover that you can very quickly create REST-based services using Project Zero.

Create a Groovy script

The Groovy script will match the name of the URL you want your REST service to be invoked by. For /resources/incentive, you need a file called incentive.groovy.

  1. Right-click on the folder /app/resources and select New > File, as shown here.

    Figure 30. New file
    Figure 30. New File

  2. Name the file incentive.groovy.

    Figure 31. incentive.groovy
    Figure 31. incentive.groovy

  3. Click Yes if prompted to add Groovy support to the project.

    Figure 32. Groovy support
    Figure 32. Groovy support

Manage incentives

To manage incentives, you want to provide the ability to list all incentives; get individual incentives; and create, update, and delete incentives. The first task is to create the ability to list incentives. Clients can invoke /resources/incentive to see a list of incentives.

  1. Open the incentive.groovy file you just created.

    Figure 33. Incentive.groovy
    Figure 33. Incentive.groovy

  2. If you enter script code directly, you'll create a script that responds to any HTTP method. However, we want to have different actions based on HTTP methods. You can define special handler methods that will automatically respond to the HTTP method. The table below summarizes these callbacks.

    URI HTTP method Groovy method Description
    /incentive GET onList() Return a list of incentives
    /incentive POST onCreate() Create a new incentive(s) and return the resource location
    /incentive PUT onPutCollection() Update a set of incentives
    /incentive DELETE onDeleteCollection() Delete a set of incentives
    /incentive/<incentiveId> GET onRetrieve() Retrieve an incentive by ID
    /incentive/<incentiveId> PUT onUpdate() Update an individual incentive
    /incentive/<incentiveId> DELETE onDelete() Delete an Individual incentive
    /incentive/<incentiveId> POST onPostMember() Post an individual member to the location you choose


    For this article you'll build the 1st, 2nd, 5th, 6th, and 7th callbacks.

  3. To build and test the list use-case first, add the snippet of code shown in Listing 3. Or, you can paste it from C:\ProjectZeroArticleSeries\Part1\list.txt.

    Listing 3. Incentive list
                            
    import zero.data.groovy.Manager;
    
    def onList()
    {
    	def dm = Manager.create("incentiveDB");
    	request.json.output = dm.queryList("select * from incentive");
    	request.view="JSON";
    	render();
    }
    

    This code:

    • Uses the Manager object from Project Zero's data API. The Manager object provides convenient methods to execute SQL queries. There are two versions: a Java version and a Groovy version. Although the Java version works in Groovy, the Groovy version takes advantage of Groovy shortcuts, such as passing GStrings as input, use of closures, and others. When issuing a create, we pass in the string used in the configuration /app/db/incentiveDB/config.

    • Selects the full list from the Manager and assigns it to request.json.output. This may seem like we are assigning the results to a regular Groovy variable, but much more is happening here. Remember, all state is maintained in the global context. Project Zero provides a Java API for storing and retrieving data from the GlobalContext.

      For example, the code

      String data = GlobalContext.get("/request/myData");

      gets a string from the request zone of the global context. Project Zero groovy scripts further add build-implicit support for global context data. They have predefined four variables for each zone (app, user, request, and event). So in Groovy, the following code:

      request.myData = "Hello"

      is the same as
      GlobalContext.put("/request/myData","Hello);

      Taking advantage of these shortcuts in Groovy reduces the amount of code you need to write. In the example, we are storing a list into the request zone under /request/json/output. See the Project Zero Developer's Guide (Resources) for more details about the global context.

    After storing the result in the GlobalContext, another object called the ViewEngine is used. Project Zero supports various ways of rendering result context. You can explicitly write to the output stream (direct render). Application code and event handlers can write directly to the response entity using OutputStream (/request/outputstream) and PrintWriter (/request/writer) objects.

    The following is a Java example:

    // Content of a Java class
    PrintWriter writer = (PrintWriter) GlobalContext.get("/request/writer");
    writer.println("Hello World.");

    The default output for all Groovy scripts (including templates) is the response writer, allowing application developers to write directly to the response with the println method. Refer to the Rendering Results section of the Project Zero Developer's Guide for details on rendering.

    Project Zero provides a library of renderers for common response handling. Invoking a renderer generally involves the following steps:

    1. Set the value of /request/view in the global context to the corresponding renderer.
    2. Set additional renderer-specific values into the GlobalContext .
    3. Invoke
      zero.core.views.ViewEngine.render() 

      From within a Groovy REST Handler though, calling render() alone will result in calling the View Engine renderer.

    zero.core includes View, Error, XML, and JSON renderers. You can also add the Atom package, which contains an Atom renderer.

    The example uses the JSON handler. Another alternative is to use a Groovy template. You can store a Groovy template under the /app/views folder and set request.view to that name of the template.

    As you can see, these conventions drastically reduce the amount of code you need to write.

Test by launching the application

You can now test onList very easily by launching the application.

  1. Right-click the project and select Run as > Project Zero Application, as shown in Figure 34.

    Figure 34. Run Project Zero application
    Figure 34. Run Project Zero           application

  2. Examine the console. The application should have launched and be listening on port 8080.

    Figure 35. Application running on port 8080
    Figure 35. Application running on Port           8080

  3. Launch a browser and go to http://localhost:8080, which should bring up the default zero page. (This is one of the tools in the Web Tools library previously mentioned.) You will see the default index page. If you add your own index.html file, yours will take precedence over the default.

    Figure 36. Default home page
    Figure 36. Default home page

  4. Launch the Firefox Poster tool by selecting View > SideBar > Poster.

    Figure 37. Run Poster plug-in
    Figure 37. Run Poster Plug-in

  5. Enter http://localhost:8080resources/incentive for the URL and click GET.

    Figure 38. GET incentives
    Figure 38. GET incentives

  6. The Response window should pop up with the response payload, as shown here. The format will be a JSON array with each entry being a JSON object.

    Figure 39. JSON result
    Figure 39. JSON result

  7. You can optionally test the XML rendering as well. Change the view type to XML, as shown in Listing 4.

    Listing 4. XML result
                            
    def onList()
    {
    		def dm = Manager.create("incentiveDB");
    request.xml.output = 
        dm.queryList("select * from incentive");
    		request.view="XML";
    		render();
    }
                        

  8. Click GET again from the Poster plug-in to see the result in XML, as shown in Figure 40.

    Figure 40. XML results
    Figure 40. XML results

    Be sure to change the code back to JSON.

Accessing a service

Next, you will create the onRetrieve method to access a specific RESTful service by passing its identifier.

  1. Inside the incentive.groovy file, enter the onRetrieve method and code as shown in Figure 41, or Listing 5, below. You can alternatively paste it from C:\ProjectZeroArticleSeries\Part1\retrieve.txt.

    Figure 41. Retrieve incentive
    Figure 41. Retrieve incentive



    Listing 5. Retrieve single incentive
                            
    def onRetrieve()
    {
    def dm = Manager.create("incentiveDB");
    request.json.output = dm.queryFirst(
    "select * from incentive where incentiveid = 
     ${request.params.incentiveId[0].get()}");
    	request.view="JSON";
    	render();
    } 
    

    Similar to what you did with the onList method, now you'll create an instance of the Manager and execute a query. This example has a few important points:

    • The method will get executed by executing the following URI: /resources/incentive/1. 1 is the identifier of the desired incentive. To pass this into the where clause you need to access it from the URI. Zero automatically populates the GlobalContext with the path information. For example, request.params.incentiveId[0] will return 1. The table below gives a few examples of how you can access parameters.

      URI parameters
      /incentive/1 request.params.incentiveId[0] == 1
      /incentive/1/provider?location=NJ request.params.location[0] == NJ


    • The built-in support for Groovy GStrings within the query is being used. GString allows you to use an expression language to refer to variables within a string literal. So, the query string literal, shown here:
      select * from incentive where incentiveid = ${request.params.incentiveId[0].get()} 
      |-------20--------30--------40--------50--------60--------70--------80--------9|
      |-------- XML error:  The previous line is longer than the max of 90 characters ---------|
      

      can have access to the GlobalContext directly. Alternatively, there are APIs in the data access libraries that allow you to pass in Plain Old Java Objects (POJOs) and use :property style of inputs, as well as support for ? type parameters. See the data section JavaDocs for Project Zero and the Data Access section of the Project Zero Developer's Guide (Resources), for more information.
  2. Save the file. Back in the Firefox Poster tool, enter the URL http://localhost:8080/resources/incentive/1 and click GET, as shown in Figure 42. The result should be a JSON object with a single record.

    Figure 42. JSON result for single incentive
    Figure 42. JSON result for single incentive

Adding to the example

Now you'll add the onCreate(), onUpdate(), and onDelete() methods.

  1. Enter the code in Listing 6 into incentive.groovy, or paste it from C:\ProjectZeroArticleSeries\Part1\updateMethods.txt.

    Listing 6. Create, update, and delete incentive
                            
    def onCreate()
    {
    	def dm = Manager.create("incentiveDB");
    	def incentive = zero.json.JsonType.fromData(request.input.get()).getJson();
    	def newKey = dm.insert("insert into incentive
     (name,description,providername,incentivetype,validfrom,validto,website)
     values(${incentive.name},${incentive.description},${incentive.providername},
    ${incentive.incentivetype},${incentive.validfrom},${incentive.validto},
    ${incentive.website})",['incentiveid']);
        
    	locationUri = zero.core.utils.URIUtils.getAbsoluteUri(request.path) + '/' + newKey
        request.headers.out.Location = locationUri
        request.status = HttpURLConnection.HTTP_NO_CONTENT
    }
    
    def onUpdate()
    {
    	def dm = Manager.create("incentiveDB");
    	def incentive = zero.json.JsonType.fromData(request.input.get()).getJson();
    	dm.update("update incentive set name =
     ${incentive.name},description = $incentive.description ,providername =
     $incentive.providername,incentivetype=$incentive.incentivetype,validfrom=
    $incentive.validfrom,validto=$incentive.validto,
    website=$incentive.website where
     incentiveid=${request.params.incentiveId[0].get()}");
    	request.status = HttpURLConnection.HTTP_NO_CONTENT
    	
    } 
    
    def onDelete()
    {
    	def dm = Manager.create("incentiveDB");
    def newKey = dm.update("delete from incentive where incentiveid=
    ${request.params.incentiveId[0].get()}");
    	request.status = HttpURLConnection.HTTP_NO_CONTENT;
    }
    

    In this code:
    • The data access APIs have methods to execute updates. onDelete and onUpdate use the generic update method that lets you pass any database Insert, Update, and Delete statement. onCreate() also uses a specially defined insert method that will return the primary key. This is useful in situations when the database generates the primary key.
    • The onCreate method sets the URL of the newly created resource. This is mandated by the REST pattern.
    • All the updates set the return type to no Content.
    • Use of the specialized zero.json.JsonType.fromData translates a message body into a Java representation of a JSON object.
  2. Using the Poster, enter http://localhost:8080/resources/incentive. Inside Content to Send, add the JSON object in Listing 7 (or paste it from C:\ProjectZeroArticleSeries\Part1\insertUpdatePayload.txt).

    Listing 7. Create JSON payload
                            
    {"providername":"Hawaii Gas Company ",
    "website":"http://www.hawaiigas.com/rebate/commercial.html",
    "description":"Existing Commercial Utility Gas customers of The Gas Company 
    may apply for a rebate for new gas equipment..",
    "name":"Commercial Switch to Gas Program",
    "incentivetype":"Energy","validto":"2007-09-01 13:01:23.123456",
    "validfrom":"2008-06-30 13:01:23.123456"}
    

  3. Select POST, as shown in Figure 43.

    Figure 43. POST incentive
    Figure 43. POST Incentive

  4. The response should be 204, and the location should be set to the new resource: http://localhost:8080/resources/incentive/3, as shown in Figure 44.

    Figure 44. POST Result
    Figure 44. POST Result

  5. Close the response and go back to the Poster tool. Enter the new URL http://localhost:8080/resources/incentive/3, and click GET to verify the item was created.

    Figure 45. GET created incentive
    Figure 45. GET created incentive

  6. You should get the response matching the record you created.

    Figure 46. GET new incentive
    Figure 46. GET new incentive

  7. Repaste the payload from the C:\ProjectZeroArticleSeries\Part1\insertUpdatePayload.txt.
  8. Change the incentiveType to Gas, as shown in the JSON object in Listing 8.

    Listing 8. Update JSON payload
                            
    {"providername":"Hawaii Gas Company ",
    "website":"http:\/\/www.hawaiigas.com\/rebate\/commercial.html",
    "description":"Existing Commercial Utility Gas customers of The Gas
     Company may apply for a rebate for new gas equipment..",
    "name":"Commercial Switch to Gas Program",
    "incentivetype":"Gas",
    "validto":"2007-09-01 13:01:23.123456",
    "validfrom":"2007-09-01 13:01:23.123456"}
    

  9. Enter the URL of the resource http://localhost:8080/resources/incentive/3 with the payload and click PUT.

    Figure 47. PUT incentive
    igure 47. PUT incentive

  10. You should get a 204 response.

    Figure 48. 204 result
    Figure 48. 204 result

  11. Issue another GET on the resource to ensure the update was successful.

    Figure 49. Delete incentive
    Figure 49. Delete incentive

  12. Finally, on the URL http://localhost:8080/resources/incentive/3, click Delete. You should get a 204 response, as shown here.

    Figure 50. 204 result for Delete
    Figure 50. 204 result for Delete

  13. Issue a GET. You should now get an empty result. (Future articles in this series will add error handling into the code.)


Back to top


Import a sample RIA client

Now that the RESTful services are functional, you're going to import a sample RIA that will consume the RESTful services. This article does not focus heavily on the client; details about the imported client and how REST is one of the foundations for mashup applications are briefly covered.

A subsequent article in this series will discuss the UI support in Zero.
Currently Project Zero contains the Dojo Toolkit 4.3. For the example we'll be using a Dojo-based application. You'll use the base Dojo support with some imported helpers.

To add the Dojo package to the project:

  1. Much like you did previously, open ivy.xml under the Config folder and add dojo:dojo(0.4.3) to your application.

    Figure 51. Add Dojo package
    Figure 51. Add Dojo package

  2. Right-click on the project and select Zero Tools Resolve. This will resolve Dojo from the local repository.

    You can also use the Update Dependencies icon to load from the Remote repository, as you did before.



    Figure 52. Resolve Dojo
    Figure 52. Resolve Dojo

  3. Stop the application from the console view by clicking Stop, as shown in Figure 53. Unlike code changes, when adding new libraries or updating the zero.config a restart of the application is required.

    Figure 53. Stop application
    Figure 53. Stop application

At this point you can import and examine the code:

  1. Right-click on the public folder of the project and select Import.

    Figure 54. Import UI code
    Figure 54. Import UI code

  2. In the From directory, enter C:\ProjectZeroArticleSeries\Part1\webapp. Check the webApp box and ensure the Into folder is public, as shown in Figure 55.

    Figure 55. Import Wizard
    Figure 55. Import Wizard

Let's briefly examine the code:

  1. Open the index.html, as shown in Figure 56.

    Figure 56. Examine index
    Figure 56. Examine index

  2. We have built the incentive client as a widget. Building RESTful clients as Dojo widgets is fundamental to providing modular clients that can be mashed together on the glass to provide integration. Figure 57 shows how the incentive widget is a single declaration on the page.

    The example also has another added piece of JavaScript to simulate another widget. That widget will subscribe to the incentive widget and display the RESTful events.



    Figure 57. Two widgets
    Figure 57. Two widgets

  3. Under the zero.incentive.widget folder, you will find the code needed to build a Dojo widget. A Dojo widget is primarily made up of an HTML template, a CSS file for style, and a JavaScript function. Building a Dojo widget is a topic for a whole separate article. See Resources for information on the Dojo Toolkit and widgets. Figure 58 highlights the widget files.

    Figure 58. Dojo widget code
    Figure 58. Dojo widget code

  4. Listing 9 highlights a piece of the IncentiveWidget.js file, especially the way the Dojo widget invokes our RESTful service. A sample JSONRestService JavaScript class is provided, to be examined in a moment. The sample shows how the widget invokes the listData method to invoke the service. Another important aspect is use of the Dojo publish and subscribe functions to emit events about when the RESTful services are invoked. This is how the neighboring widgets discover when the data is accessed.

    Keep in mind that some data may be secure in nature. Pure JavaScript mashups from untrusted sources can be highly dangerous. A subsequent article in this series will examine more secure patterns.



    Listing 9. JSON rest call
                            
    postCreate: function(){
    		
    		dojo.debug("postCreate, setting subscriptions");
    		
    		//Load Widget
    		dojo.event.topic.subscribe(this.inputTopic, this, this.listIncentives);
    		
    		//Get Incentives Events
    		dojo.event.topic.subscribe(this.getAllTopic, this, this.bindIncentives);
    
    listIncentives:function (){
    		zero.rest.JsonRestService.listData(this.restUri,this.getAllTopic,this.errorListTopic);
    |--10--------20--------30--------40--------50--------60--------70--------80--------9|
    |-------- XML error:  The previous line is longer than the max of 90 characters ---------|
    	},
    	bindIncentives:function(data){
    			dojo.debug("Binding to -> " + this.incentiveTable);
    			for(i = 0; i < data.length ; i++)
    			{
    				data[i].validto = dojo.date.fromIso8601 (data[i].validto);
    				data[i].validfrom = dojo.date.fromIso8601 (data[i].validfrom);
    |--10--------20--------30--------40--------50--------60--------70--------80--------9|
    |-------- XML error:  The previous line is longer than the max of 90 characters ---------|
    				data[i].website = '<a href=\"' +
      data[i].website + '\" target="_blank">' + data[i].website + '</a>';
    			}
    			this.incentiveTable.store.setData(data);
    			this.showIncentiveFormButton.show();
    			this.editIncentiveFormButton.show();
    			this.deleteIncentiveButton.show();	
    	}
    

  5. Open the JsonRestService.js file under the zero.rest folder, as shown in Figure 59. In the code, notice a callback method for all our RESTful events. We use the dojo.io.bind() method and dojo publish/subscribe to notify when events are done. This code can also be seen in the Developer's Guide.

    Figure 59. JsonRestService.js
    Figure 59. JsonRestService.js

Now, to run the client application:

  1. Re-launch the application. You can do this using the Eclipse run arrow, as shown below.

    Figure 60. Re-launch application
    Figure 60. Re-launch application

  2. Launch your browser to http://localhost:8080. Notice that our index page gets invoked instead of the Web Tools index page. The incentive widget has called the list data, and the neighbor widget displays the event.

    Figure 61. Application loaded
    Figure 61. Application loaded

  3. Add a new incentive by clicking Add New Incentive.

    Figure 62. Add new incentive
    Figure 62. Add new incentive

  4. Enter some data (you can using the JSON payload as an example, or look at Figure 63).

    Figure 63. Add new incentive form
    Figure 63. Add new incentive form

  5. Click Submit. The newly created resource should have been added to the table.

    Figure 64. Update incentive
    Figure 64. Update Incentive

  6. Highlight the newly created resource and click Edit Selected Incentive.

    When selecting the resource, the onRetrieve method is executed to get the individual resource.

  7. Update any of the fields and click Submit.

    In version 4.3 of Dojo, there is a small bug with the drop-down date widget displaying form data. Check the Dojo site for updates, or populate the widget directly.



    Figure 65. Dojo bug in 4.3
    Figure 65. Dojo bug in 4.3

  8. Finally, highlight the resource and click Delete Selected Incentive.

    Figure 66. Delete incentive
    Figure 66. Delete Incentive

  9. The list should be updated, as shown in Figure 67.

    Figure 67. After deleting incentive
    Figure 67. After Delete

  10. Examine the neighbor widget as it displays the REST event and payload.

    Figure 68. Mashed-up wizard
    Figure 68. Mashed-up wizard

Congratulations on building your first RESTful service with Project Zero!

Summary

Share this...

digg Digg this story
del.icio.us Post to del.icio.us
Slashdot Slashdot it!

In this article you are introduced to Project Zero, a new platform for building Web-oriented applications or Web-extended SOA. You learned about Project Zero's architecture and how to build RESTful services to facilitate Web 2.0 development. Our relatively simple example used an often-executed pattern.

Stay tuned for Part 2, which will show you how to build RESTful services for more complex data, and introduce other parts of the platform that can help assemble, secure, and deliver fully functional Web-extended SOA.




Back to top


Download

DescriptionNameSizeDownload method
sample codei-zero1code.zip13KBHTTP
Information about download methods


Resources

Learn

Get products and technologies

Discuss


About the authors

Photo: Roland Barcia

Roland Barcia is a Senior Technical Staff Member and lead Web 2.0 architect for IBM Software Services for WebSphere. He is a co-author of IBM WebSphere: Deployment and Advanced Configuration and the forthcoming Persistence within the Enterprise .


Steve Ims

Steve Ims is a senior technical staff member and lead for the Project Zero run-time "core." You'll find Steve on the Project Zero forums.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


12345
Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot