 | 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.
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:
 | | 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.
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
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
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
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
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
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 | /incentive | GET | JSON array of objects | Retrieve a list of incentives | | Incentive | /incentive | POST | JSON object | Create a new incentive | | Incentive | /incentive/<incentiveId> | GET | JSON object | Retrieve 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:
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.
- First, you'll create a Zero project, as follows.
- From the Eclipse Main Menu, select New > Project as shown in
Figure 6.
Figure 6. Create a new project
- From the Project Wizard, select Zero > Project Zero Application. Click
Next, as shown in Figure 7.
Figure 7. Project Zero
Application
- Name the project
RebateIncentiveServices, and click Finish.
Figure 8.
RebateIncentiveServices
- In the next step you'll examine the Project Zero directory structure and tooling.
- 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
- 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).
- Figure 10 highlights the Config directory, which contains important files needed by your Zero
application.
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
- 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
- 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.
- 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.)
- Right-click RebateIncentiveServices and select Import, as shown in
Figure 13.
Figure 13. Import artifacts
-
Figure 14. File system
- 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
- 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
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' );
|
- 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
- Right-click the project again, and select Apache Derby > Start
Derby Network Server, as shown in Figure 18.
Figure 18. Start Derby network server
- Examine the console to ensure the database is up and running.
Figure 19. Running Derby database
- 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
- Examine the console to ensure the table is created and the records are
inserted.
Figure 21. Database script results
- 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.
- Open the ivy.xml file, as shown in Figure 22.
Figure 22. ivy.xml
- This step opens the ivy.xml editor. Click Add, as shown in Figure 23.
Figure 23. Add Zero Packages
- 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
- 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
- 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
- Click OK to allow the tool to check for remote versions.
Figure 27. Select dependencies to run
- 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.
- Expand the Config folder and open the zero.config file, as shown in
Figure 28.
Figure 28. zero.config
- Figure 29 shows the stanza to be added.
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.
 |
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.
- Right-click on the folder /app/resources and select New > File, as
shown here.
Figure 30. New file
- Name the file
incentive.groovy.
Figure 31. incentive.groovy
- Click Yes if prompted to add Groovy support to the project.
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.
- Open the incentive.groovy file you just created.
Figure 33. Incentive.groovy
- 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.
- 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:
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:
- Set the value of
/request/view in the global
context to the corresponding renderer.
- Set additional renderer-specific values into the
GlobalContext .
- 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.
- Right-click the project and select Run as > Project Zero
Application, as shown in Figure 34.
Figure 34. Run Project Zero
application
- Examine the console. The application should have launched and be listening on port
8080.
Figure 35. Application running on port
8080
- 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
- Launch the Firefox Poster tool by selecting View > SideBar > Poster.
Figure 37. Run Poster plug-in
- Enter
http://localhost:8080resources/incentive for the
URL and click GET.
Figure 38. GET incentives
- 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
- 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();
}
|
- Click GET again from the Poster plug-in to see the result in XML, as shown
in Figure 40.
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.
- 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
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.
-
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
Adding to the example
Now you'll add the onCreate(), onUpdate(), and onDelete() methods.
- 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.
- 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"}
|
- Select POST, as shown in Figure 43.
Figure 43. POST incentive
- 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
- 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
- You should get the response matching the record you created.
Figure 46. GET new incentive
- Repaste the payload from the C:\ProjectZeroArticleSeries\Part1\insertUpdatePayload.txt.
- 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"}
|
- Enter the URL of the resource
http://localhost:8080/resources/incentive/3 with the
payload and click PUT.
Figure 47. PUT incentive
- You should get a 204 response.
Figure 48. 204 result
- Issue another GET on the resource to ensure the update was successful.
Figure 49. Delete incentive
- 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
- Issue a GET. You should now get an empty result. (Future articles in this series will
add error handling into the code.)
 |
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:
- 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
- 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
- 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
At this point you can import and examine the code:
-
Right-click on the public folder of the project and select Import.
Figure 54. Import UI code
- 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
Let's briefly examine the code:
- Open the index.html, as shown in Figure 56.
Figure 56. Examine index
- 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
- 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
- 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();
}
|
- 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
Now, to run the client application:
- Re-launch the application. You can do this using the Eclipse run arrow, as
shown below.
Figure 60. Re-launch application
- 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
- Add a new incentive by clicking Add New Incentive.
Figure 62. Add new incentive
- Enter some data (you can using the JSON payload as an example, or look at Figure
63).
Figure 63. Add new incentive form
- Click Submit. The newly created resource should have been added to the
table.
Figure 64. Update incentive
- Highlight the newly created resource and click Edit Selected Incentive.
When selecting the
resource, the onRetrieve method is executed to get the individual resource.
- 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
- Finally, highlight the resource and click Delete Selected Incentive.
Figure 66. Delete incentive
- The list should be updated, as shown in Figure 67.
Figure 67. After deleting incentive
- Examine the neighbor widget as it displays the REST event and payload.
Figure 68. Mashed-up wizard
Congratulations on building your first RESTful service with Project Zero!
Summary
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.
Download | Description | Name | Size | Download method |
|---|
| sample code | i-zero1code.zip | 13KB | HTTP |
|---|
Resources Learn
-
Learn all about the Project Zero simple environment for creating, assembling and executing applications based on popular Web technologies.
-
The Project Zero
Developer's Guide
explains the core concepts that define the architecture of a Zero application.
-
Use the Project Zero Forum for help, feedback, alerts, discussion of ongoing development, and more.
-
Learn about Groovy, an agile dynamic language for the Java Platform.
-
Read how to install and configure PHP to develop Project Zero applications and new PHP extensions for Project Zero.
-
See additional developerWorks articles
and tutorials about Project Zero.
-
Learn all about Dojo, the JavaScript toolkit, and Dojo widgets.
-
Read about
Representational
State Transfer (REST) in Roy Thomas Fielding's dissertation, "Architectural Styles and the Design of Network-based Software Architectures."
-
Get details on JSON and JSON support in Project Zero.
-
Learn all about Eclipse, an open development platform.
-
Get more details about the Web browser
Firefox by Mozilla and the Poster plug-in.
-
Read about
Apache Derby, an open source relational database implemented entirely in Java.
-
Find out more about caching with a caching tutorial
for Web authors and webmasters.
-
Learn about Community-driven
commercial development (CD/CD).
- Read "Resource-oriented
vs. activity-oriented Web services," (developerWorks, Oct 2004).
- See additional developerWorks
articles and tutorials about REST.
-
RSS
feed for this series. (Find out more about RSS.)
- Visit
developerWorks Architecture,
and get the resources you need to advance your skills in the IT architecture arena.
- Browse the
technology bookstore
for books on these and other technical topics.
Get products and technologies
Discuss
About the authors
 | 
|  | 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
|