 | Level: Intermediate Brandon J.W. Smith (brandon+dW@16cards.com), Software Engineer, IBM Hanumanth R. Kanthi (kanthi@us.ibm.com), IT Architect,
IBM
08 Jan 2008 Project Zero is a simplified development platform focused on the agile development of Web 2.0 applications following a Service-Oriented Architecture (SOA). Among Project Zero's arsenal of libraries is a simplified API for executing SQL queries. Learn how to leverage these APIs to build a simple wiki.
Editor's note: IBM® WebSphere® sMash and IBM WebSphere sMash Developer Edition are based on the highly acclaimed Project Zero incubator project. Project Zero is the development community for WebSphere sMash and will continue to offer developers a cost-free platform for developing applications with the latest builds, the latest features, and the support of the community.
Before you get started
This article assumes you have a basic understanding of
Project Zero. If you need to get up to speed,
you can get started by taking a look at both the introductory article titled "Building RESTful services
for your Web application" and the introductory tutorial titled "Get
started with Project Zero and PHP." When you're comfortable using Project Zero, you
can download it (see Resources) and write a simple application yourself.
Introduction
Larry Wall said it best: make easy things easy and hard things possible.
Data access has use cases that range from the simple to the very complex. As such, many
developers pine for a data access API that is flexible enough to handle complex situations
without making the simple cases too cumbersome. Project Zero's data access API (called
zero.data) addresses this exact pain point. It is not intended as an
abstraction layer like Hibernate or the Java™ Persistence Architecture. Rather, it is a
library that strives to make the easy things easy and the hard things possible by providing a
thin wrapper around SQL as this article illustrates later. For instance,
Listing 1 shows how to execute a simple query and obtain the results
as a list of bean instances:
Listing 1. Use zero.data to return a list of bean and map instances
Manager data = Manager.create("myDb");
List<Person> results = data.queryList("SELECT * FROM person", Person.class);
List<Map<String,Object>> resultsMap = data.queryList("SELECT * FROM person");
|
Over the last year, the Project Zero team has collaborated closely with IBM®'s Information
Management developers on pureQuery, a high-performance data access platform that includes development
tools, APIs, and an advanced runtime for Java applications. zero.data
leverages pureQuery's APIs and runtime. zero.data does not preclude the use
of pureQuery's toolset because pureQuery tools generate Java artifacts. However, at the time of this writing, there is no Project Zero-specific integration with this robust toolset. (You can get more details
about pureQuery in Resources.)
Figure 1 shows the relationship between
Project Zero's APIs and pureQuery:
Figure 1. Relationship between Project Zero's zero.data relational data access APIs
 |
