A Gentle Ramble

This is a good place to start if you are not sure what Mojasef is, or what it has to offer. Installation, basic configuration, and some of the major features are introduced in a comfortable step-by-step approach.

Contents
  1. Hello World
  2. Counting Hits
  3. User Sessions
  4. Permanent Configurations
  5. Catching All Accesses
  6. Finding Things Out
  7. Passing Things Back To The Server
  8. Sharing Context Between Several Methods
  9. Making Nice Looking Pages
  10. Magic With Templates
Hello World

In the time-honoured tradition, let's start with "hello, world". In keeping with the principles described above, we want to be able to reuse as much as possible that we have learned before. So let's start with an old "Hello.java" that we might have lying around after learning Java in the first place:

public class Hello
{
  public void sayhello()
  {
    System.out.println("Hello, World!");
  }

  public static void main(String[] args)
  {
    Hello hello = new Hello();
    hello.sayhello();
  }
}

To put this program on the web, we need to make the following changes to it: none at all :)

To use this program with Mojasef:

  1. compile Hello.java so that you get a file Hello.class in your current directory
  2. run Mojasef using

    java -Dhttp.application$=Hello -jar moja-http.jar

  3. point your browser at http://localhost/sayhello

If all that went according to plan, you should see "Hello World!". That was pretty straightforward, wasn't it.

As an aside, note the "$", that little character is actually part of some key technology that gives mojasef its simple and flexible configuration power. See the manual for more details.

Counting Hits

Now, this is pretty simplistic, so far. So let's tighten it up a bit. First, Our "Hello" application may only be a dozen lines, but it's still too big. So let's remove some redundant code. We don't need any of that "main" nonsense, becuse mojasef already knows how to create an object and call a method.

public class Hello
{
  public void sayhello()
  {
    System.out.println("Hello, World!");
  }
}

That all looks neat enough, but it doesn't actually do much so far. How about remembering things between page requests? To keep it simple for this example, we'll just make it count accesses.

public class Hello
{
  int n = 1;

  public void sayhello()
  {
    System.out.println("Hello, World!");
    System.out.println("visit number " + n++);
  }
}

Try it. Stop the server (using Control-C, task manager or whatever), recompile Hello.java, and run Mojasef again. Refresh your browser a few times to see that it really is counting. Cool. And way simpler than messing about with the Servlet API.

OK, those of you with servlet experience might be beginning to worry. Relying on member variables in a multi-threaded situation is extremely risky and a classic servlet problem. So this is a little simplistic as it stands. If you are getting a lot of hits and you really care about your hit count being "absolutely correct", you should probably wrap the increment in a synchronized block. On the other hand, you could sidestep the problem by reading the next section.

User Sessions

Counting is good, but sometimes we don't want to share a single value. How about if we want to keep a separate count for each visitor? This might seem tricky, but not in mojasef. Just run the server using:

To test this yourself you will either need to access it from different machines, or using different browsers. Firefox and Internet Explorer, for example. Point both your browsers at the same URL and try different combinations of refreshing the page to prove to yourself that the counts really are independent.

Permanent Configurations

At this point I'd be getting fed up with typing such a long command line. Luckily Mojasef allows you to store stuff like this in a file ready to be picked up when the server starts. Here's a simple way to do that:

  1. create a file in the current directory called "http.spec"
  2. put the following single line of text in it:

    http.application$=http.SessionWrapper Hello

  3. Now you can run the server using:

    java -jar moja-http.jar

Catching all Accesses

While playing with this, you may have noticed that it's got a pretty narrow view of what URLs to respond to. Anything other than /sayhello gets a 404 "not found" error. There are several ways to improve this, but one of the simplest is to rename the method from sayhello() to request(). request() is one of the method names that Mojasef looks for if it can't find a match on the URL.

public class Hello
{
  int n = 1;

  public void request()
  {
    System.out.println("Hello, World!");
    System.out.println("visit number " + n++);
  }
}

Now our server is much more polite. It will say "hello" to all visitors, whatever URL they ask for.

As an aside, Mojasef will always look for specific names before trying more general options like request, so we can add another method:

public class Hello
{
  int n = 1;

  public void request()
  {
    System.out.println("Hello, World!");
    System.out.println("visit number " + n++);
  }

  public void secret()
  {
    System.out.println("you found the hidden page :)");
  }
}

Now pretty much every URL we can think of (such as http://localhost/wibble, or whatever) will give us the "Hello, World" message , but if we happen on http://localhost/secret we get the other message. Anyone for web services without all that fuss?

Finding things out

Placing our raw objects on the web is a cool thing to do, but so far, not really as useful as the ugly Servlet API. If nothing else we need to be able to look at the parameters passd to GET and POST requests, and maybe other things such as request headers, cookies, and system configurations. Luckily, Mojasef comes to our aid with this too.

There are two major ways to get access to this kind of context information. I'll break with tradition in this simple tutorial, and introduce both of them, so you can get the idea of the possibilities. For the first approach, let's go back to our basic "hello" program and add a parameter to our method:

import org.stringtree.StringFetcher;

public class Hello
{
  int n = 1;

  public void sayhello(StringFetcher context)
  {
    System.out.println("Hello, World!");
    System.out.println("visit number " + n++);
  }
}

As you can see, we have eventually needed to import an extra class. Don't worry, though. This class doesn't carry a lot of baggage. StringFetcher is a very simple interface consisting of two methods:

If you want to fetch something in the form of a String from the surrounding context, use get(String key). This method returns the string value of the named context object, or the empty string ("") if not present.

If you want to fetch any other type of object, use getObject(String key) and cast the result if necessary. Note that if there is nothing stored with the named key, this methjod will return null, so it can also be used to check for the presence or absence of a value.

To compile this class you will need to make sure that StringFetcher is in your compilation classpath. The simplest thing to do at the moment is to just put the whole moja-http.jar in the classpath. Later, you may prefer to use the much "lighter" stringtree-if.jar from the Stringtree project, which contains all the interfaces needed to write applications that use Mojasef, but contains no implementation code to slow down and clutter up compilation.

To compile the class either place stringtree-if.jar or moja-http.jar in your classpath or use:

javac -classpath moja-http.jar Hello.java

As an aside, when Mojasef starts up, it will look for class directories and jar files in a lib directory, so when you find that you want to use external APIs or libraries in your applications or components, just pop them in there.

Now we have a context to look in, we really ought to use this new parameter to fetch some information. let's print the originating IP address of the request and the browser identification header, and (to make our greeting more personal), the value of a supplied "name" parameter.

import org.stringtree.StringFetcher;

public class Hello
{
  int n = 1;

  public void sayhello(StringFetcher context)
  {

    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));
  }
}

If you pop to the browser and request your mojasef URL (probably still http://localhost/sayhello), you should see something starting with

Now if you pass in a parameter by using http://localhost/sayhello?name=Frank You should see a message starting with

If you want something other than an empty string to appear when no parameter is supplied, you can easily set a default value in the same place you sett http.application. Add the following line to http.spec and restart the server:

name=Mystery Guest

Now, viewing http://localhost/sayhello gives:

Passing things back to the server

This is all simple enough, but the output is beginning to look a bit messy. Despite using "println" to put our text on separate lines, the web browser is treating it as HTML, and displaying it all on one line. A simple way to fix this is to set the output "content type" to text/plain to override the default. You may notice that the StringFetcher we are passing in to this method only has "get" methods, If we want to be able to "put" output values as well, we need to pass in a StringRepository instead. Let's modify our class by changing the import statement and the parameter declaration:

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;

  public void sayhello(StringRepository context)
  {
    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));
  }
}

