Use Project Zero and WebSphere sMash's data access APIs to build a simple wiki

Create a simple wiki application using the classic Model-View-Controller pattern

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.

Brandon J.W. Smith (brandon+dW@16cards.com), Software Engineer, IBM

Brandon SmithBrandon 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 R. Kanthi (kanthi@us.ibm.com), IT Architect, IBM Japan

Hanumanth Kanthi photoHanumanth 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.



08 January 2008

Also available in Chinese Russian

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
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
MethodDescriptionVariationsGroovy alternative
queryFirstReturns 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>)
queryListReturns 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>)
queryIteratorReturns 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>)
queryArrayReturns 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)
insertExecutes 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
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
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
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
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
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
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
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
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
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

DescriptionNameSize
Sample Project Zero Eclipse projectwa-pz-wiki.zip10KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, XML, Information Management, WebSphere
ArticleID=280763
ArticleTitle=Use Project Zero and WebSphere sMash's data access APIs to build a simple wiki
publish-date=01082008