The Project Zero community
Take a stroll around the Project Zero Web
site and see how Project Zero provides a powerful — but radically simple — development and execution platform for modern Web applications. The active community discusses project development, provides help to developers, and wants to hear your ideas! |
|
zero.data provides a thin wrapping API around functionality provided by pureQuery's
APIs and runtime. This is preferred rather than using pureQuery APIs in order to enable
some simplifying assumptions in a Project Zero application (for instance, configuration and
connection pooling) and to provide a common API in which both Groovy and PHP scripts can
leverage the robust APIs in ways that make sense for each respective language. For instance,
several methods exposed in the Groovy interface make use of closures, whereas its PHP
equivalent uses PHP resource identifiers.
This article focuses on the Groovy APIs. You can learn more about the Java and PHP APIs
from Project Zero's documentation. In the rest of the article, you'll learn the basics
of using zero.data in your Zero applications. First, you will learn to
manage your data using the
zero.data.groovy.Manager interface and the motivations behind its
design, including looking at the APIs from both the Java and the Groovy
perspective. Next, you will
quickly get practical and create
an application to use the zero.data APIs. Once the application is created, you
will build a simple wiki, initialize tables, and finally code the application. Following is the high-level outline:
Manage your data
zero.data.groovy.Manager (referred to hereafter as the
Manager)
defines a convenience API for a user to query and manipulate relational databases. The most
basic use of the API is to pass an SQL string. In Groovy, you pass in the parameters embedded in
the string as follows: data.queryFirst("SELECT * FROM t WHERE id=$id").
The Manager then prepares the string using a
PreparedStatement, executes it, and returns the results. It also
intelligently manages closing resources created: for instance, the result set, statement, and
connection.
The Manager provides a series of methods to perform the following operations:
- Execute a query and iterate over each row executing a closure.
-
Execute a query and return just the first row of the ResultSet converted into one of the
following:
- instance of a Java Bean class
- java.util.Map
-
Execute a query and return all the rows of the ResultSet converted into one the above
contained by one of the following:
- java.util.Iterator
- java.util.List
- a Java array
- Execute a query and return the ResultSet.
-
Execute data manipulation language statements (such as INSERT, UPDATE, and DELETE)
including a specialized method for generated keys.
Simple API
As a data point, it is worthwhile to compare how the Manager
reduces boilerplate
code and allows you to focus on functionality rather than potentially buggy
'supporting' code. For instance, Listing 2 shows a JDBC-only implementation
of the code found in
Listing 1 and shows how dramatically Manager makes
the simple things
easy:
Listing 2. Using JDBC to return an instance of a Map is much more verbose
// assumes Connection has already been initialized
// see JDBC documentation for more details
List<Map<String,Object>> results = new ArrayList<Map<String,Object>>();
try {
PreparedStatement stmt =
connection.prepareStatement("SELECT * FROM person");
ResultSet rs = stmt.executeQuery();
try {
while(rs.next()) {
ResultSetMetaData meta = rs.getMetaData();
int numColumns = meta.getColumnCount();
Map<String,Object> row = new HashMap<String,Object>(numColumns);
for (int i = 1; i <= numColumns; i++) {
row.put(meta.getColumnName(i).toLowerCase(), rs.getObject(i));
}
results.add(row);
}
} finally {
rs.close();
}
} finally {
stmt.close();
}
|
Rarely does any application code utilize JDBC directly, as illustrated in
Listing 2. Most frameworks provide a layer of indirection and
simplifications to some extent. We believe the Manager
goes to tremendous lengths to
make the simple things easy and the hard things possible. For instance, in addition to
returning a single instance or List, Iterator, or Array of a Java bean class
or Map as shown in Listing 1, zero.data provides a template
method approach to allow you as a developer, or
possibly third parties, to implement complex ResultSet processing.
These more advanced uses of the template method approach will be discussed in a later
developerWorks article. As mentioned previously, zero.data is built on top of the
pureQuery runtime engine. The pureQuery runtime not only provides
a framework for constraining
database access in a predictable, yet flexible, manner through the use of an open API,
but it
encourages a high degree of code reuse. For instance, much of the pureQuery runtime itself
is composed of implementations of the very interfaces that you as a developer can implement
to extend the engine. In this way, the pureQuery runtime is
flexible enough to handle everything from 'one-off' extensions to its engine for a given
application to an organization endorsing a library of reusable ResultSet
processing components.
As depicted in Figure 1, Manager
actually wraps the zero.data.Manager, providing more Groovy friendly
shortcuts.
Following is a comparison of Manager's data access
APIs and zero.data.Manager's. You'll notice that they carry a common theme.
Namely, there are a variety of methods types
that accomplish nearly the same thing but for special use cases. For instance,
queryList returns a java.util.List,
whereas queryIterator returns an
java.util.Iterator. Fairly self-explanatory. Each of these methods
types has three overloaded methods and are symmetrical in signature and function across all
the method types. Table 1 depicts all the method types and overloaded
methods complete with descriptions. You can find more information in Project Zero's
Javadoc API documentation.
Table 1. A high-level overview of Manager methods
| Method | Description | Variations | Groovy alternative |
|---|
| queryFirst | Returns the first row in a ResultSet. | Map<String,Object> queryFirst(String, Object...) | Map<String,Object> queryFirst(GString) |
|---|
| T queryFirst(String, Class<T>, Object...) | T queryFirst(GString, Class<T>) | | T queryFirst(String, RowHandler<T>, Object...) | T queryFirst(GString, RowHandler<T>) | | queryList | Returns the ResultSet as a java.util.List. | List<Map<String,Object>> queryList(String, Object...) | List<Map<String,Object>> queryList(GString) |
|---|
| List<T> queryList(String, Class<T>, Object...) | List<T> queryList(GString, Class<T>) | | List<T> queryList(String, RowHandler<T>, Object...) | List<T> queryList(GString, RowHandler<T>) | | queryIterator | Returns the ResultSet as a java.util.Iterator. | Iterator<Map<String,Object>> queryIterator(String, Object...) | Iterator<Map<String,Object>> queryIterator(GString) |
|---|
| Iterator<T> queryIterator(String, Class<T>, Object...) | Iterator<T> queryIterator(GString, Class<T>) | | Iterator<T> queryIterator(String, RowHandler<T>, Object...) | Iterator<T> queryIterator(GString, RowHandler<T>) | | queryArray | Returns the ResultSet as a Java
array. | Map<String,Object>[] queryArray(String, Object...) | Map<String,Object>[] queryArray(GString) |
|---|
| T[] queryArray(String, Class<T>, Object...) | T[] queryArray(GString, Class<T>) | | T[] queryArray(String, RowHandler<T>, Object...) | T[] queryArray(GString, RowHandler<T>) | | update |
Executes an update and returns the number of rows affected.
| int update(String, Object...) | int update(GString) |
|---|
| insert | Executes and returns generated key value casted into the class specified in the second
parameter. The Groovy version is opinionated and casts to an int.
| T insert(String, Class<T>, String[], Object...) | int insert(GString, List<String>) |
|---|
Java
programming and Groovy
As you can gather from Table 1, zero.data has a comprehensive
set of data access methods to suit a variety of situations. We will only use the
zero.data.groovy.Manager version of
queryFirst(GString),
queryList(GString),
update(GString),
and insert(GString, List).
Groovy is a dynamic, object-oriented programming language that runs on the Java platform. A frequent misconception is that Groovy attempts to replace the Java programming language. Because Groovy compiles to Java bytecode, it can leverage the standard Java APIs and many libraries that are also written in the Java language. Thus, Groovy doesn't attempt to replace the Java syntax but rather to complement it by offering an alternative syntax containing many language constructs allowing for more concise, terse code.
For example, using the Java version of Project Zero's zero.data APIs, you can
already reduce the lines of code from standard JDBC method calls, as illustrated previously.
However, compare Listing 3, which shows functionally equivalent
Java and Groovy code:
Listing 3. Comparison of functionally equivalent Java and Groovy code
// Java
Manager data = zero.data.Manager.create("wiki");
data.inTransaction(new LocalTransaction() {
public void execute() {
data.update("UPDATE mytable SET name=? WHERE id=?", 1, "new name");
data.insert("INSERT INTO anothertable (name) VALUES (?)", "another name");
List<Map<String,Object>> results = data.queryList("SELECT * FROM sometable");
for (Map<String,Object> row : results) {
for (String key : row.keySet()) {
System.out.println("key: " + key + ", value: " + row.get(key));
}
}
}
});
// Groovy
def data = zero.data.groovy.Manager.create("wiki")
data.inTransaction {
data.update("UPDATE mytable SET name=$name WHERE id=$id")
data.insert("INSERT INTO anothertable (name) VALUES ($name)")
data.eachRow("SELECT * FROM sometable") { row ->
row.each { key, value ->
println("key: $key, value: $value")
}
}
}
|
From Listing 3, you can see that not only are the number of lines of code
reduced, but the Groovy language tends to stay out of the way. For instance, in the Java
version of the inTransaction method, we must explicitly create
an anonymous instance of LocalTransaction. However, in Groovy,
we hide this behind a closure. Closures are a way in Groovy to create, in a way, "portable"
code. Similar to how you can create an anonymous implementation of the abstract
LocalTransaction class and pass it to the inTransaction method within the Java language,
in Groovy you can zip up the code between the closure brackets ("{" and "}") and send it
to the inTransaction method in a much more concise manner. The Groovy documentation (see Resources) has a more comprehensive explanation about closures in the Groovy
language, including examples and how to write APIs that take a closure as an argument.
The Groovy version of the code in Listing 3 has a second and a third use of closures. The eachRow method can take a closure and
will execute the code in between the brackets for each row in the results. As you can
see in the listing, that code calls another closure, which simply loops over the entries
in the row Map and prints out the keys and values.
Creating an application
 |