If you compile and run this, you'll notice that it behaves exactly as it did before. A StringRepository is also a StringFetcher, and provides all the same methods and results. StringRepository also provides two extra methods, with pretty obvious uses:

Actually, StringRepository also provides a clear() method, but using it in a Mojasef application can be a very quick way to screw up your program unless you know exactly what you are doing.

To set the page content-type, let's add a line to put "text/plain" back into the context:

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;

  public void sayhello(StringRepository context)
  {
    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));

    context.put("http.response.header.Content-Type", "text/plain");
  }
}

Compile the class and restart the server. You should now see your messages in glorious plain-text-o-vision.

There are, of course, pleanty of other things you can put back into the context. Anything with a name starting with http.response.header. will be sent as an outgoing header. You can set the HTTP response code (e.g. 404 for missing page) using http.response.code, and set outgoing cookies by starting names with http.response.cookie.. You can also set any other value you like, to be used in a page template, but that will be introduced in a little while, below. For more details of any of this, see the manual.

Sharing context between several methods

Remember I mentioned another way of getting information from the server? If we want to keep our methods with no parameters (this is more usual when there are several other pre-existing methods in the class which we also want to make available on the web), we can make use of another mojasef feature. Before calling any method on our object, mojasef will first try the special method warmup. Just as with request, mojasef will look for warmup(StringRepository context), warmup(StringFetcher context), or warmup(). If you provide any of those public methods, mojasef will call it, and you can keep a copy of the supplied context if you want:

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;
  StringRepository context;

  public void warmup(StringRepository context)
  {
    this.context = context;
  }

  public void sayhello()
  {
    System.out.println("Hello, " + context.get("name");
    context.put("http.response.header.Content-Type", "text/plain");
  }

  public void secret()
  {
    System.out.println(context,get(name) + ", you found the hidden page :)");
  }
}

Making nice-looking pages

Interesting as that side-trip into sending our page as plain text was, it's not much use for the bulk of web pages. Most web pages use HTML, and use markup such as <a href> for links and <p> for paragraphs. If we want to put this sort of stuff in our pages, we've got quite a few choices. Popular approaches used with the Servlet API include:

There are probably more. Realistically, you can use any of these with Mojasef, too. Mojasef also provides a few alternative options that (I feel) integrate better with the core application. To the above choices, Mojasef adds:

To show how this works, let's go back a bit, to our application without the text/plain:

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;

  public void sayhello(StringRepository context)
  {
    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));
  }
}

