Welcome to the Tutorial

This tutorial is intented to get you started writing Java code to extend or customize the Brazil System. It only covers the basics; for more detailed examples, consult the Brazil source code.

This tutorial will touch upon three common ways of extending the functionality of Brazil: Handlers, Templates, and filters.

Handlers

In its simplest form, writing a handler is a bit like writing a servlet; it takes an http request, and generates a response. The request object, passed to each call to respond contains methods that abstract the HTTP protocol, and provide convenience methods for returning valid responses. Here is the first example:

Figure 1: SampleHandler1.java
package sample;

import sunlabs.brazil.handler.MatchString;
import sunlabs.brazil.server.Handler;
import sunlabs.brazil.server.Request;
import sunlabs.brazil.server.Server;
import java.io.IOException;

public class SampleHandler1 implements Handler {

   /*
    * The names of handler-specific configuration parameters are typically
    * defined here.  This handler uses a parameter named "parameter".
    */

   public static final String PARAM="parameter";

   MatchString isMine;		// Utility class for URL matching

   /**
    * Called once for each handler instance created.
    * - server:		a reference to our server
    * - namePrefix	The "name" our handler instance, and the prefix
    *			for our configuration parameters in server.props.
    */

   public boolean init(Server server, String namePrefix) {
      isMine = new MatchString(namePrefix, server.props);
      return true;
   }

   /*
    * Called at each request.  It is up to the handler to decide to
    * handle this request.  The convenience class MatchString may be
    * used for handling based on URL's.
    */

   public boolean respond(Request request) throws IOException {
       if (!isMine.match(request.url)) {
	  return false;
       }
       String param = request.props.getProperty(
	     isMine.prefix() + PARAM, "default");
       request.sendResponse(
	     "<h1>Hello " + param + "from the Sample Handler</h1>");
       return true;
   }
}

Notice the response includes HTML markup compiled into the Java code. This is almost always a bad idea; to change the presentation, the handler needs to be recompiled. It is better to generate the results in a presentation-neutral form, so the presentation can be changed without recompiling the handler. The only time it makes sense to include markup in the code like this is in extremely simple servers, where only one handler is desired, or where the output format is fixed and static.

The next example, a modification of the original, demonstrates a better approach. Source code changes to the example are indicated by presenting new code in bold-face. Deletions are crossed out.

Figure 2: SampleHandler2.java
package sample;

import sunlabs.brazil.handler.MatchString;
import sunlabs.brazil.server.Handler;
import sunlabs.brazil.server.Request;
import sunlabs.brazil.server.Server;
import java.io.IOException;

public class SampleHandler2 implements Handler {

   /*
    * The names of handler-specific configuration parameters are typically
    * defined here.  This handler uses a parameter named "parameter".
    */

   public static final String PARAM="parameter";

   public static final String MSG="message";

   MatchString isMine;		// Utility class for URL matching

   /**
    * Called once for each handler instance created.
    * - server:		a reference to our server
    * - namePrefix	The "name" our handler instance, and the prefix
    *			for our configuration parameters in server.props.
    */

   public boolean init(Server server, String namePrefix) {
      isMine = new MatchString(namePrefix, server.props);
      return true;
   }

   /*
    * Called at each request.  It is up to the handler to decide to
    * handle this request.  The convenience class MatchString may be
    * used for handling based on URL's.
    */

   public boolean respond(Request request) throws IOException {
       if (!isMine.match(request.url)) {
	  return false;
       }
       String param = request.props.getProperty(
	     isMine.prefix() + PARAM, "default");
       request.sendResponse(
	     "<h1>Hello " + param + "from the Sample Handler</h1>");
       return true;
       request.props.put(isMine.prefix() + MSG,
             "Hello " + param + "from the Sample Handler");
       return false;
   }
}

In Figure 2, the results are returned, not as an HTML page, put placed in the request property table. Note the return code is now false instead of true. This is an indication that request processing is not complete, and additional steps need to be taken to generate the response.

A typical way to generate the response would be to use the TemplateHandler to process an HTML (or XML) template to substitute in the value generated by the sample handler. This requires a server configuration that involves two handlers working together to produce the desired results; one to generate the presentation-neutral values, and the other to apply the presentation.

Here is a sample server configuration file:

Figure 3: sample1.config
# Server Configuration for SampleHandler2

#
# The ChainHandler causes a "chain" of handlers to run in sequence, until
# one of them generates a response (by having the respond() method return true).
# The ChainHandler assign names to each handler, which is provided to
# the handler's init() method, and us used as a prefix to look-up a
# handler's configuration parameters.

handler=sunlabs.brazil.server.ChainHandler
handlers=sample template

# This is our sample handler
# We know from the class documentation that a property called "parameter"
# is used.

sample.class=sample.SampleHandler2
sample.param=Hello from Sample Handler 2

#    The TemplateHandler permits classes to "register" HTML (or XML) tags.
# When a registered "tag" is seen, a method in the registered class
# is called to process the "tag".  Typically, the processed output is
# ordinary HTML.
#    The SetTemplate looks for a tag of the form: <get name=xxx> and
# replaces it from a value in the request property table.

template.class=sunlabs.brazil.template.TemplateHandler
template.templates=sunlabs.brazil.template.SetTemplate

This file would be used with an HTML template, such as:

Figure 4: sample1.template
<html>
<head>
<title>Sample Html Template </title>
</head>
<body>
<h1>Hello <get name=sample.message> from the sampe handler</h1>
</body>
</html>

Templates

(not done yet)

Object Model

The following "axioms" help define the process model of the system.


Back to overview