Using zero.data APIs in this article
Project Zero leverages Groovy as a dynamic language that can perform but does not require
static, compile-time type checking. Thus, the Map version of the APIs is used
in this article, which maps a row in a ResultSet to a
java.util.Map where the column names are keys in the Map and the
values are the values in the row.
|
|
For the remainder of this article, you will see how the power zero.data provides by creating a simple wiki application using the classic Model View Controller pattern. Figure 2 illustrates the high level architecture of how this works in a Zero application; later in the article, you will learn where to place your code artifacts to support the Zero conventions.
The Model-View-Controller Pattern
Take a look at Figure 2, which illustrates the Model-View-Controller implementation in a Project Zero application:
Figure 2. Model-View-Controller implementation in a Project Zero application
To jump-start your application, you first need to create a Project Zero application.
The figures that follow show the use of the Project Zero plug-in for Eclipse, which provides
user interface shortcuts for developing applications (but everything can also be done using
the command-line utility equivalent functionality).
First, you must create a Zero application. "Introducing Project
Zero, Part 1" has detailed steps illustrating how to use the Project
Zero Eclipse user interface to create an application. Further, it details the various
folders and artifacts that make up a Project Zero application. But you'll see the basic
steps here.
First, create an application by clicking the File > Project.. menu item. A
dialog box provides the option to select a project wizard. Select Project Zero > Project Zero Application
to start the wizard as shown in Figure 3:
Figure 3. Select the Project Zero Application wizard
The first screen in the wizard prompts for an application name. It can be named anything you wish,
but we'll keep it obvious by naming it mywiki, as shown in Figure 4:
Figure 4. New Project Zero Application name prompt
This creates a project in your Eclipse workspace in the Project Zero application folder structure
and some default application artifacts. Find the mywiki project. It should
look as shown in Figure 5:
Figure 5. Project Zero application folder structure
Thanks to Project Zero's use of the Ivy framework to maintain dependencies, obtaining zero.data
is very simple. Dependencies are declared in the application in
${app_home}/config/ivy.xml. For convenience and simplicity, we will use Apache Derby
in embedded mode for this demonstration. Edit this file to include the two lines of
XML found in Listing 4:
Listing 4. Add to the application's ivy.xml
<dependency org="zero" name="zero.data" rev="1.0+"/>
<dependency org="org.apache.derby" name="derby" rev="10.3.1.4"/>
|
 |