Now imagine we wish to "wrap" this content in a nice HTML web page. Here are the steps:

  1. Make sure there is a directory called templates in the current directory.
  2. Create a file default.tpl (in this case it could also be default.txt or default.html)
  3. add the following to the new file:
    <html><head><title>A greeting from Mojasef</title></head>
    <body>
    <img src='http://www.stringtree.org/mojasef/images/mojasef.jpg'/>
    <h2>Welcome</h2>
    My name is Mojasef,<br/>
    <pre>

    A Gentle Ramble

    This is a good place to start if you are not sure what Mojasef is, or what it has to offer. Installation, basic configuration, and some of the major features are introduced in a comfortable step-by-step approach.

    Contents
    1. Hello World
    2. Counting Hits
    3. User Sessions
    4. Permanent Configurations
    5. Catching All Accesses
    6. Finding Things Out
    7. Passing Things Back To The Server
    8. Sharing Context Between Several Methods
    9. Making Nice Looking Pages
    10. Magic With Templates
    Hello World

    In the time-honoured tradition, let's start with "hello, world". In keeping with the principles described above, we want to be able to reuse as much as possible that we have learned before. So let's start with an old "Hello.java" that we might have lying around after learning Java in the first place:

    public class Hello
    {
      public void sayhello()
      {
        System.out.println("Hello, World!");
      }
    
      public static void main(String[] args)
      {
        Hello hello = new Hello();
        hello.sayhello();
      }
    }
    

    To put this program on the web, we need to make the following changes to it: none at all :)

    To use this program with Mojasef:

    1. compile Hello.java so that you get a file Hello.class in your current directory
    2. run Mojasef using

      java -Dhttp.application$=Hello -jar moja-http.jar

    3. point your browser at http://localhost/sayhello

    If all that went according to plan, you should see "Hello World!". That was pretty straightforward, wasn't it.

    As an aside, note the "$", that little character is actually part of some key technology that gives mojasef its simple and flexible configuration power. See the manual for more details.

    Counting Hits

    Now, this is pretty simplistic, so far. So let's tighten it up a bit. First, Our "Hello" application may only be a dozen lines, but it's still too big. So let's remove some redundant code. We don't need any of that "main" nonsense, becuse mojasef already knows how to create an object and call a method.

    public class Hello
    {
      public void sayhello()
      {
        System.out.println("Hello, World!");
      }
    }
    

    That all looks neat enough, but it doesn't actually do much so far. How about remembering things between page requests? To keep it simple for this example, we'll just make it count accesses.

    public class Hello
    {
      int n = 1;
    
      public void sayhello()
      {
        System.out.println("Hello, World!");
        System.out.println("visit number " + n++);
      }
    }
    

    Try it. Stop the server (using Control-C, task manager or whatever), recompile Hello.java, and run Mojasef again. Refresh your browser a few times to see that it really is counting. Cool. And way simpler than messing about with the Servlet API.

    OK, those of you with servlet experience might be beginning to worry. Relying on member variables in a multi-threaded situation is extremely risky and a classic servlet problem. So this is a little simplistic as it stands. If you are getting a lot of hits and you really care about your hit count being "absolutely correct", you should probably wrap the increment in a synchronized block. On the other hand, you could sidestep the problem by reading the next section.

    User Sessions

    Counting is good, but sometimes we don't want to share a single value. How about if we want to keep a separate count for each visitor? This might seem tricky, but not in mojasef. Just run the server using:

      java "-Dhttp.application$=http.SessionWrapper Hello" -jar moja-http.jar

    To test this yourself you will either need to access it from different machines, or using different browsers. Firefox and Internet Explorer, for example. Point both your browsers at the same URL and try different combinations of refreshing the page to prove to yourself that the counts really are independent.

    Permanent Configurations

    At this point I'd be getting fed up with typing such a long command line. Luckily Mojasef allows you to store stuff like this in a file ready to be picked up when the server starts. Here's a simple way to do that:

    1. create a file in the current directory called "http.spec"
    2. put the following single line of text in it:

      http.application$=http.SessionWrapper Hello

    3. Now you can run the server using:

      java -jar moja-http.jar

    Catching all Accesses

    While playing with this, you may have noticed that it's got a pretty narrow view of what URLs to respond to. Anything other than /sayhello gets a 404 "not found" error. There are several ways to improve this, but one of the simplest is to rename the method from sayhello() to request(). request() is one of the method names that Mojasef looks for if it can't find a match on the URL.

    public class Hello
    {
      int n = 1;
    
      public void request()
      {
        System.out.println("Hello, World!");
        System.out.println("visit number " + n++);
      }
    }
    

    Now our server is much more polite. It will say "hello" to all visitors, whatever URL they ask for.

    As an aside, Mojasef will always look for specific names before trying more general options like request, so we can add another method:

    public class Hello
    {
      int n = 1;
    
      public void request()
      {
        System.out.println("Hello, World!");
        System.out.println("visit number " + n++);
      }
    
      public void secret()
      {
        System.out.println("you found the hidden page :)");
      }
    }
    

    Now pretty much every URL we can think of (such as http://localhost/wibble, or whatever) will give us the "Hello, World" message , but if we happen on http://localhost/secret we get the other message. Anyone for web services without all that fuss?

    Finding things out

    Placing our raw objects on the web is a cool thing to do, but so far, not really as useful as the ugly Servlet API. If nothing else we need to be able to look at the parameters passd to GET and POST requests, and maybe other things such as request headers, cookies, and system configurations. Luckily, Mojasef comes to our aid with this too.

    There are two major ways to get access to this kind of context information. I'll break with tradition in this simple tutorial, and introduce both of them, so you can get the idea of the possibilities. For the first approach, let's go back to our basic "hello" program and add a parameter to our method:

    import org.stringtree.StringFetcher;
    
    public class Hello
    {
      int n = 1;
    
      public void sayhello(StringFetcher context)
      {
        System.out.println("Hello, World!");
        System.out.println("visit number " + n++);
      }
    }
    

    As you can see, we have eventually needed to import an extra class. Don't worry, though. This class doesn't carry a lot of baggage. StringFetcher is a very simple interface consisting of two methods:

    • public Object getObject(String key);
    • public String get(String key);

    If you want to fetch something in the form of a String from the surrounding context, use get(String key). This method returns the string value of the named context object, or the empty string ("") if not present.

    If you want to fetch any other type of object, use getObject(String key) and cast the result if necessary. Note that if there is nothing stored with the named key, this methjod will return null, so it can also be used to check for the presence or absence of a value.

    To compile this class you will need to make sure that StringFetcher is in your compilation classpath. The simplest thing to do at the moment is to just put the whole moja-http.jar in the classpath. Later, you may prefer to use the much "lighter" stringtree-if.jar from the Stringtree project, which contains all the interfaces needed to write applications that use Mojasef, but contains no implementation code to slow down and clutter up compilation.

    To compile the class either place stringtree-if.jar or moja-http.jar in your classpath or use:

    javac -classpath moja-http.jar Hello.java

    As an aside, when Mojasef starts up, it will look for class directories and jar files in a lib directory, so when you find that you want to use external APIs or libraries in your applications or components, just pop them in there.

    Now we have a context to look in, we really ought to use this new parameter to fetch some information. let's print the originating IP address of the request and the browser identification header, and (to make our greeting more personal), the value of a supplied "name" parameter.

    import org.stringtree.StringFetcher;
    
    public class Hello
    {
      int n = 1;
    
      public void sayhello(StringFetcher context)
      {
    
        System.out.println("Hello, " + context.get("name");
        System.out.println("visit number " + n++);
        System.out.println("from IP: " + context.get("remote.address"));
        System.out.println("browser: " + context.get("http.request.header.User-Agent"));
      }
    }
    

    If you pop to the browser and request your mojasef URL (probably still http://localhost/sayhello), you should see something starting with

      Hello, visit number 1 from IP:
    Now if you pass in a parameter by using http://localhost/sayhello?name=Frank You should see a message starting with

      Hello, Frank visit number 2 from IP:

    If you want something other than an empty string to appear when no parameter is supplied, you can easily set a default value in the same place you sett http.application. Add the following line to http.spec and restart the server:

    name=Mystery Guest

    Now, viewing http://localhost/sayhello gives:

      Hello, Mystery Guest visit number 1 from IP:
    Passing things back to the server

    This is all simple enough, but the output is beginning to look a bit messy. Despite using "println" to put our text on separate lines, the web browser is treating it as HTML, and displaying it all on one line. A simple way to fix this is to set the output "content type" to text/plain to override the default. You may notice that the StringFetcher we are passing in to this method only has "get" methods, If we want to be able to "put" output values as well, we need to pass in a StringRepository instead. Let's modify our class by changing the import statement and the parameter declaration:

    import org.stringtree.StringRepository;
    
    public class Hello
    {
      int n = 1;
    
      public void sayhello(StringRepository context)
      {
        System.out.println("Hello, " + context.get("name");
        System.out.println("visit number " + n++);
        System.out.println("from IP: " + context.get("remote.address"));
        System.out.println("browser: " + context.get("http.request.header.User-Agent"));
      }
    }
    

    If you compile and run this, you'll notice that it behaves exactly as it did before. A StringRepository is also a StringFetcher, and provides all the same methods and results. StringRepository also provides two extra methods, with pretty obvious uses:

    • public void put(String name, Object value);
    • public void remove(String name);

    Actually, StringRepository also provides a clear() method, but using it in a Mojasef application can be a very quick way to screw up your program unless you know exactly what you are doing.

    To set the page content-type, let's add a line to put "text/plain" back into the context:

    import org.stringtree.StringRepository;
    
    public class Hello
    {
      int n = 1;
    
      public void sayhello(StringRepository context)
      {
        System.out.println("Hello, " + context.get("name");
        System.out.println("visit number " + n++);
        System.out.println("from IP: " + context.get("remote.address"));
        System.out.println("browser: " + context.get("http.request.header.User-Agent"));
    
        context.put("http.response.header.Content-Type", "text/plain");
      }
    }
    

    Compile the class and restart the server. You should now see your messages in glorious plain-text-o-vision.

    There are, of course, pleanty of other things you can put back into the context. Anything with a name starting with http.response.header. will be sent as an outgoing header. You can set the HTTP response code (e.g. 404 for missing page) using http.response.code, and set outgoing cookies by starting names with http.response.cookie.. You can also set any other value you like, to be used in a page template, but that will be introduced in a little while, below. For more details of any of this, see the manual.

    Sharing context between several methods

    Remember I mentioned another way of getting information from the server? If we want to keep our methods with no parameters (this is more usual when there are several other pre-existing methods in the class which we also want to make available on the web), we can make use of another mojasef feature. Before calling any method on our object, mojasef will first try the special method warmup. Just as with request, mojasef will look for warmup(StringRepository context), warmup(StringFetcher context), or warmup(). If you provide any of those public methods, mojasef will call it, and you can keep a copy of the supplied context if you want:

    import org.stringtree.StringRepository;
    
    public class Hello
    {
      int n = 1;
      StringRepository context;
    
      public void warmup(StringRepository context)
      {
        this.context = context;
      }
    
      public void sayhello()
      {
        System.out.println("Hello, " + context.get("name");
        context.put("http.response.header.Content-Type", "text/plain");
      }
    
      public void secret()
      {
        System.out.println(context,get(name) + ", you found the hidden page :)");
      }
    }
    

    Making nice-looking pages

    Interesting as that side-trip into sending our page as plain text was, it's not much use for the bulk of web pages. Most web pages use HTML, and use markup such as <a href> for links and <p> for paragraphs. If we want to put this sort of stuff in our pages, we've got quite a few choices. Popular approaches used with the Servlet API include:

    • Generate HTML as strings in our application, e.g. System.out.println("<b>this is important</b>");
    • Generate HTML using a special-purpose HTML-creation library (e.g. Jakarta ECS)
    • Some form of "page compilation" such as Java Server Pages
    • Some form of combined scripting/templating approach (e.g. velocity, FreeMarker, or Webmacro)
    • Generate an intermediate format (such as XML) in the code, and style it at run-time
    • Generate (roughly) plain text and run it through a markup inference process (e.g. Wiki markup or Structured Text)

    There are probably more. Realistically, you can use any of these with Mojasef, too. Mojasef also provides a few alternative options that (I feel) integrate better with the core application. To the above choices, Mojasef adds:

    • Templates without scripting
      Mojasef includes a powerful template processing system with no need for any kind of "embedded" scripting language. Common operations such as indexing through lists and showing optional information are done using a kind of algebra of templates, More complex or application-specific operations are written as regular Java, just like Mojasef applications and components. Remember the principle of self-similarity.
    • build HTML by assembling HTML fragments
      Mojasef's powerful "spec" mechanism allows large or small chunks of markup and text to be easily loaded from files, classpath resources or even remote URLs.

    To show how this works, let's go back a bit, to our application without the text/plain:

    import org.stringtree.StringRepository;
    
    public class Hello
    {
      int n = 1;
    
      public void sayhello(StringRepository context)
      {
        System.out.println("Hello, " + context.get("name");
        System.out.println("visit number " + n++);
        System.out.println("from IP: " + context.get("remote.address"));
        System.out.println("browser: " + context.get("http.request.header.User-Agent"));
      }
    }
    

    Now imagine we wish to "wrap" this content in a nice HTML web page. Here are the steps:

    1. Make sure there is a directory called templates in the current directory.
    2. Create a file default.tpl (in this case it could also be default.txt or default.html)
    3. add the following to the new file:
      <html><head><title>A greeting from Mojasef</title></head>
      <body>
      <img src='http://www.stringtree.org/mojasef/images/mojasef.jpg'/>
      <h2>Welcome</h2>
      My name is Mojasef,<br/>
      <pre>${CONTENT}</pre>
      </body>
      </html>
      
    4. Then (you don't need to restart the server) fetch the page http://localhost/sayhello again.

    You should see a decorated page with the generated content nicely laid out in a preformatted block. Try changing the template and fetch the page again. You should see it change each time. The important thing to note about this is that you do not need to change the application to use different templates.

    However, that's not all. Specifying such a default template causes it to be applied to all pages generated by the application. This may be just what you want, but you may want something special for some pages. There are a few ways of changing this.

    • You can decide which template to use in your application program:- put a value named page.template into the context, Mojasef will try and find a template with the same name as the value. If you put a value named page.class, Mojasef will look in the context or a value named template.class.yourvalue and look for a template with the same name.
    • You can specify a template with the same name as your application method, and it will be used in preference to the default.

    To show all these in action, let's add a few small methods to our application;

    import org.stringtree.StringRepository;
    
    public class Hello
    {
      int n = 1;
    
      public void sayhello(StringRepository context)
      {
        System.out.println("Hello, " + context.get("name");
        System.out.println("visit number " + n++);
        System.out.println("from IP: " + context.get("remote.address"));
        System.out.println("browser: " + context.get("http.request.header.User-Agent"));
      }
    
      public void ex1(StringRepository context)
      {
        System.out.println("This uses an explicit template");
        context.put("page.template", "whatever");
      }
    
      public void ex2(StringRepository context)
      {
        System.out.println("This uses a page class");
        context.put("page.class", "thing");
      }
    
      public void ex3(StringRepository context)
      {
        System.out.println("This uses a template with the same name");
      }
    }
    

    If you compile this and restart the server, then fetch the pages (using, for example http://localhost/ex1) you will see that they all still use the same default template. Mojasef tried to find the templates they ask for, but we haven't created them yet, so it falls back to what it knows. We can add appropriate templates to the system and see them in action. I'll let you create these templates as you like. Just remember that the generated page content will appear wherever you put ${CONTENT}. Any other context value can also be displayed by placing its name between ${ and }.

    1. Create a template (in the templates directory, remember) called whatever.tpl, and fetch http://localhost/ex1
    2. Add a line template.class.thing=whatever to http.spec, restart the server, and fetch http://localhost/ex2. You'll see that it uses the template you just created.
    3. Create a template called ex3.tpl, and fetch http://localhost/ex3.

    If all you want to do is return some static text, or examine some context values, without even running any application code, you can do that too.

    1. Create a template called ex4.tpl, and fetch http://localhost/ex4.

    Magic with Templates

    As a final twist, all the templates we have used so far are just what Mojasef considers simple templates. Templates can be made much more powerful by setting and invoking context values in the template itself, and by using the algebra of templates to process complex context values. More details can be found in the manual.

    Just to show how this can be useful, try the following:

    1. Create a template called dump.tpl with the following text in it:
        <table>
        
        <tr><th colspan='2'>Request Context - only available during a request</th></tr>
        <tr><th>Name</th><th>Value</th></tr>
        ${request.context*row}
        
        <tr><th colspan='2'>System Context - available at any time</th></tr>
        <tr><th>Name</th><th>Value</th></tr>
        ${system.context*row}
        
        </table>
        
    2. Create a template called row.tpl with the following text in it:
        <tr><td>${CONTENT}</td><td>${^CONTENT}</td></tr>
        
    3. Fetch http://localhost/dump
    4. Marvel at the huge collection of context names and values for you to use in your templates and applications.

    That's the end of this simple demonstration. For more information about what else you can do with Mojasef, you can either check out the next example Making a Quiz, or head straight for the manual. Have Fun!

    </pre> </body> </html>
  4. Then (you don't need to restart the server) fetch the page http://localhost/sayhello again.

You should see a decorated page with the generated content nicely laid out in a preformatted block. Try changing the template and fetch the page again. You should see it change each time. The important thing to note about this is that you do not need to change the application to use different templates.

However, that's not all. Specifying such a default template causes it to be applied to all pages generated by the application. This may be just what you want, but you may want something special for some pages. There are a few ways of changing this.

To show all these in action, let's add a few small methods to our application;

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;

  public void sayhello(StringRepository context)
  {
    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));
  }

  public void ex1(StringRepository context)
  {
    System.out.println("This uses an explicit template");
    context.put("page.template", "whatever");
  }

  public void ex2(StringRepository context)
  {
    System.out.println("This uses a page class");
    context.put("page.class", "thing");
  }

  public void ex3(StringRepository context)
  {
    System.out.println("This uses a template with the same name");
  }
}

If you compile this and restart the server, then fetch the pages (using, for example http://localhost/ex1) you will see that they all still use the same default template. Mojasef tried to find the templates they ask for, but we haven't created them yet, so it falls back to what it knows. We can add appropriate templates to the system and see them in action. I'll let you create these templates as you like. Just remember that the generated page content will appear wherever you put

A Gentle Ramble

This is a good place to start if you are not sure what Mojasef is, or what it has to offer. Installation, basic configuration, and some of the major features are introduced in a comfortable step-by-step approach.

Contents
  1. Hello World
  2. Counting Hits
  3. User Sessions
  4. Permanent Configurations
  5. Catching All Accesses
  6. Finding Things Out
  7. Passing Things Back To The Server
  8. Sharing Context Between Several Methods
  9. Making Nice Looking Pages
  10. Magic With Templates
Hello World

In the time-honoured tradition, let's start with "hello, world". In keeping with the principles described above, we want to be able to reuse as much as possible that we have learned before. So let's start with an old "Hello.java" that we might have lying around after learning Java in the first place:

public class Hello
{
  public void sayhello()
  {
    System.out.println("Hello, World!");
  }

  public static void main(String[] args)
  {
    Hello hello = new Hello();
    hello.sayhello();
  }
}

To put this program on the web, we need to make the following changes to it: none at all :)

To use this program with Mojasef:

  1. compile Hello.java so that you get a file Hello.class in your current directory
  2. run Mojasef using

    java -Dhttp.application$=Hello -jar moja-http.jar

  3. point your browser at http://localhost/sayhello

If all that went according to plan, you should see "Hello World!". That was pretty straightforward, wasn't it.

As an aside, note the "$", that little character is actually part of some key technology that gives mojasef its simple and flexible configuration power. See the manual for more details.

Counting Hits

Now, this is pretty simplistic, so far. So let's tighten it up a bit. First, Our "Hello" application may only be a dozen lines, but it's still too big. So let's remove some redundant code. We don't need any of that "main" nonsense, becuse mojasef already knows how to create an object and call a method.

public class Hello
{
  public void sayhello()
  {
    System.out.println("Hello, World!");
  }
}

That all looks neat enough, but it doesn't actually do much so far. How about remembering things between page requests? To keep it simple for this example, we'll just make it count accesses.

public class Hello
{
  int n = 1;

  public void sayhello()
  {
    System.out.println("Hello, World!");
    System.out.println("visit number " + n++);
  }
}

Try it. Stop the server (using Control-C, task manager or whatever), recompile Hello.java, and run Mojasef again. Refresh your browser a few times to see that it really is counting. Cool. And way simpler than messing about with the Servlet API.

OK, those of you with servlet experience might be beginning to worry. Relying on member variables in a multi-threaded situation is extremely risky and a classic servlet problem. So this is a little simplistic as it stands. If you are getting a lot of hits and you really care about your hit count being "absolutely correct", you should probably wrap the increment in a synchronized block. On the other hand, you could sidestep the problem by reading the next section.

User Sessions

Counting is good, but sometimes we don't want to share a single value. How about if we want to keep a separate count for each visitor? This might seem tricky, but not in mojasef. Just run the server using:

To test this yourself you will either need to access it from different machines, or using different browsers. Firefox and Internet Explorer, for example. Point both your browsers at the same URL and try different combinations of refreshing the page to prove to yourself that the counts really are independent.

Permanent Configurations

At this point I'd be getting fed up with typing such a long command line. Luckily Mojasef allows you to store stuff like this in a file ready to be picked up when the server starts. Here's a simple way to do that:

  1. create a file in the current directory called "http.spec"
  2. put the following single line of text in it:

    http.application$=http.SessionWrapper Hello

  3. Now you can run the server using:

    java -jar moja-http.jar

Catching all Accesses

While playing with this, you may have noticed that it's got a pretty narrow view of what URLs to respond to. Anything other than /sayhello gets a 404 "not found" error. There are several ways to improve this, but one of the simplest is to rename the method from sayhello() to request(). request() is one of the method names that Mojasef looks for if it can't find a match on the URL.

public class Hello
{
  int n = 1;

  public void request()
  {
    System.out.println("Hello, World!");
    System.out.println("visit number " + n++);
  }
}

Now our server is much more polite. It will say "hello" to all visitors, whatever URL they ask for.

As an aside, Mojasef will always look for specific names before trying more general options like request, so we can add another method:

public class Hello
{
  int n = 1;

  public void request()
  {
    System.out.println("Hello, World!");
    System.out.println("visit number " + n++);
  }

  public void secret()
  {
    System.out.println("you found the hidden page :)");
  }
}

Now pretty much every URL we can think of (such as http://localhost/wibble, or whatever) will give us the "Hello, World" message , but if we happen on http://localhost/secret we get the other message. Anyone for web services without all that fuss?

Finding things out

Placing our raw objects on the web is a cool thing to do, but so far, not really as useful as the ugly Servlet API. If nothing else we need to be able to look at the parameters passd to GET and POST requests, and maybe other things such as request headers, cookies, and system configurations. Luckily, Mojasef comes to our aid with this too.

There are two major ways to get access to this kind of context information. I'll break with tradition in this simple tutorial, and introduce both of them, so you can get the idea of the possibilities. For the first approach, let's go back to our basic "hello" program and add a parameter to our method:

import org.stringtree.StringFetcher;

public class Hello
{
  int n = 1;

  public void sayhello(StringFetcher context)
  {
    System.out.println("Hello, World!");
    System.out.println("visit number " + n++);
  }
}

As you can see, we have eventually needed to import an extra class. Don't worry, though. This class doesn't carry a lot of baggage. StringFetcher is a very simple interface consisting of two methods:

If you want to fetch something in the form of a String from the surrounding context, use get(String key). This method returns the string value of the named context object, or the empty string ("") if not present.

If you want to fetch any other type of object, use getObject(String key) and cast the result if necessary. Note that if there is nothing stored with the named key, this methjod will return null, so it can also be used to check for the presence or absence of a value.

To compile this class you will need to make sure that StringFetcher is in your compilation classpath. The simplest thing to do at the moment is to just put the whole moja-http.jar in the classpath. Later, you may prefer to use the much "lighter" stringtree-if.jar from the Stringtree project, which contains all the interfaces needed to write applications that use Mojasef, but contains no implementation code to slow down and clutter up compilation.

To compile the class either place stringtree-if.jar or moja-http.jar in your classpath or use:

javac -classpath moja-http.jar Hello.java

As an aside, when Mojasef starts up, it will look for class directories and jar files in a lib directory, so when you find that you want to use external APIs or libraries in your applications or components, just pop them in there.

Now we have a context to look in, we really ought to use this new parameter to fetch some information. let's print the originating IP address of the request and the browser identification header, and (to make our greeting more personal), the value of a supplied "name" parameter.

import org.stringtree.StringFetcher;

public class Hello
{
  int n = 1;

  public void sayhello(StringFetcher context)
  {

    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));
  }
}

If you pop to the browser and request your mojasef URL (probably still http://localhost/sayhello), you should see something starting with

Now if you pass in a parameter by using http://localhost/sayhello?name=Frank You should see a message starting with

If you want something other than an empty string to appear when no parameter is supplied, you can easily set a default value in the same place you sett http.application. Add the following line to http.spec and restart the server:

name=Mystery Guest

Now, viewing http://localhost/sayhello gives:

Passing things back to the server

This is all simple enough, but the output is beginning to look a bit messy. Despite using "println" to put our text on separate lines, the web browser is treating it as HTML, and displaying it all on one line. A simple way to fix this is to set the output "content type" to text/plain to override the default. You may notice that the StringFetcher we are passing in to this method only has "get" methods, If we want to be able to "put" output values as well, we need to pass in a StringRepository instead. Let's modify our class by changing the import statement and the parameter declaration:

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;

  public void sayhello(StringRepository context)
  {
    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));
  }
}

If you compile and run this, you'll notice that it behaves exactly as it did before. A StringRepository is also a StringFetcher, and provides all the same methods and results. StringRepository also provides two extra methods, with pretty obvious uses:

Actually, StringRepository also provides a clear() method, but using it in a Mojasef application can be a very quick way to screw up your program unless you know exactly what you are doing.

To set the page content-type, let's add a line to put "text/plain" back into the context:

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;

  public void sayhello(StringRepository context)
  {
    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));

    context.put("http.response.header.Content-Type", "text/plain");
  }
}

Compile the class and restart the server. You should now see your messages in glorious plain-text-o-vision.

There are, of course, pleanty of other things you can put back into the context. Anything with a name starting with http.response.header. will be sent as an outgoing header. You can set the HTTP response code (e.g. 404 for missing page) using http.response.code, and set outgoing cookies by starting names with http.response.cookie.. You can also set any other value you like, to be used in a page template, but that will be introduced in a little while, below. For more details of any of this, see the manual.

Sharing context between several methods

Remember I mentioned another way of getting information from the server? If we want to keep our methods with no parameters (this is more usual when there are several other pre-existing methods in the class which we also want to make available on the web), we can make use of another mojasef feature. Before calling any method on our object, mojasef will first try the special method warmup. Just as with request, mojasef will look for warmup(StringRepository context), warmup(StringFetcher context), or warmup(). If you provide any of those public methods, mojasef will call it, and you can keep a copy of the supplied context if you want:

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;
  StringRepository context;

  public void warmup(StringRepository context)
  {
    this.context = context;
  }

  public void sayhello()
  {
    System.out.println("Hello, " + context.get("name");
    context.put("http.response.header.Content-Type", "text/plain");
  }

  public void secret()
  {
    System.out.println(context,get(name) + ", you found the hidden page :)");
  }
}

Making nice-looking pages

Interesting as that side-trip into sending our page as plain text was, it's not much use for the bulk of web pages. Most web pages use HTML, and use markup such as <a href> for links and <p> for paragraphs. If we want to put this sort of stuff in our pages, we've got quite a few choices. Popular approaches used with the Servlet API include:

There are probably more. Realistically, you can use any of these with Mojasef, too. Mojasef also provides a few alternative options that (I feel) integrate better with the core application. To the above choices, Mojasef adds:

To show how this works, let's go back a bit, to our application without the text/plain:

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;

  public void sayhello(StringRepository context)
  {
    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));
  }
}

