JavaServer

Using Page Compilation


Contents / New Features / Administrator Docs / Developer Docs / Index / Page Comp Intro

This document explains how to use page compilation to create hybrid HTML/Java pages:

Introduction to Page Compilation

Putting information on the Web is not a difficult task. The Web is designed to accommodate formatted information, divided into pages. The formatting commands, expressed in HTML, are easy to master. Publishing static pages is the specialty of the Web and its publishing tools.

But if you try to do something a little more complex, a little more dynamic, the Web can grow into a far more complicated beast. It's not that the technology of the Web is too weak for the task. The problem is that the publishing tools are complicated and unwieldy. More often than not, the only tools available to you are a box of UNIX utilities and scripting languages that don't work well together.

PageCompileServlet enables you to embed Java code in static HTML pages and compile these hybrid HTML/Java pages into Java servlets. The resulting servlets blend the static HTML content with dynamic content derived from the embedded Java code.

Using PageCompileServlet, you can quickly design dynamically generated pages using very simple tools and techniques. Once you have mastered the fundamental techniques, you will find that more complex Web applications are only a small step behind.

This tutorial guides you through the basic techniques of using Page Compilation to create a dynamic Web site. Even if you are a seasoned HTML developer, or an experienced Java programmer, you should look carefully at these examples to see how the two work together.

When you finish this tutorial, you should know enough to design your own dynamic Web pages. You should also be able to realize your designs quickly, using the examples given here.