Obfuscating passwords
Because you're using embedded Derby for a database, you don't need connection properties, which are often required of databases that run out of processes from your application. For instance, you'll notice the lack of a password property. Project Zero provides a
mechanism to obfuscate passwords so they do not appear in plain text.
Project Zero
documentation has more details on how to accomplish this type of configuration.
|
|
Resolve your new dependencies as described in
" Introducing Project Zero, Part 1", and then return here.
Configure zero.data
zero.data uses a javax.sql.DataSource to connect to
databases. You can configure and connect to one or more databases by configuring the connection
properties in your Project Zero application's zero.config file. Listing 5
illustrates how to configure a named database with a key of 'wiki':
Listing 5. Configure zero.data in zero.config
/config/db/wiki = {
"class" : "org.apache.derby.jdbc.EmbeddedDataSource",
"databaseName" : "db/wiki",
"connectionAttributes" : "create=true"
}
|
Obtain a Manager instance
With your database connection properties properly configured, you're now ready to obtain a
Manager instance. With this instance, you can execute queries and
manipulate the data using the convenience method described above. You obtain a configured
Manager by using the key you selected in the zero.config file. In
this case, we chose 'wiki'. Pass this as an argument to the create method as shown in
Listing 6:
Listing 6. Obtain a configured Manager
def data = zero.data.groovy.Manager.create('wiki')
|
As you can see from
Listing 4,
Listing 5,
and Listing 6, very little is required to get
your Zero application up and running. Next, we will start to build our simple wiki by
defining some basic requirements and translating that into code.
Build a simple wiki
To illustrate the uses of zero.data, we will build a simple wiki application. In its
simplest form, a wiki creates, edits, links to, and renders wiki pages. Thus, in this
example, we will illustrate the Create, Retrieve, and Update operations from the canonical CRUD
operation (but we will not illustrate the Delete operation).
Why a wiki?
Why implement a wiki to illustrate the zero.data APIs? First, a simple wiki is,
well, simple. Thus, our focus on the zero.data APIs can remain in the forefront
without dwelling too much on other implementation details that arise in a more complex
wiki implementation.
Second, a wiki provides a good base in which additional functionality can be
built up later to illustrate more advanced uses of zero.data and other features of
Project Zero.
 |