Now imagine we wish to "wrap" this content in a nice HTML web page. Here are the steps:

  1. Make sure there is a directory called templates in the current directory.
  2. Create a file default.tpl (in this case it could also be default.txt or default.html)
  3. add the following to the new file:
    <html><head><title>A greeting from Mojasef</title></head>
    <body>
    <img src='http://www.stringtree.org/mojasef/images/mojasef.jpg'/>
    <h2>Welcome</h2>
    My name is Mojasef,<br/>
    <pre>${CONTENT}</pre>
    </body>
    </html>
    
  4. Then (you don't need to restart the server) fetch the page http://localhost/sayhello again.

You should see a decorated page with the generated content nicely laid out in a preformatted block. Try changing the template and fetch the page again. You should see it change each time. The important thing to note about this is that you do not need to change the application to use different templates.

However, that's not all. Specifying such a default template causes it to be applied to all pages generated by the application. This may be just what you want, but you may want something special for some pages. There are a few ways of changing this.

To show all these in action, let's add a few small methods to our application;

import org.stringtree.StringRepository;

public class Hello
{
  int n = 1;

  public void sayhello(StringRepository context)
  {
    System.out.println("Hello, " + context.get("name");
    System.out.println("visit number " + n++);
    System.out.println("from IP: " + context.get("remote.address"));
    System.out.println("browser: " + context.get("http.request.header.User-Agent"));
  }

  public void ex1(StringRepository context)
  {
    System.out.println("This uses an explicit template");
    context.put("page.template", "whatever");
  }

  public void ex2(StringRepository context)
  {
    System.out.println("This uses a page class");
    context.put("page.class", "thing");
  }

  public void ex3(StringRepository context)
  {
    System.out.println("This uses a template with the same name");
  }
}

If you compile this and restart the server, then fetch the pages (using, for example http://localhost/ex1) you will see that they all still use the same default template. Mojasef tried to find the templates they ask for, but we haven't created them yet, so it falls back to what it knows. We can add appropriate templates to the system and see them in action. I'll let you create these templates as you like. Just remember that the generated page content will appear wherever you put ${CONTENT}. Any other context value can also be displayed by placing its name between ${ and }.

  1. Create a template (in the templates directory, remember) called whatever.tpl, and fetch http://localhost/ex1
  2. Add a line template.class.thing=whatever to http.spec, restart the server, and fetch http://localhost/ex2. You'll see that it uses the template you just created.
  3. Create a template called ex3.tpl, and fetch http://localhost/ex3.

If all you want to do is return some static text, or examine some context values, without even running any application code, you can do that too.

  1. Create a template called ex4.tpl, and fetch http://localhost/ex4.

Magic with Templates

As a final twist, all the templates we have used so far are just what Mojasef considers simple templates. Templates can be made much more powerful by setting and invoking context values in the template itself, and by using the algebra of templates to process complex context values. More details can be found in the manual.

Just to show how this can be useful, try the following:

  1. Create a template called dump.tpl with the following text in it:
      <table>
      
      <tr><th colspan='2'>Request Context - only available during a request</th></tr>
      <tr><th>Name</th><th>Value</th></tr>
      ${request.context*row}
      
      <tr><th colspan='2'>System Context - available at any time</th></tr>
      <tr><th>Name</th><th>Value</th></tr>
      ${system.context*row}
      
      </table>
      
  2. Create a template called row.tpl with the following text in it:
      <tr><td>${CONTENT}</td><td>${^CONTENT}</td></tr>
      
  3. Fetch http://localhost/dump
  4. Marvel at the huge collection of context names and values for you to use in your templates and applications.

That's the end of this simple demonstration. For more information about what else you can do with Mojasef, you can either check out the next example Making a Quiz, or head straight for the manual. Have Fun!

. Any other context value can also be displayed by placing its name between .

  1. Create a template (in the templates directory, remember) called whatever.tpl, and fetch http://localhost/ex1
  2. Add a line template.class.thing=whatever to http.spec, restart the server, and fetch http://localhost/ex2. You'll see that it uses the template you just created.
  3. Create a template called ex3.tpl, and fetch http://localhost/ex3.

If all you want to do is return some static text, or examine some context values, without even running any application code, you can do that too.

  1. Create a template called ex4.tpl, and fetch http://localhost/ex4.

Magic with Templates

As a final twist, all the templates we have used so far are just what Mojasef considers simple templates. Templates can be made much more powerful by setting and invoking context values in the template itself, and by using the algebra of templates to process complex context values. More details can be found in the manual.

Just to show how this can be useful, try the following:

  1. Create a template called dump.tpl with the following text in it:
      <table>
      
      <tr><th colspan='2'>Request Context - only available during a request</th></tr>
      <tr><th>Name</th><th>Value</th></tr>
      
      
      <tr><th colspan='2'>System Context - available at any time</th></tr>
      <tr><th>Name</th><th>Value</th></tr>
      
      
      </table>
      
  2. Create a template called row.tpl with the following text in it:
      <tr><td>

      A Gentle Ramble

      This is a good place to start if you are not sure what Mojasef is, or what it has to offer. Installation, basic configuration, and some of the major features are introduced in a comfortable step-by-step approach.

      Contents
      1. Hello World
      2. Counting Hits
      3. User Sessions
      4. Permanent Configurations
      5. Catching All Accesses
      6. Finding Things Out
      7. Passing Things Back To The Server
      8. Sharing Context Between Several Methods
      9. Making Nice Looking Pages
      10. Magic With Templates
      Hello World

      In the time-honoured tradition, let's start with "hello, world". In keeping with the principles described above, we want to be able to reuse as much as possible that we have learned before. So let's start with an old "Hello.java" that we might have lying around after learning Java in the first place:

      public class Hello
      {
        public void sayhello()
        {
          System.out.println("Hello, World!");
        }
      
        public static void main(String[] args)
        {
          Hello hello = new Hello();
          hello.sayhello();
        }
      }
      

      To put this program on the web, we need to make the following changes to it: none at all :)

      To use this program with Mojasef:

      1. compile Hello.java so that you get a file Hello.class in your current directory
      2. run Mojasef using

        java -Dhttp.application$=Hello -jar moja-http.jar

      3. point your browser at http://localhost/sayhello

      If all that went according to plan, you should see "Hello World!". That was pretty straightforward, wasn't it.

      As an aside, note the "$", that little character is actually part of some key technology that gives mojasef its simple and flexible configuration power. See the manual for more details.

      Counting Hits

      Now, this is pretty simplistic, so far. So let's tighten it up a bit. First, Our "Hello" application may only be a dozen lines, but it's still too big. So let's remove some redundant code. We don't need any of that "main" nonsense, becuse mojasef already knows how to create an object and call a method.

      public class Hello
      {
        public void sayhello()
        {
          System.out.println("Hello, World!");
        }
      }
      

      That all looks neat enough, but it doesn't actually do much so far. How about remembering things between page requests? To keep it simple for this example, we'll just make it count accesses.

      public class Hello
      {
        int n = 1;
      
        public void sayhello()
        {
          System.out.println("Hello, World!");
          System.out.println("visit number " + n++);
        }
      }
      

      Try it. Stop the server (using Control-C, task manager or whatever), recompile Hello.java, and run Mojasef again. Refresh your browser a few times to see that it really is counting. Cool. And way simpler than messing about with the Servlet API.

      OK, those of you with servlet experience might be beginning to worry. Relying on member variables in a multi-threaded situation is extremely risky and a classic servlet problem. So this is a little simplistic as it stands. If you are getting a lot of hits and you really care about your hit count being "absolutely correct", you should probably wrap the increment in a synchronized block. On the other hand, you could sidestep the problem by reading the next section.

      User Sessions

      Counting is good, but sometimes we don't want to share a single value. How about if we want to keep a separate count for each visitor? This might seem tricky, but not in mojasef. Just run the server using:

        java "-Dhttp.application$=http.SessionWrapper Hello" -jar moja-http.jar

      To test this yourself you will either need to access it from different machines, or using different browsers. Firefox and Internet Explorer, for example. Point both your browsers at the same URL and try different combinations of refreshing the page to prove to yourself that the counts really are independent.

      Permanent Configurations

      At this point I'd be getting fed up with typing such a long command line. Luckily Mojasef allows you to store stuff like this in a file ready to be picked up when the server starts. Here's a simple way to do that:

      1. create a file in the current directory called "http.spec"
      2. put the following single line of text in it:

        http.application$=http.SessionWrapper Hello

      3. Now you can run the server using:

        java -jar moja-http.jar

      Catching all Accesses

      While playing with this, you may have noticed that it's got a pretty narrow view of what URLs to respond to. Anything other than /sayhello gets a 404 "not found" error. There are several ways to improve this, but one of the simplest is to rename the method from sayhello() to request(). request() is one of the method names that Mojasef looks for if it can't find a match on the URL.

      public class Hello
      {
        int n = 1;
      
        public void request()
        {
          System.out.println("Hello, World!");
          System.out.println("visit number " + n++);
        }
      }
      

      Now our server is much more polite. It will say "hello" to all visitors, whatever URL they ask for.

      As an aside, Mojasef will always look for specific names before trying more general options like request, so we can add another method:

      public class Hello
      {
        int n = 1;
      
        public void request()
        {
          System.out.println("Hello, World!");
          System.out.println("visit number " + n++);
        }
      
        public void secret()
        {
          System.out.println("you found the hidden page :)");
        }
      }
      

      Now pretty much every URL we can think of (such as http://localhost/wibble, or whatever) will give us the "Hello, World" message , but if we happen on http://localhost/secret we get the other message. Anyone for web services without all that fuss?

      Finding things out

      Placing our raw objects on the web is a cool thing to do, but so far, not really as useful as the ugly Servlet API. If nothing else we need to be able to look at the parameters passd to GET and POST requests, and maybe other things such as request headers, cookies, and system configurations. Luckily, Mojasef comes to our aid with this too.

      There are two major ways to get access to this kind of context information. I'll break with tradition in this simple tutorial, and introduce both of them, so you can get the idea of the possibilities. For the first approach, let's go back to our basic "hello" program and add a parameter to our method:

      import org.stringtree.StringFetcher;
      
      public class Hello
      {
        int n = 1;
      
        public void sayhello(StringFetcher context)
        {
          System.out.println("Hello, World!");
          System.out.println("visit number " + n++);
        }
      }
      

      As you can see, we have eventually needed to import an extra class. Don't worry, though. This class doesn't carry a lot of baggage. StringFetcher is a very simple interface consisting of two methods:

      • public Object getObject(String key);
      • public String get(String key);

      If you want to fetch something in the form of a String from the surrounding context, use get(String key). This method returns the string value of the named context object, or the empty string ("") if not present.

      If you want to fetch any other type of object, use getObject(String key) and cast the result if necessary. Note that if there is nothing stored with the named key, this methjod will return null, so it can also be used to check for the presence or absence of a value.

      To compile this class you will need to make sure that StringFetcher is in your compilation classpath. The simplest thing to do at the moment is to just put the whole moja-http.jar in the classpath. Later, you may prefer to use the much "lighter" stringtree-if.jar from the Stringtree project, which contains all the interfaces needed to write applications that use Mojasef, but contains no implementation code to slow down and clutter up compilation.

      To compile the class either place stringtree-if.jar or moja-http.jar in your classpath or use:

      javac -classpath moja-http.jar Hello.java

      As an aside, when Mojasef starts up, it will look for class directories and jar files in a lib directory, so when you find that you want to use external APIs or libraries in your applications or components, just pop them in there.

      Now we have a context to look in, we really ought to use this new parameter to fetch some information. let's print the originating IP address of the request and the browser identification header, and (to make our greeting more personal), the value of a supplied "name" parameter.

      import org.stringtree.StringFetcher;
      
      public class Hello
      {
        int n = 1;
      
        public void sayhello(StringFetcher context)
        {
      
          System.out.println("Hello, " + context.get("name");
          System.out.println("visit number " + n++);
          System.out.println("from IP: " + context.get("remote.address"));
          System.out.println("browser: " + context.get("http.request.header.User-Agent"));
        }
      }
      

      If you pop to the browser and request your mojasef URL (probably still http://localhost/sayhello), you should see something starting with

        Hello, visit number 1 from IP:
      Now if you pass in a parameter by using http://localhost/sayhello?name=Frank You should see a message starting with

        Hello, Frank visit number 2 from IP:

      If you want something other than an empty string to appear when no parameter is supplied, you can easily set a default value in the same place you sett http.application. Add the following line to http.spec and restart the server:

      name=Mystery Guest

      Now, viewing http://localhost/sayhello gives:

        Hello, Mystery Guest visit number 1 from IP:
      Passing things back to the server

      This is all simple enough, but the output is beginning to look a bit messy. Despite using "println" to put our text on separate lines, the web browser is treating it as HTML, and displaying it all on one line. A simple way to fix this is to set the output "content type" to text/plain to override the default. You may notice that the StringFetcher we are passing in to this method only has "get" methods, If we want to be able to "put" output values as well, we need to pass in a StringRepository instead. Let's modify our class by changing the import statement and the parameter declaration:

      import org.stringtree.StringRepository;
      
      public class Hello
      {
        int n = 1;
      
        public void sayhello(StringRepository context)
        {
          System.out.println("Hello, " + context.get("name");
          System.out.println("visit number " + n++);
          System.out.println("from IP: " + context.get("remote.address"));
          System.out.println("browser: " + context.get("http.request.header.User-Agent"));
        }
      }
      

      If you compile and run this, you'll notice that it behaves exactly as it did before. A StringRepository is also a StringFetcher, and provides all the same methods and results. StringRepository also provides two extra methods, with pretty obvious uses:

      • public void put(String name, Object value);
      • public void remove(String name);

      Actually, StringRepository also provides a clear() method, but using it in a Mojasef application can be a very quick way to screw up your program unless you know exactly what you are doing.

      To set the page content-type, let's add a line to put "text/plain" back into the context:

      import org.stringtree.StringRepository;
      
      public class Hello
      {
        int n = 1;
      
        public void sayhello(StringRepository context)
        {
          System.out.println("Hello, " + context.get("name");
          System.out.println("visit number " + n++);
          System.out.println("from IP: " + context.get("remote.address"));
          System.out.println("browser: " + context.get("http.request.header.User-Agent"));
      
          context.put("http.response.header.Content-Type", "text/plain");
        }
      }
      

      Compile the class and restart the server. You should now see your messages in glorious plain-text-o-vision.

      There are, of course, pleanty of other things you can put back into the context. Anything with a name starting with http.response.header. will be sent as an outgoing header. You can set the HTTP response code (e.g. 404 for missing page) using http.response.code, and set outgoing cookies by starting names with http.response.cookie.. You can also set any other value you like, to be used in a page template, but that will be introduced in a little while, below. For more details of any of this, see the manual.

      Sharing context between several methods

      Remember I mentioned another way of getting information from the server? If we want to keep our methods with no parameters (this is more usual when there are several other pre-existing methods in the class which we also want to make available on the web), we can make use of another mojasef feature. Before calling any method on our object, mojasef will first try the special method warmup. Just as with request, mojasef will look for warmup(StringRepository context), warmup(StringFetcher context), or warmup(). If you provide any of those public methods, mojasef will call it, and you can keep a copy of the supplied context if you want:

      import org.stringtree.StringRepository;
      
      public class Hello
      {
        int n = 1;
        StringRepository context;
      
        public void warmup(StringRepository context)
        {
          this.context = context;
        }
      
        public void sayhello()
        {
          System.out.println("Hello, " + context.get("name");
          context.put("http.response.header.Content-Type", "text/plain");
        }
      
        public void secret()
        {
          System.out.println(context,get(name) + ", you found the hidden page :)");
        }
      }
      

      Making nice-looking pages

      Interesting as that side-trip into sending our page as plain text was, it's not much use for the bulk of web pages. Most web pages use HTML, and use markup such as <a href> for links and <p> for paragraphs. If we want to put this sort of stuff in our pages, we've got quite a few choices. Popular approaches used with the Servlet API include:

      • Generate HTML as strings in our application, e.g. System.out.println("<b>this is important</b>");
      • Generate HTML using a special-purpose HTML-creation library (e.g. Jakarta ECS)
      • Some form of "page compilation" such as Java Server Pages
      • Some form of combined scripting/templating approach (e.g. velocity, FreeMarker, or Webmacro)
      • Generate an intermediate format (such as XML) in the code, and style it at run-time
      • Generate (roughly) plain text and run it through a markup inference process (e.g. Wiki markup or Structured Text)

      There are probably more. Realistically, you can use any of these with Mojasef, too. Mojasef also provides a few alternative options that (I feel) integrate better with the core application. To the above choices, Mojasef adds:

      • Templates without scripting
        Mojasef includes a powerful template processing system with no need for any kind of "embedded" scripting language. Common operations such as indexing through lists and showing optional information are done using a kind of algebra of templates, More complex or application-specific operations are written as regular Java, just like Mojasef applications and components. Remember the principle of self-similarity.
      • build HTML by assembling HTML fragments
        Mojasef's powerful "spec" mechanism allows large or small chunks of markup and text to be easily loaded from files, classpath resources or even remote URLs.

      To show how this works, let's go back a bit, to our application without the text/plain:

      import org.stringtree.StringRepository;
      
      public class Hello
      {
        int n = 1;
      
        public void sayhello(StringRepository context)
        {
          System.out.println("Hello, " + context.get("name");
          System.out.println("visit number " + n++);
          System.out.println("from IP: " + context.get("remote.address"));
          System.out.println("browser: " + context.get("http.request.header.User-Agent"));
        }
      }
      

      Now imagine we wish to "wrap" this content in a nice HTML web page. Here are the steps:

      1. Make sure there is a directory called templates in the current directory.
      2. Create a file default.tpl (in this case it could also be default.txt or default.html)
      3. add the following to the new file:
        <html><head><title>A greeting from Mojasef</title></head>
        <body>
        <img src='http://www.stringtree.org/mojasef/images/mojasef.jpg'/>
        <h2>Welcome</h2>
        My name is Mojasef,<br/>
        <pre>${CONTENT}</pre>
        </body>
        </html>
        
      4. Then (you don't need to restart the server) fetch the page http://localhost/sayhello again.

      You should see a decorated page with the generated content nicely laid out in a preformatted block. Try changing the template and fetch the page again. You should see it change each time. The important thing to note about this is that you do not need to change the application to use different templates.

      However, that's not all. Specifying such a default template causes it to be applied to all pages generated by the application. This may be just what you want, but you may want something special for some pages. There are a few ways of changing this.

      • You can decide which template to use in your application program:- put a value named page.template into the context, Mojasef will try and find a template with the same name as the value. If you put a value named page.class, Mojasef will look in the context or a value named template.class.yourvalue and look for a template with the same name.
      • You can specify a template with the same name as your application method, and it will be used in preference to the default.

      To show all these in action, let's add a few small methods to our application;

      import org.stringtree.StringRepository;
      
      public class Hello
      {
        int n = 1;
      
        public void sayhello(StringRepository context)
        {
          System.out.println("Hello, " + context.get("name");
          System.out.println("visit number " + n++);
          System.out.println("from IP: " + context.get("remote.address"));
          System.out.println("browser: " + context.get("http.request.header.User-Agent"));
        }
      
        public void ex1(StringRepository context)
        {
          System.out.println("This uses an explicit template");
          context.put("page.template", "whatever");
        }
      
        public void ex2(StringRepository context)
        {
          System.out.println("This uses a page class");
          context.put("page.class", "thing");
        }
      
        public void ex3(StringRepository context)
        {
          System.out.println("This uses a template with the same name");
        }
      }
      

      If you compile this and restart the server, then fetch the pages (using, for example http://localhost/ex1) you will see that they all still use the same default template. Mojasef tried to find the templates they ask for, but we haven't created them yet, so it falls back to what it knows. We can add appropriate templates to the system and see them in action. I'll let you create these templates as you like. Just remember that the generated page content will appear wherever you put ${CONTENT}. Any other context value can also be displayed by placing its name between ${ and }.

      1. Create a template (in the templates directory, remember) called whatever.tpl, and fetch http://localhost/ex1
      2. Add a line template.class.thing=whatever to http.spec, restart the server, and fetch http://localhost/ex2. You'll see that it uses the template you just created.
      3. Create a template called ex3.tpl, and fetch http://localhost/ex3.

      If all you want to do is return some static text, or examine some context values, without even running any application code, you can do that too.

      1. Create a template called ex4.tpl, and fetch http://localhost/ex4.

      Magic with Templates

      As a final twist, all the templates we have used so far are just what Mojasef considers simple templates. Templates can be made much more powerful by setting and invoking context values in the template itself, and by using the algebra of templates to process complex context values. More details can be found in the manual.

      Just to show how this can be useful, try the following:

      1. Create a template called dump.tpl with the following text in it:
          <table>
          
          <tr><th colspan='2'>Request Context - only available during a request</th></tr>
          <tr><th>Name</th><th>Value</th></tr>
          ${request.context*row}
          
          <tr><th colspan='2'>System Context - available at any time</th></tr>
          <tr><th>Name</th><th>Value</th></tr>
          ${system.context*row}
          
          </table>
          
      2. Create a template called row.tpl with the following text in it:
          <tr><td>${CONTENT}</td><td>${^CONTENT}</td></tr>
          
      3. Fetch http://localhost/dump
      4. Marvel at the huge collection of context names and values for you to use in your templates and applications.

      That's the end of this simple demonstration. For more information about what else you can do with Mojasef, you can either check out the next example Making a Quiz, or head straight for the manual. Have Fun!

      </td><td></td></tr>
  3. Fetch http://localhost/dump
  4. Marvel at the huge collection of context names and values for you to use in your templates and applications.

That's the end of this simple demonstration. For more information about what else you can do with Mojasef, you can either check out the next example Making a Quiz, or head straight for the manual. Have Fun!


Creative Commons License
This site is licensed under a Creative Commons License