Creating Your First Page

  1. Choose a place to put your first HTML/Java page.

    For this example, you'll create it in the web server's document root. As usual, the page will be accessed from the web server using the appropriate URL.

  2. Use any editor to create a file with an extension of .jhtml. (The file must have an extension .jhtml for the web server to check for Java code.)

    For this example, if your document root is JavaWebServer1.1/public_html/, then your first PageCompileServlet page could be stored in:

    JavaWebServer1.1/public_html/FirstPage.jhtml
        

  3. Create a standard HTML page which includes the required tags. You can add any additional HTML tags and text you wish displayed.

    For this example, put the following HTML tags and text into FirstPage.jhtml:

    <html>
    <head>
    <title>My First Page </title>
    </head>
    <body>
    <h1>My First Page </h1>
    </body>
    </html>

    At your browser, go to the URL needed to access the page. For this example, you created the page in the default document root <server_root>/public_html. If that document root is on the default port 8080, you would access the file by typing:

    http://your-server:8080/FirstPage.jhtml

    Of course, this is a file that contains normal HTML. You don't need the PageCompileServlet to view this but it's important to remember that PageCompileServlet works with your HTML files, whether they contain embedded Java code or not.

  4. Now add some Java code.

    For this example, make your example file look like the following:

    <html>
    <head>
    <title>My First Page</title>
    </head>
    <body>
    <h1>My First Page</h1>
    <ul>
    <java>  
    for (int i = 0; i < 5; i++) out.println ("<li>" + i);
    </java>
    </ul>
    </body>
    </html>
  5. Finally, go to the necessary URL to request the file.

    For our example, the URL is in the previous step. (Because you've entered new code into a file you've previously viewed, FirstPage.jhtml, you'll need to reload the page to view the new results.)

You should see a page that counts from 0 to 4. The magic is everything that happens between the special PageCompileServlet java delimiters. When PageCompileServlet detects these delimiting tags, PageCompileServlet treats everything in between as Java code which PageCompileServlet compiles and executes. In this case, the Java code is a for loop that prints five lines to out and out is bound to a ServletOutputStream.

HTML to Java and Back Again

Now that you've compiled your first combined HTML/Java page, let's take a quick look at what is really happening behind the scenes.

You may notice that PageCompileServlet takes a while to serve your page the first time you request it, but subsequent requests on the same page are much faster. This is because PageCompileServlet must compile the Java code in your file before it can serve it. However, once PageCompileServlet compiles a page, PageCompileServlet remembers the compiled version. Subsequent accesses use this stored version, which can be generated very quickly. If you change your file, PageCompileServlet detects this and compiles your file again the next time it is accessed.

Even though PageCompileServlet does all of this automatically, you should be familiar with what PageCompileServlet is doing to your pages. Once you understand this, you will know what you can and cannot do with PageCompileServlet in a page.

Consider the previous example:

<html><head><title>My First Page</title></head>
<body><h1>My First Page</h1>
<ul>
<java>
  for (int i = 0; i < 5; i++) out.println ("<li>" + i);
</java>
</ul>
</body></html>

The first thing PageCompileServlet does with this file is convert it to pure Java servlet definitions. The resulting code looks something like this:

package pagecompile;

import com.sun.server.webserver.pagecompile.filecache.*;
import com.sun.server.webserver.pagecompile.ParamsHttpServletRequest;
import com.sun.server.webserver.pagecompile.*;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*


public class _FirstPage
extends HttpServlet{

//-------------------------------
  static {
  }
  
  //-------------- The service method
  public void service (HttpServletRequest request,
                         HttpServletResponse response)
      throws ServletException, IOException
  {
    ServletOutputStream out = response.getOutputStream ();
    ByteFileData __fileData = null;
    try {
      __fileData = (ByteFileData) 
      ServletUtil.getFileCache(this).getFile\
        ("C:\\Java Web Server1.0\\public_html\\FirstPage.jhtml",\
        null, 865872648000L);
      if (__fileData == null) throw new ServletException("FileChanged");

      /*** lines: 1-3 */
      __fileData.writeBytes (0, 93, out);
  
     for (int i = 0; i < 5; i++) out.println ("<li>" + i);
           /*** lines: 5-8 */
      __fileData.writeBytes (175, 40, out);
    }
    finally {
      if (__fileData != null) __fileData.close();
    }
  }
}

In effect, an HTML/Java file is treated as a script that is executed every time the file is requested. The HTML/Java file is translated into a Java source file. This Java source file defines a servlet class that produces the desired output. The source file is compiled and instantiated, then run as a servlet every time the source file is requested. Hence, the name PageCompileServlet.

Keep in mind that all of this Java code is executed by PageCompileServlet on the server. The output of that code is sent to the browser. The browser never sees any of the Java code. This is very different from a Java applet, which is sent to the browser to be executed. Of course, PageCompileServlet allows you to use applets as you would normally, but PageCompileServlet's internal Java workings and page generation have nothing to do with applets.

PageCompileServlet is actually doing a little more in the translation. Java requires that all this code be packaged within the method of a class, which PageCompileServlet does. Don't worry about this yet. All you need to know is that PageCompileServlet converts the entire page into one continuous piece of Java code.

This translation step from your HTML source file to a Java file has several implications for you. These are described below.

Multiple HTML/Java Blocks

You can have many HTML/Java blocks in your page, intermingled as much as you want with regular HTML. They'll all get inserted into the proper place within the resulting Java file.

For example:

<html>
<head><title>Two sections</title></head>
<body>
<h1>Two sections</h1>

<java> 
out.println ("<p>here's one block");
</java>

<h1>And a list</h1>
<ul>
<java>
for (int i = 1; i < 10; i++) {
  out.println ("<li>" + i);
}
</java>
</ul>

</body>
</html>

This example contains two separate java sections, each doing their own thing. The second section is used to create an unnumbered list by surrounding the section with <ul> and </ul>. As you can see, you can freely mix regular HTML with your java blocks.

Declaring Variables

If you declare a variable in one HTML/Java block, that variable will be "visible" in subsequent HTML/Java blocks. For example:

<html>
<head><title>My First Page</title></head>
<body>
<h1>My First Page</h1>

<java> 
int i = 21;
out.println ("<p>i = " + i);
</java>

<h1>But now what does i equal?</h1>

<java> 
out.println ("<p>i still = " + i);
i = 17;
out.println ("<p>but now i = " + i);
</java>

</body>
</html>

Here the variable i is visible across two blocks of HTML/Java. If you look at the resulting Java code, it's obvious why:

package pagecompile;

import com.sun.server.webserver.pagecompile.filecache.*;
import com.sun.server.webserver.pagecompile.ParamsHttpServletRequest;
import com.sun.server.webserver.pagecompile.*;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class _list2
extends HttpServlet{

//-------------------------------
  static {
  }
  
  //-------------- The service method
  public void service (HttpServletRequest request,
                         HttpServletResponse response)
      throws ServletException, IOException
  {
    ServletOutputStream out = response.getOutputStream ();
    ByteFileData __fileData = null;
    try {
      __fileData = (ByteFileData) ServletUtil.getFileCache(this).\
        getFile("C:\\Java Web Server1.0\\public_html\\list2.jhtml", null, 865870424000L);
      if (__fileData == null) throw new ServletException("FileChanged");

      /*** lines: 1-6 */
      __fileData.writeBytes (0, 105, out);
 
     int i = 21;
     out.println ("<p>i = " + i);
           /*** lines: 9-13 */
      __fileData.writeBytes (179, 53, out);
 
     out.println ("<p>i still = " + i);
     i = 17;
     out.println ("<p>but now i = " + i);
           /*** lines: 17-20 */
      __fileData.writeBytes (351, 30, out);
    }
    finally {
      if (__fileData != null) __fileData.close();
    }
  }
}

It's as if the HTML/Java blocks were never separated by a line of HTML. But this also means that you can't reuse a variable name later in your page:

<html>
<head><title>My First Page</title></head>
<body>
<h1>My First Page</h1>

<java>
int i = 21;
out.println ("<p>i = " + i);
</java>

<h1>But now what does i equal?</h1>
<java>
int i = 14;
out.println ("<p>i still = " + i);

</java>
</body>
</html>

This results in an error because Java won't let you declare the same variable twice in the same block (we'll get to errors in a bit). The way to get around this, should you need to, is to use braces. In Java, any code enclosed by braces has its own scope. Any variables declared within this scope are not visible outside of the scope, which means that they can be reused. For example:

<html>
<head><title>My First Page </title></head>
<body>
<h1>My First Page</h1>
<java>
{
  int i = 21;
  out.println ("<p>i = " + i);
}
</java>
<h1>But now what does i equal?</h1>
<java> 
{
  int i = 14;
  out.println ("<p>a different i = " + i);
}
</java>
</body>
</html>

Conditional HTML

One nice application of HTML/Java blocks is to determine whether a block of HTML should be printed by using an if statement. For example:

<html>
<head><title>Phone bill</title></head>
<body>
<h1>Phone bill</h1>

<java>
double balance = 40.25;
</java>

<p>Your current balance is: <java> out.print (balance); </java>
<java> if (balance >= 100.00) { </java>
<p>You use the phone far too much!
<java> } </java>

</body>
</html>

This will print out your current balance, then chide you only if your balance is greater than $100.00. You can try changing the value of balance to see this work.

Note how the if statement is broken into two parts:

<java> if (balance >= 100.00) { </java>

and

<java> } </java>

The reason for this becomes clear if we examine the resulting Java code:

package pagecompile;

import com.sun.server.webserver.pagecompile.filecache.*;
import com.sun.server.webserver.pagecompile.ParamsHttpServletRequest;
import com.sun.server.webserver.pagecompile.*;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class _phone__bill
extends HttpServlet{

//-------------------------------
  static {
  }
  
  //-------------- The service method
  public void service (HttpServletRequest request,
                         HttpServletResponse response)
      throws ServletException, IOException
  {
    ServletOutputStream out = response.getOutputStream ();
    ByteFileData __fileData = null;
    try {
      __fileData = (ByteFileData) ServletUtil.getFileCache(this).\
        getFile("C:\\Java Web Server1.0\\public_html\\phone_bill.jhtml",\
        null, 865873524000L);
      if (__fileData == null) throw new ServletException("FileChanged");

      /*** lines: 1-6 */
      __fileData.writeBytes (0, 99, out);

     double balance = 40.25;
           /*** lines: 8-10 */
      __fileData.writeBytes (149, 37, out);
 out.print (balance);       /*** lines: 10-11 */
      __fileData.writeBytes (221, 7, out);
 if (balance >= 100.00) {       /*** lines: 11-13 */
      __fileData.writeBytes (267, 48, out);
 }       /*** lines: 13-16 */
      __fileData.writeBytes (331, 30, out);
    }
    finally {
      if (__fileData != null) __fileData.close();
    }
  }
}

The bracket ({) at the beginning of the if statement requires a matching bracket (}) to end the statement. Thus, you need a second HTML/Java section to put in that ending brace.