What is a wiki?
A wiki is software that allows users to quickly and easily create, edit, and link Web pages.
The term is derived from a Hawaiian word meaning quick or informal.
|
|
Wiki requirements
As mentioned previously, a basic wiki implementation needs to create, retrieve, and update
wiki pages. Common to most wiki implementations is that pages are created by linking to them
from another page first. The wiki user clicks such a link, and a form prompting the user to
create the page is displayed. If the page already exists, it is simply rendered with
a link that allows the user to edit the page in a form similar to the create form.
We will use combination of Project Zero's script and
templating features and leverage some know-how around familiar MVC patterns to prototype this implementation. Namely, we will
place our controller scripts in the application's public folder. These scripts will be accessible
through URIs — much like you'd expect from a PHP application. Folder hierarchies and files on
the file system match the URI structure. Our views will live in the application's /app/views
folder. Because we will implement this in Groovy, our controllers will have the
.groovy suffix and views will be suffixed with .gt.
To get a better understanding of where we are going, Figure 6 shows what the application directory
will look like after creating our application artifacts:
Figure 6. Project Zero application folder structure after completing the steps
Enough background. Let's dive into the code.
Initialize tables
Before we get too carried away with our controller and view implementations, we need a model
that they can use to retrieve, display, and manipulate data. We will persist wiki pages in a
database table. For simplicity, our model will just be a Map mapped to a row in a database
table. (This wouldn't be much of an article about zero.data if we didn't.) Our storage
needs are very modest. We simply need a name for the page and the actual page content. This
is reflected in the SQL code snippet in Listing 7 placed in the setup.sql file:
Listing 7. Contents of setup.sql
CREATE TABLE pages (
id int NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
name varchar(20) NOT NULL,
content varchar(3000),
updated timestamp,
PRIMARY KEY (id)
);
|
Start it up!
Unlike other application artifacts discussed earlier, there is no convention around
setup.sql. The data definition contained in this file is executed using a startup
handler — code you provide to a Project Zero application that is executed at a certain stage when the application is, you guessed it, started.
First, we create the Groovy script that should be executed when your Project Zero application
is started. We want it to execute the statements found in setup.sql if the
database does not yet exist. We are about to do a development time trick, which
should not be repeated in production. Currently, no support exists for modifying an
existing database schema over time. As such, if the application's
schema changes, you must delete the database from the file system using a startup handler. For purposes of illustration, we'll leave best
practices at the front door. But this simple — if not naive — implementation will suffice to
illustrate the use of zero.data APIs (see Listing 8):
Listing 8. Contents of app/scripts/startup.groovy
import zero.data.groovy.Manager
//if derby database already exists, don't run the script
def db_dir = new File('db/wiki')
if (!db_dir.isAbsolute())
db_dir = new File(config.root[], 'db/wiki')
if (!db_dir.exists()) {
def buffer = new StringBuffer()
new File('setup.sql').text.split('\n').each() { line ->
line = line.trim()
if (line && !line.startsWith("--") && !line.toLowerCase().startsWith("connect"))
buffer << line << '\n'
}
def statements = buffer.toString().split(';')
def data = Manager.create('wiki')
try {
data.inTransaction() {
statements.each() { statement ->
statement = statement.trim()
if (statement)
data.update(statement)
}
}
} catch (Throwable error) {
throw new RuntimeException("Setup database error: ${error.message}", error);
}
}
|
Before this script can execute at startup, we need to configure it to do so. This is done
by registering the script as a startup handler in the config/zero.config file, as shown
in Listing 9:
Listing 9. Add the following stanza to config/zero.config
/config/handlers += {
"events" : "start",
"handler" : "startup.groovy"
}
|
This registration tells the Project Zero runtime to execute the startup.groovy script under
all conditions when the 'start' event is fired. Start the Project Zero application and the
CREATE TABLE statement will now be executed. Because the database does not yet exist,
embedded Derby will create it on disk for you (because you previously configured the
connection properties to create it if it didn't exist).
Code the application
Leave your application running. Project Zero is dynamic and can pick up most changes. Now that
you have your table created, you can start coding your controller and views. Let's start with
rendering a page.
Rendering dynamic HTML
To render a page, we need a hook that the Project Zero runtime uses to hand off control
to our wiki application. We will implement this in the form of a controller in the app/public
directory. We'll call the render functionality 'view.groovy'. First, render needs a
Manager to execute the query for a page. Next, we will
execute a query to retrieve a row in the database. If the row exists, we render it. If it
does not exist, we display a create page. The implementation is shown in Listing
10:
Listing 10. The view.groovy implementation
def name = request.params.name[]
def data = new zero.data.Manager('wiki')
def page = data.queryFirst("SELECT * FROM pages WHERE name=$name")
if (page) {
request.page.name = page.name
request.page.content = page.content
request.view = 'view.gt'
} else {
request.page.name = name
request.view = 'create.gt'
}
render()
|
We now need to create the 'view.gt' and 'create.gt' views to support the view.groovy
controller. Both views simply render data in the request scope using Groovy templates
(see Listings 11 and 12):
Listing 11. The view.gt implementation
<html>
<head>
<title><%= request.page.name[] %></title>
</head>
<body>
<h1><%= request.page.name[] %></h1>
<%= request.page.content[] %>
<hr/>
<a href="<%= "${getRelativeUri('/edit.groovy')}?page=${request.page.name[]}" %>">
Edit this page?
</a>
</body>
</html>
|
Listing 12. The create.gt implementation
<html>
<head>
<title><%= request.page.name[] %> - Create</title>
</head>
<body>
<h1><%= request.page.name[] %></h1>
This page does not exist.
<a href="<%= "${getRelativeUri("/edit.groovy")}?name=${request.page.name[]}" %>">
Create?
</a>
</body>
</html>
|
Updating the database
In the previous section, you created two views: a wiki page rendered and a form to create a
wiki page. To support these views, you need to create additional controllers and views.
Namely, the view.gt view links to the edit.groovy controller, and the create.gt HTTP POSTs its
form to save.groovy by rendering edit.gt. edit.groovy retrieves data and displays a form
similar to create, only now it's populated with the existing wiki page content. save.groovy either
inserts a row or updates an existing row in the database table. Their implementations
are shown in Listings 13 through 15:
Listing 13. The edit.groovy implementation
def name = request.params.name[]
def data = zero.data.groovy.Manager('wiki')
def page = data.queryFirst("SELECT COUNT(*) FROM pages WHERE name=$name")
if (page) {
request.page.content = page.content
} else {
request.page.content = ""
}
request.page.name = name
request.view = 'edit.gt'
render()
|
Listing 14. The edit.gt implementation
<html>
<head>
<title><%= request.page.name[] %> - Editing</title>
</head>
<body>
<h1>Editing <%= request.page.name[] %></h1>
<form method="POST"
action="<%= "${getRelativeUri('/save.groovy')?name=${request.page.name[]}" %>">
<textarea name="content" rows="20" cols="60"><%= request.page.content[] %></textarea>
<input type="submit" value="Save Page"/>
</form>
</body>
</html>
|
Listing 15. The save.groovy implementation
def name = request.params.name[]
def data = zero.data.groovy.Manager('wiki')
def page data.queryFirst("SELECT * FROM pages WHERE name=${name}")
def content = request.params.content[]
if (page) {
data.update("UPDATE pages SET content=${content}")
} else {
data.update("INSERT INTO pages (name,content) VALUES ($page_name,$content")
}
uri = "${getAbsoluteUri('/view.groovy')}?name=${name}"
request.headers.out.Location = uri
request.status = HttpURLConnection.HTTP_MOVED_TEMP
|
Testing the application
You now have a very basic wiki application. So basic, in fact, that you must provide a wiki page that doesn't
exist in order to bootstrap the application. You can do this by entering
http://localhost:8080/view.groovy?name=HomePage
to get the page shown in Figure 7:
Figure 7. Missing HomePage
We are instructed that the page does not exist. This is good because it means that it is working. We could have
put any value into the URI's name parameter, but "HomePage" just seemed like a good start. Next, we need
to create content for the HomePage. Let's enter in any arbitrary HTML. Perhaps add a link in the
form that we know will link to a page (even if we know it doesn't exist) as shown in
Figure 8:
Figure 8. Edit HomePage
Now, we click the Save Page button to put the page in the database. We are then redirected to
view the page we just edited, as shown in Figure 9:
Figure 9. Found HomePage
If you linked to a non-existing page (it's pretty easy because only one page exists in the database now), then
you can click on that link and it will take you to the missing page screen again. You can create a page
for your linked page as shown in Figure 10:
Figure 10. Missing CodingTips
And that's it for our simple wiki. Naturally, our wiki could do many more things. We could use a markup text like Markdown or Textile to simplify content creation and linking, among other things. (You can try these as exercises later!)
Conclusion
Project Zero is a simplified development platform focused on agile development of Web
2.0 applications following an SOA. Among Project Zero's arsenal of libraries is a simplified API for executing
SQL queries. You learned how to leverage these APIs to build a simple wiki.
We discussed the motivations behind the zero.data API, including its wrapping of the pureQuery APIs.
We also looked in-depth at zero.data.Manager and illustrated some of the
high-level differences between the Java and Groovy versions of the APIs.
We then immediately got practical by creating an application
using the zero.data APIs by building a simple wiki, initializing database tables, and finally
coding the implementation. We hope this article has been useful to you and that you'll dive in to creating Zero applications! The active Project Zero community will be there to help you if you need it.
Download | Description | Name | Size | Download method |
|---|
| Sample Project Zero Eclipse project | wa-pz-wiki.zip | 10KB | HTTP |
|---|
Resources Learn
- "Introducing Project Zero, Part 1: Building RESTful services for your Web application" (developerWorks, Oct 2007) provides an introductory, hands-on, guided tour of Project Zero's innovations to create, assemble, and deploy powerful Web applications.
- "
Preserve
the security of your Project Zero applications, Part 1: Authentication and authorization" (developerWorks, Nov 2007) discusses how Project Zero makes access-control based security of application resources simple.
- "
Use Active
Content Filtering for Project Zero application security" (developerWorks, Nov 2007) illustrates how to dodge common Web 2.0-based application
attacks, such as cross-site scripting, and dramatically increase your Project Zero
application's security using Active Content Filtering.
-
IBM Data Studio pureQuery Runtime
is a robust set of development tools, an application runtime API, and engine to manage the life cycle
of Java database development. Project Zero leverages the runtime API and engine to provide a flexible
environment to develop Web 2.0 applications.
-
Groovy Closures
shows practical ways to leverage this advanced language construct in Groovy.
-
"Template method pattern"
(Wikipedia, Nov 2007) discusses this pattern and how the use of it in designing APIs allows
software library designers to enable users to inject new functionality into the system without
modifying existing services.
- "Optimize
database configuration and dependencies of Project Zero applications" (developerWorks, Sept 2007)
illustrates a technique for managing database configuration across multiple Project Zero
applications.
- The
zero.data.Manager Javadoc API provides a more detailed description
of all the methods available for database access.
- Join the
Project Zero community and see what all the buzz is about!
-
The introductory tutorial to Project Zero, titled "Get started with Project Zero and PHP," can get you started developing Project Zero applications today.
-
Browse the developerWorks Web development zone to find tools, code, and resources to get you started developing Web 2.0 applications today.
-
The developerWorks Ajax resource center is packed with information for all skill levels to help you build Ajax into your applications and dramatically improve your user's Web experience.
Get products and technologies
Discuss
About the authors  | 
|  | Brandon Smith works on IBM's Project Zero, heading up all things data. He has a master's degree
from Carnegie Mellon University. Catch up with him at 16cards.com
and brandon+dW@16cards.com. |
 | 
|  | Hanumanth Kanthi works as an IT Architect with IBM Software Services for WebSphere.
He has a master’s degree in computer science from Victoria University of Technology, Australia.
He can be reached at kanthi@us.ibm.com. |
Rate this page
|  |