You can use this technique to conditionalize your HTML using if statements, else statements, and even switch statements. You just have to make sure that the resulting Java code is legal, by explicitly adding the correct matching braces or break; statements.

Looping HTML

The previous section described how you can use Java statements to generate different HTML under different conditions. You can use the same techniques with Java looping statements, such as for, while, and do. The following example prints out the same line 20 times:

<html>
<head><title>Useless repetition</title></head>
<body>
<h1>Useless repetition</h1>

<ul>

<java> for (int i = 0; i < 20; i++) { </java>
<li>Same old thing...

<java> } </java>
</ul>

</body>
</html>

Once again, note that a separate HTML/Java block is needed to match the brace that begins the for loop.

You can extend this technique to perform more useful tasks, such as running through a list of items. However, you must be careful not to create infinite loops (loops that never terminate). Such a beast will not produce useful output and will only serve to slow down the PageCompileServlet.

Generating HTML

By now it should be clear that you can freely mix your HTML content with java sections. Your java sections can create more content by printing to out. But the content printed by your java sections is not limited to straight text. Your java sections can generate HTML tags, simply by printing them out.

We have already seen a couple of examples of this. Many of the out.println () statements used so far include a paragraph tag: <p>. As long as the output of your java section is legal HTML, you can print it.

This is a powerful concept, but may be confusing at first because it requires you to think in two languages at once: HTML and Java. The trick is to remember that the process happens in two stages: The Java code executes and produces HTML. The HTML then goes to your browser and is displayed. Now, if you know what it is that you want to be displayed, start from the end and work backwards. Figure out what the HTML should look like. Then figure out what Java code is needed to generate that HTML. Following these steps should keep things straight.

This example generates a formatted HTML list of anchors. As specified in the Java code, item 11 of the list is emphasized.

<html>
<head><title>Generating HTML</title></head>
<body>
<h1>Generating HTML</h1>
<java>
int size = 24;
int emphasize = 11;
out.println ("<h2>A list of " + size + " items</h2>");
out.println ("<ul>");
for (int i = 0; i < size; i++) {
  out.println ("<li>");
  if (i == emphasize) out.println ("<b>");
  out.println("<a href=\"item" + i + ".jhtml\">item number "\
     + i + "</a>");
  if (i == emphasize) out.println ("</b>");
}
out.println ("</ul>");
</java>

</body>
</html>

Using Back Quotes

Embedding Java code within an HTML tag requires a different approach. For example, consider an HTML anchor that you want to be generated based on the value of a variable:

<a href="picture-<java> out.print(i); </java>.jpg">

In this example you want an anchor to be generated based on the value of the variable i. However, this syntax is not legal syntax for the PageCompileServlet. A different mechanism is required.

PageCompileServlet provides a shorthand for embedding Java statements within an HTML tag. Inside an HTML tag, you can enclose a Java expression within back quote characters (`). For example:

<a href="picture-`i`.jpg">

Anything enclosed in the back quotes is treated as a Java expression, whose value is converted to a String and placed in an out.print call. The page compilation process for this example produces code that is functionally similar to the following:

out.print("<a href=\"picture-");
out.print(ServletUtil.toString(i));
out.print(".jpg\">");

The actual generated code is different for better performance. The ServletUtil.toString method is identical to the standard Java method String.valueOf in that it can take as a parameter any expression that produces an Object or a primitive type (int, float, and so on). An Object is converted to a string using its toString() method. Primitive values are converted using the static toString method in the container class. For example, to convert an int, ServletUtil.toString uses the method:

String Integer.toString(i)

The only difference between String.valueOf and ServletUtil.toString is that if the parameter is an Object that is null, an empty string is returned instead of the string "null". This is more convenient since you rarely want to send the string "null" when generating HTML.

The back quotes only work as a short hand within HTML tags. Outside of HTML tags, back quotes are given no special treatment. For example:

<p> This ` is just a plain old back quote `

Because these back quotes are not inside an HTML tag, they are treated as ordinary characters.

Eliminating Bugs

When developing for the Web, there are many ways to make mistakes. Fortunately, you can catch most of those mistakes just by looking at the results of your page in a Web browser and seeing if it looks right.

With PageCompileServlet, you are programming in both HTML and Java, and thus you double the number of bugs you can create. Fortunately, PageCompileServlet makes it easy to catch your Java bugs. If you try to access a PageCompileServlet page with a Java bug in it, you'll see an error message sent right back to your Web browser.

For example, let's say you forgot a semicolon in one of your pages:

<html>
<head><title>A Broken PageCompileServlet Page</title></head>
<body>
<h1>A Broken PageCompileServlet page</h1>
<java>
out.println ("<p>don't I need a semicolon somewhere?")
</java>
</body>
</html>

When you try to access this page, PageCompileServlet will send the following to your Web browser in place of the page that you were expecting:

Error getting compiled page

C:\Java Web Server1.0\servlets\pagecompile\_broken__page.java:32:
     Invalid type expression.
     out.println ("don't I need a semicolon somewhere?")
                 ^
C:\Java Web Server1.0\servlets\pagecompile\_broken__page.java:34:
     Invalid declaration.
      __fileData.writeBytes (222, 28, out);
                            ^
2 errors

The output of the page compilation process is to render a page with an error message. This occurs when PageCompileServlet cannot compile your file into a Java class because it found some errors. An error message is printed, indicating the compiled file, its location, and the type of error which has occurred (in this example, an error has occurred in the file broken_page.java. The error type is identified as a missing semicolon.

Unfortunately, a missing semicolon produces some rather cryptic errors, but at least you have some idea where the error occurred. However, you may have to go through a couple of steps to find it.

The error message printed by PageCompileServlet includes the number of the offending line, which you can use to locate the error in your file. If your file is large, this might not be the best way to find the error.

In this example, the message says that the Invalid type expression error occurred on line 32 of file broken_page.java; the message also provides the pathname of the file. (Note that this filename is only used as an example.)

What file is that? If you recall, the first thing that PageCompileServlet does is turn your file into Java code. The broken_page.java file is where the Java code ended up, and on line 32 of that file is where PageCompileServlet ran into a problem. If you look at broken_page.java, you'll see that it starts off with a cryptic bit of Java code, but afterwards you should find something you can recognize as the translated version of your original file. The error occurred at line 32, so if you look at line 32 and take note of the surrounding code, that should help you locate the error in your original file. You may want to look at both the compiled Java file, and your original HTML file to discover the source of the error.

If, as in the above example, you get several compilation errors at once, try to fix the first one. This could end up eliminating many errors at once.

The preceding example demonstrates how to find a compile-time bug in PageCompileServlet. Compile-time refers to the situation in which PageCompileServlet cannot compile the code on your page, and thus cannot even begin to execute the page.

But even after you eliminate your compile-time bugs, you are not yet in the clear. Your Java code might produce errors when it is executed. Consider a divide by 0 situation:

<html>
<head><title>Bad arithmetic</title></head>
<body>
<h1>Bad arithmetic</h1>
<java>
int a = 3;
int b = 0;
out.println ("a/b = " + (a / b));
</java>
</body>
</html>

When you try to access this page, PageCompileServlet will compile the page successfully and start to execute it. PageCompileServlet will get as far as printing the "Bad Arithmetic" header, before it runs into a problem: division by 0. This will be reported to you as:


500 Internal Server Error

The servlet named "pageCompile", at the requested URL 

     http://servername.hostname.com:8080/bad_math.jhtml

reported this exception:

     / by zero

The administrator of this web server should resolve this problem.

This is a runtime error, one which occurs while the Java code is executing. In Java, a runtime error is reported by throwing an exception, which PageCompileServlet catches and reports back to you. In this case, the exception is an ArithmeticException, more specifically, division by zero.

PageCompileServlet also tells you where the exception occurred, through a stack trace which should be familiar to Java programmers. You can also get the stack trace of where this error occurred by looking in the log file; the log file will have a path name similar to the following:

your Java install directory/logs/webpageservice/error_log

The first line of the stack trace is most important since it tells you which line of your file caused the error.

As with compile-time errors, a runtime error reports where the error occurred within the resulting Java file, not in your original HTML file. You'll have to work your way back to find out where the error was in your original file.


Top
java-server-feedback@java.sun.com
Copyright © 1998 Sun Microsystems, Inc.
All Rights Reserved.