| Vibrant Life Plans | Electronic Information System Plan | Data | Admin Scale For Vibrant Life | |
| New Theme Page | Policies | Programs | Notes | Table Of Contents |
| New Database | eCourses | Quizzes | Search |
Lesson 2: Procedural, Structured and Object-Oriented Programming
Your First Java Program
Compiling and Running your Program
Object Oriented Concepts in Java – Part 2
Passing Parameters and Returning Values
Access Control Modifiers
Encapsulation with Accessors
Overloaded Methods
Advanced Inheritance: Overriding Methods
Summary
Summary and Resources for Further Reading
Build your own Database Driven Website using PHP & MySQL
JSP Quick-Start Guide for Linux
Downloading and Installing Apache Server
Downloading and Installing Tomcat
![]()
Until recently, programs were thought of as a series of procedures that acted upon data. A procedure, or function, is a set of specific instructions executed one after another. The data was quite separate from the procedures, and the trick in programming was to keep track of which functions called which other functions, and what data was changed. To make sense of this potentially confusing situation, structured programming was created.
The principle idea behind structured programming is as simple as the idea of divide and conquer. A computer program can be thought of as consisting of a set of tasks. Any task that is too complex to be described simply would be broken down into a set of smaller component tasks, until the tasks were small and easy to understand.
As an example, computing the average salary of every employee of a company is a rather complex task. You can, however, break it down into the following sub-tasks:
Totaling the salaries can be broken down into the following steps:
In turn, obtaining each employee's record can be broken down into the following:
Structured programming remains an enormously successful approach for dealing with complex problems. By the late 1980s, however, some of the deficiencies of structured programming had become clear.
First, a natural desire is to think of data and what you can do idea as a single idea. Procedural programming worked against this, separating data structures from functions that manipulated that data.
Second, programmers found themselves constantly reinventing new solutions to old problems. This is the opposite of reusability. The idea behind reusability is to build components that have known properties and then to be able to plug them into your program as you need them.
Object-oriented programming attempts to respond to these needs, providing techniques for managing enormous complexity, achieving reuse of software and coupling data with the tasks that manipulate data.
Looking to learn how to build dynamic Web sites? There are many options out there, the most popular of which include ASP, PHP, and other scripting languages. Another option is Java. Oh sure, Java began as a language for writing Web-based Applets and cross-platform applications, but in the past few years its role has been expanded to include server-side programming of Web pages. In fact, there is great demand in the job market for developers with experience in writing server-side Java applications. Your first step towards adding these skills to your résumé should be to pick up a basic understanding of the Java language in general.
This is the first in a series of articles that will teach you the Java programming language with an eye to features and techniques that are applicable to building dynamic Web sites. Specifically, after covering the basics of the language and the object-oriented concepts you need to use the language effectively, I’ll proceed to a discussion of Java Servlets and JavaServer Pages (JSP), the two technologies used to build dynamic, data-driven Web sites using Java. Along the way, I’ll introduce you to related technologies, like Java Database Connectivity (JDBC). But before I get too bogged down in a description of things to come, let me turn your attention to the object of this article: an introduction to the basics of the Java language.
Java is a full-featured programming language like C/C++, but simpler and more tightly structured. Like C++, Java is an object-oriented programming language, which is a concept I’ll expand on in the next article in this series. In basic terms, however, Java programs are written by creating a structured set of software components that interact with each other to produce the desired effect. These components are called objects, and the fundamental task of a Java developer is to determine the best object structure to achieve a system that works as required, as efficiently as possible and, wherever possible, producing components that may be reused in similar applications.
If all that sounds a little scary, don't worry; it'll all make sense once you've learned it. For now, we'll proceed in baby steps.
Java programs, instead of running directly on a computer's operating system, run on a "Java Virtual Machine" (JVM), which itself is a program that runs on the computer's operating system. Since the production of Java Virtual Machines is highly standardized, incompatibilities between different platforms are minimal. This means that, in theory, any operating system that has a JVM (pretty much all major operating systems these days) can run any Java program, with no need to recompile the program for each platform. This leads to one of the most attractive features of the Java language: "Write Once, Run Anywhere" (WORA). The disadvantage is that Java programs tend to run slower because the Virtual Machine has to convert Java program instructions and pass them to the operating system on which it is running.
Most current Web browsers can also run Java programs that are downloaded from the Web, either using a JVM built into the browser (as in Netscape 4 and Internet Explorer browsers), or by interfacing with a standard JVM installed separately (as in Netscape 6 and Opera browsers). Java programs designed to run in Web browsers are called Java Applets. When Java was originally released, much of the marketing hype surrounding the language centred on these little programs that run in Web browsers. Over the years, however, the focus of Java on the Web has shifted to server-side applications (including Servlets and JSP), and Java applets have been replaced in many instances by more nimble technologies like Dynamic HTML and Flash. Common uses of Java applets these days include Web-based chat programs and online games.
Now that you know what you’re getting yourself into, it’s time for you to get a hold of the tools you’ll need to get started with your Java development efforts.
Everything you need to develop and run Java programs may be freely downloaded from the Sun Java Web site at www.javasoft.com. The main package you'll need is the Java 2 Software Development Kit (SDK), Standard Edition. The SDK contains both the development tools for creating Java programs and the Java Runtime Environment (JRE) for running Java programs. The JRE includes the JVM and various supporting files. Barring Java applets, which run using the internal JVM’s of some browsers, anyone who wants to run a Java program will need to install the JRE, which may be downloaded separately from the SDK as well. To write your own Java programs, however, you need the full SDK. You’ll also want to pick up a copy of the Java 2 Platform Documentation package, which includes a comprehensive reference of all the built-in functionality that Java provides for you. Once you get familiar with the basics of the language and are ready to write real-world programs, this documentation will be your very best friend.
Detailed installation instructions are provided for each of those packages, and I highly recommend you follow them to the letter. Many people who install the Windows version simply download and run the setup program and neglect to complete the additional task of setting up critical environment variables to allow Java to operate correctly. The only omission in the provided installation instructions is a method to add/edit environment variables in Windows ME and Windows 2000. The methods provided in the instructions work for Windows 95/98/NT, but in Windows ME you need to click Start, Run..., and then type msconfig to launch Windows ME’s System Configuration Utility. The system environment variables may be adjusted on the Environment tab. In Windows 2000, the procedure they provide is almost right. Once you run the System Control Panel icon, proceed to the Advanced tab and click the Environment Variables button, then proceed according to the instructions.
To double-check that the Java SDK is installed correctly on your computer, open a command prompt (i.e. the Command Prompt or MS-DOS Command Prompt in Windows, or XTerm under Linux). Try the two commands shown below. If you get similar output, you’re good to go. If your operating system doesn’t recognize the commands, you may need to reboot for changes to your environment variables to be detected.
C:\> java –version
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)
C:\> javac
Usage: javac <options> <source files>
where possible options include:
...list of options...
Once you have the SDK (and, optionally, the documentation) installed, you’re ready to write your first Java program. Before you proceed, let me say a few words about Integrated Development Environments (IDE's). You have probably seen ads for fancy development environments, both commercial and free, for writing Java programs. While these can be useful for the experienced Java developer (I myself make heavy use of IBM VisualAge for Java in my own projects), I strongly recommend that, as a beginner, you get started using the simple tools provided in the SDK.
My reasoning on this issue is that many of the features provided by Integrated Development Environments such as JBuilder and others are designed to provide shortcuts to get certain tasks done more quickly. The problem is that if you don't understand the 'long way' of doing those tasks beforehand, you're going to have a lot of trouble understanding the implications and pitfalls of using the automated methods provided by these tools. This issue is akin to choosing between a text editor like HotDog Pro and a WYSIWYG editor like Dreamweaver to build a Web site. While Dreamweaver can help you quickly produce some advanced effects, if you don't understand how to hand-code those same effects beforehand, you're going to have a hard time producing any advanced effects beyond the scope of those provided through Dreamweaver's automated tools.
The goal of this section is to give you a feel for the process of writing, compiling, and running a Java program. You’ll also get to see what a Java program – if only a very basic one – looks like. I’ll explain everything in basic terms, but if something doesn’t make sense to you don’t worry about it too much. Some concepts will only be familiar to experienced programmers, and if that's not you, don't worry about it! At this stage it’s most important for you to get used to what needs to be done, not understand why.
Start by creating a new directory in a convenient place; in
most cases, you’ll want the files for each of your Java programs to be stored in
a separate directory. I’ll assume the directory you’re using is D:\MyFirstJava,
but you can call the directory anything you like. Under Linux, for example, you
would probably create the directory as a subdirectory of your personal home
directory (e.g. /home/kyank/MyFirstJava).
Using whichever text editor you prefer (NotePad under
Windows will do fine, for example), create a file called Hello.java
in that directory. Note the .java file extension. All files
containing Java source code should be given the .java extension to
identify them as Java source files. Note also that the filename is capitalized.
This is important, so be sure to give the file that exact name. To save a file
without a .txt extension in NotePad, be sure to select
All Files in the Save As Type drop-down menu
in the Save As dialog box; otherwise, NotePad will add
.txt to the end of the filename (e.g. Hello.java.txt).
Type the following for the contents of Hello.java,
then save the file. Note that the line numbers are provided only for your
convenience; do not type the line numbers into the file!
1 /**
2 * Hello.java
3 * A simple Java program
4 */
5
6 class Hello {
7 public static void main(String[] args) {
8 // Print a couple of one-line messages
9 System.out.println("Hello, World!");
10 System.out.println("This is a test.");
11 }
12 }
You've just written your first Java program! Before I show you how to compile and run it, I'll step through the code line by line to explain, in general terms, what everything does.
/* (pronounced 'slash-star') and ends it with */
('star-slash'). Everything between these two markers is ignored by Java. As
you can see, a comment of this type can span multiple lines.
I've formatted this comment in the standard style recommended by the Java documentation style guide. The comment begins with slash-star followed by another star and a line break, and then each line of the comment begins with a space followed by a star and another space. The comment ends with a space followed by the terminating star-slash appearing alone on a line. While this is the recommended commenting style, and will be the one I use throughout this series of articles, you or your company may develop an alternate style. Here are a couple of examples of alternate commenting styles:
/*
/*-----------------------*\ Hello.java | Hello.java
| A simple Java Program | A simple Java program | */
\*-----------------------*/ |
Although they look very different, notice that they both
start with /* and end with */. What comes between
those two markers is of no consequence as far as how the program works – use
whatever style you prefer.
class indicates that I am starting a new
component (for now, you can take a class to mean a
component), and the word Hello is the name of that component (or
class). The opening brace ({) marks the beginning of the code
that will define the new class. It's no coincidence that the class (Hello)
is named the same as the file in which it is defined (Hello.java).
In fact, this is a requirement. Every class that you create must be defined in
its own file with the same name as the class defined within. The two names
must match exactly, right down to the case (you can't define a class named
MyClass in a file called myclass.java; rather, the
file must be named MyClass.java). Class names in Java are
capitalized by convention. That is to say, you could name a class
myclass if you really, really wanted to, but other Java programmers are
used to seeing class names capitalized, so your code will be a lot easier to
read and maintain if you instead called the class MyClass.
public, static, and void at the
start of the line provide certain information about this method. Each of these
has a fairly long story behind why it is required here; so don't worry about
these for now. The word main is the name of the method. Note that
method names, unlike class names, are not capitalized. Once again, this is
only a convention, but one that you should really stick to for the sake of
others who may have to read your code. Depending on how much, if any,
programming experience you have, the parenthesized portion of this line is
either already familiar to you or pretty scary looking. Basically, it defines
what information is required to make this method do its job, but for now you
don't need to worry about the details. This main method is
actually rather special. When it first starts running a program, Java looks
for a method called main with the words public static void
in front of it in the class and uses it as the starting point of the program.
So if you like, you can think of this whole line as a "magic formula" for
saying "the program starts here". /* and */. This is an example of
the second type of comments that Java allows you to use. When it encounters
// (slash-slash) anywhere in your code, Java ignores the rest of
that line. This type of comment is useful for quickly writing one-line
comments in your code, or for adding a short explanation to the end of a
particularly complicated line of code. ;). One of the most
common mistakes that beginners make when writing Java programs is to forget
the semicolons on the ends of their statements. Fortunately, Java is pretty
good about spotting these mistakes and letting you know about them. This
particular statement instructs your program to print the text Hello,
World! on the screen. System.out.println means "print the
following line of text on the screen," while the rest of the line indicates
what, precisely, should be printed. This is a test. on the screen. Since the statements are executed
one after another, this message should be printed on the screen right after
the previous message. main method. When
the program gets to this point, it stops running. Hello class.
Before I continue, a note on coding style. You probably
noticed that some of the lines of this program have spaces in front of them,
while others don't. This coding style, known as indenting
is intended to show off the structure of the code. That is, by indenting the
main method (along with its closing brace on line 11) by two
spaces, it makes clear the fact that the method is inside the Hello
class. Likewise, by indenting lines 8-10 (the contents of the main
method) by a further two spaces, it becomes clear that those lines belong to the
main method. The code of the program could have been written
without indenting (with every line starting at the left margin), and it would
have worked just as well, but the structure of the program would not have been
obvious at a glance. When you get to a stage where you're writing complicated
programs, it will not be uncommon for certain passages of your code to be
indented five or even ten levels deep. By picking up this good habit now, it
will ensure that your code is easy to read now and in future.
With your first Java program written, you're probably
anxious to see it running. Before you can run your program, you must first
convert it into a format that the Java Virtual Machine (JVM) can understand.
This process, called compilation, involves running a
program called the Java compiler that checks your Java
code for mistakes (missing semicolons and whatnot) and then converts it into a
binary format called Java bytecode that the JVM can
understand. The Java compiler is run from the command line by typing javac,
followed by the name of the Java code file that you want to compile.
To compile your Hello.java file, start by
opening a command prompt and navigating to the directory containing the file to
be compiled. On Windows, for example, to navigate to D:\MyFirstJava,
type the following commands (hitting Enter after each):
C:\> d:
D:\> cd MyFirstJava
D:\MyFirstJava>
To compile Hello.java, type the following
command:
D:\MyFirstJava> javac Hello.java
If everything goes as planned, there should be a short delay followed by another prompt (no news is good news!). If the compiler finds anything wrong with your code, however, one or more errors or warnings will be displayed. In most cases, the exact line number and some clue as to the nature of the error will be given. Compare your code to that provided above and make sure they match exactly (remember, the line numbers are not part of the code).
Once you've successfully compiled your program, a file
called Hello.class will have been created in the directory
alongside your Hello.java file. This is the compiled version of
your Java code, and contains a description of the Hello class that
you defined in your file. Such files are called class files,
for obvious reasons. That description is in binary format (specifically, in Java
bytecode), and is ready to be run by the JVM.
Running a Java program is similar to compiling it, except
that instead of using the Java compiler (javac), you use the Java
Runtime Environment (JRE), which you can invoke using the java
command, followed by the name of the class that contains the special main
method. In this case, your class is called Hello, so to run your
program you type the following command:
D:\MyFirstJava> java Hello
Hello, World!
This is a test.
As expected, the two messages, Hello, World!
and This is a test. are printed out. Your program is working! One
important note: when running a program, you need to specify the name of the
class (Hello), not the name of the class file (Hello.class).
Java finds the class file automatically using the name of the class. If you told
it to run Hello.class, it would be looking for a file containing a
definition of a class called Hello.class, and you'd get an error
like the following:
D:\MyFirstJava> java Hello.class
Exception in thread "main" java.lang.NoClassDefFoundError: Hello/class
This NoClassDefFoundError indicates that Java
couldn't find a definition of the class it was looking for, in this case
Hello.class (which it displays as Hello/class for reasons
that I'll explain in a future article).
In this article, I've provided an introduction to the Java programming language from the ground up. I covered the basics of what Java is and why it's a useful tool to have under your belt, I explained what tools you need to write, compile, and run Java programs on your computer and where you can get them, and finally I walked you through the process of creating and running a very simple Java program.
As I said, this is only the first in a series of articles intended to bring you into the world of Java programming for the Web. In part 2, Java Language Baics, we'll explore the language in greater detail, covering data types, operators, variables, and flow of control. In the meantime, if your ultimate goal is to learn to create dynamic Web sites using Java Servlets and JavaServer Pages (JSP), you can read my JSP Quick-Start Guide to set up the software you'll need to produce server-side Java programs for the Web.
If you're anxious to move forward with the Java language, there are some other resources you can refer to while awaiting additional instalments in this series. The Java Tutorial is the official online guide to learning most aspects of Java, and can be accessed free of charge. A better way to learn the language, however, is to pick up a good book on the subject. My best recommendation goes to "Beginning Java 2 – JDK 1.3 Edition" from WROX Press, and a complete review can be found here.
Object Oriented Concepts in Java – Part 2
Introduction
Object Oriented Programming (OOP) is a powerful force in the landscape of software development today. Some say (quite correctly, in my opinion) that the development efforts behind large software projects such as Microsoft Office simply would not be possible to manage without the modularity and code reuse made possible by today's object oriented languages. Others just prefer OOP because it pays better and it's more fun!
Whatever your reasons for learning the principles of OOP, Java is an ideal language in which to get your feet wet. It's friendly enough to beginners that you shouldn't be overwhelmed by complicated syntax if you're comfortable with basic programming concepts, and yet it is a truly complete, object oriented language, unlike many other Web development languages such as Perl, PHP, and ASP, which merely provide object oriented features.
This article is both the fourth in SitePoint's series on developing dynamic Web sites with Java, and the second of two parts that focus on teaching you what you need to know about Object Oriented Programming to take full advantage of what the Java language has to offer. If you have not read the previous articles in this series, I would definitely recommend backing up and starting from the beginning, as the concepts presented here rely on your knowledge of all that has come before.
In
Part One,
we looked at the basic concepts of classes,
Objects, properties, and
methods. We developed a simple class called Tree
as well as a program to instantiate a few Trees and test
out their height property and their grow method. After a brief look
at inheritance, where we developed a
subclass of Tree called CoconutTree, we
looked at the issues you will face when copying and
comparing Objects in Java. In Part
Two, we'll pick up right where we left off by learning some more advanced types
of methods and properties. We'll learn how these may be used to design better
classes that exhibit some important features of good object oriented software
design. In addition, we'll have a look at some advanced concepts in class
design, and I'll provide an explanation of class packages, which let you
organize your classes into groups.
With all the formalities out of the way, let's get started!
Most of the methods we have looked at so far have been of a
special type. Here is a declaration of one such method, the pickNut
method for the CoconutTree class that we developed in Part One:
public void pickNut() {
numNuts = numNuts – 1;
}
What makes this, and the other methods we have looked at so far, special is the fact that it doesn't require any parameters, nor does it return a value. As you'll come to discover as we look at more practical examples of Java classes later in this series, most methods do one or both of these.
Parameters are pieces of information that must be provided
when invoking a function to completely specify the action to be taken. For
example, if we wanted to make the pickNut method above more
powerful, we could give it a parameter to indicate the number of nuts to be
picked:
public void pickNut(int numberToPick) {
numNuts = numNuts – numberToPick;
}
In this new version of the pickNut method, we
have specified that the function takes an integer (int) parameter,
the value of which is stored in a variable called numberToPick. The
code of the method then uses it as the number to be subtracted from the
numNuts property. Thus, we can now pick as many nuts as we want from a
CoconutTree with a single invocation of the pickNut
method. Here are a few sample invocations of pickNut:
CoconutTree ct = new CoconutTree(); // New tree
// Presumably we grow a few nuts first...
ct.pickNut(1); // Picks one nut
ct.pickNut(5); // picks five nuts
ct.pickNut(0); // Doesn't do anything
int nuts = 10;
ct.pickNut(nuts); // Picks ten nuts
ct.pickNut(-1); // Picks -1 nut (??)
As this last line demonstrates, there is a problem with this method. Since it accepts any integer as the number of nuts to be picked, there is nothing stopping a program that uses it to pick a negative number of nuts. Looking at the code of our method, this would actually just add more nuts to the tree, but we should not allow operations on our object that do not make sense in the real world. Another operation that would not make sense would be to pick more nuts than there are available for picking on the tree! With the existing code, this would result in our tree reporting a negative number of nuts -- hardly a realistic situation.
These two problems reveal an important issue when designing methods that require parameters. You should always make sure that the value passed to a method makes sense before using it. Even if you're only planning on using a class in your own programs, it's surprising easy to forget what values will and will not cause problems when you aren't checking the values automatically.
The following modified version of pickNut
checks the parameter to make sure that it is not negative, and that it is no
larger than the number of nuts on the tree:
public void pickNut(int numberToPick) {
if (numberToPick < 0) return; // Cannot pick negative number
if (numberToPick > numNuts) return; // Not enough nuts
numNuts = numNuts – numberToPick;
}
The return command immediately terminates the
method. Thus, the operation of picking the nuts (subtracting from the
numNuts property) will only occur if both of the conditions in the
if statements are false. This ensures that our two constraints are met
before we allow the picking operation to go ahead.
One problem still remains, here. How can the code that
invokes the pickNut method know whether the picking operation was
successful? After all, if the picking operation fails because one of the
constraints was not satisfied, we don't want our program to carry on as if it
was able to pick the nuts. To resolve this issue, we must once again alter
pickNut; this time, we will make it return a value:
public boolean pickNut(int numberToPick) {
if (numberToPick < 0) return false;
if (numberToPick > numNuts) return false;
numNuts = numNuts – numberToPick;
return true;
}
Not only can methods receive parameter values when they are invoked, but they can also send a value back by specifying the value as part of the return command. In this new version of the code, we have replaced the word void in the method declaration with the word boolean. This indicates that the function will return a Boolean (true/false) value when it terminates. In this particular case, we have elected to return true if the picking operation succeeded, and false if it failed for any reason. This allows us to structure the code of the program that invokes the method as follows:
if (!ct.pickNut(10)) {
System.out.println("Error: Could not pick 10 nuts!");
System.exit();
}
nutsInHand = nutsInHand + 10;
The condition of the if statement calls
pickNut with a parameter value of 10, and then checks its return value to
see if it's false (note the ! operator). If it is, an error message
is printed out. The System.exit method then terminates the program
immediately, which is a reasonable response to an unexpected error. Otherwise,
the program proceeds as usual.
Another common use for return values is to create methods that perform some common calculation and return the result for the program to use. There will be plenty more examples in the rest of this series for you to learn from.
For much of Part One, we worked with a class called
Tree. Now, while Tree isn't an especially original name for
a class, it fits the class perfectly. The problem is that the same name might
fit another class just as well, and you'll have a naming conflict on your hands.
Such conflicts aren't too serious when you get to write all your own classes;
however, when you need to bring in a set of classes that someone else wrote for
use in your program, things can get messy.
Consider, for example, what would happen if you've designed all of the classes to handle the logic for a program that will track the sales of buttons for clothing. In such a case it would be natural to have a class called Button, but then your boss tells you he or she wants a nice, graphical user interface for the program. To your dismay, you find that the class built into Java for creating buttons on user interfaces is called (you guessed it) Button. How can this conflict be resolved without having to go back through your code and change every reference to your Button class?
Class packages to the rescue! Java provides class packages (usually called just 'packages') as a way of grouping together classes according to their purpose, the company that wrote them, or whatever other criteria you like. As long as you ensure that your Button class is not in the same package as Java's built-in Button class, you can use both classes in your program without any conflicts arising.
By default, classes you create reside in the default package, an unnamed package where all classes that are not assigned packages go. For most of your programs it is safe to leave your classes in the default package. All of Java's built-in classes as well as most of the classes you will find available on the Internet and from other software vendors are grouped into packages, so you usually don't have to worry about your classes' names clashing with those of other classes in the default package.
You will want to group your classes into packages if you
intend to reuse them in future projects (where new class names may clash with
those you want to reuse), or if you want to distribute them for use by other
developers (where their class names may clash with your own). To place your
class in a package, you simply have to give the name of the package on a line at
the top of your file. The convention is to use "com." followed by the name of
your company as your package name. For example, classes that we develop at
SitePoint.com are grouped in the com.sitepoint package by adding
the following line to the top of our java files:
package com.sitepoint;
Be aware that when a class that resides in a package is
compiled, the class file will be placed in a directory based on the name of the
package. For example, compiling Button.java that belongs to package
com.sitepoint creates the Button.class file in the
com/sitepoint/ subdirectory of the current directory. To run or
otherwise make use of a class in such a package, you should refer to it as if it
were in the directory that contains the com subdirectory. So, to
run the com.sitepoint.MyProgram class, you should go to the
directory containing com (which contains sitepoint,
which in turn contains the MyProgram.class file) and type:
C:\javadev> java com.sitepoint.MyProgram
Java will automatically look for com/sitepoint/MyProgram.class.
As it turns out, the Button class built into Java is
actually in the java.awt package, which also contains all of the
other classes for creating basic graphical user interfaces in Java (AWT stands
for Abstract Windowing Toolkit, in case you were wondering). Thus, the
fully qualified name of Java's Button class is
java.awt.Button. To make use of this class without your program thinking
that you're referring to your own Button class, you can use this full name
instead. For example:
// Create a Java Button
java.awt.Button b = new java.awt.Button();
In fact, Java requires that you use the full name of any class that is not in the same package as the current class!
But what if your program doesn't have a Button
class to clash with the one built into Java? Spelling out the full class name
every time means a lot of extra typing. To save yourself this annoyance, you can
import the class into the current package by putting the
following line at the top of your .java file (just below the package
line, if any):
import java.awt.Button;
Once it's imported, you can use the class by its short name (Button) as if it were part of the same package as your class.
Another convenient feature allows you to import an entire
class package into the current package. This comes in handy again when creating
user interfaces for your program, because to create a decent interface you might
easily have to use a dozen or more classes from the java.awt
package, and listing each by name on a separate import line can
become as tedious as typing the full name of the class in your code. To import
the entire java.awt package for use in a class without having to
type their full names, you can add the following line to the top of the file:
import java.awt.*;
The java.lang package, which contains all the
most basic classes of the Java language (e.g. the System class,
which we have been using in the form of the System.out.println()
method to display text on the screen), is automatically imported into every Java
file automatically.
Before you can import or use the fully qualified name of a
class to access it from another package, it must be declared
public. Classes, by default, are only available for use by
code in the same package. Obviously, this is not a desirable limitation if you
are planning to distribute your code for use by others, or reuse your classes in
multiple projects; therefore, any class that you foresee being useful to code
outside of the class' package should be made public. Doing this is as simple as
adding the keyword public to the very start of the class
declaration. For example, it would make sense to declare our Tree class public:
package com.sitepoint;
public class Tree {
...
}
The same goes for CoconutTree:
package com.sitepoint;
public class CoconutTree extends Tree {
...
}
As we have just seen, a class can be made public to allow code outside of its package to make use of it. Class members, which include properties and methods, can be similarly modified to control access to them. Like classes, members have a default access setting that restricts access to code within the same package. Consider the following sample declarations:
int numNuts = 0;
boolean pickNut(int numberToPick) {
...
}
Even if the class is declared public, the value of the
above numNuts property (assuming it is declared as the property of
an Object class) may only be accessed or modified by code in the same package.
Similarly, the pickNut method shown above may only be invoked by
code in the same package as the class.
As with classes, properties and methods may be declared
public:
public int numNuts = 0;
public boolean pickNut(int numberToPick) {
...
}
Any code (from any class in any package) can access and modify a public property value or invoke a public method.
Properties and methods have two additional access settings
that classes do not have. The first is private:
private int numNuts = 0;
private boolean pickNut(int numberToPick) {
...
}
Only code in the same class can access private properties and methods. If you want to store information in an object that is only useful to the object itself or other objects of the same class, or if you want to restrict access to the information (as we'll see in the next section, this is part of good class design!), then you should use a private property for it. Likewise, methods that perform internal calculations or are otherwise not useful to other classes should be declared private.
The final access setting that methods and properties may
take is protected:
protected int numNuts = 0;
protected boolean pickNut(int numberToPick) {
...
}
The protected mode is very similar to the
default mode, in that it refuses access to code outside of the class' package,
but it introduces one exception: subclasses of the current class (i.e. classes
that extend this class) may also access protected members.
Distinguishing the situations in which each access control
setting is appropriate takes a little experience. It's tempting at first to just
declare everything public to save yourself the trouble of worrying
when something is accessible and when it isn't. While this will certainly work,
it is definitely not in the spirit of object oriented programming. Code that you
plan to reuse or distribute, especially, will benefit from being assigned the
most restrictive access control settings that are appropriate. One reason for
this is illustrated in the following section.
Previously, we modified the pickNut method so
that it would not accept too high a number, which would cause our
CoconutTree to think it contained a negative number of coconuts. But
there is a much simpler way to produce this unrealistic situation:
CoconutTree ct = new CoconutTree();
ct.numNuts = -10;
How can we protect Object properties from being assigned
values like this that don't make sense? The solution is to make the properties
themselves private, and only permit access to them using methods. Here is an
updated version of our CoconutTree class that makes use of this
technique:
1 package com.sitepoint;
2
3 public class CoconutTree extends Tree {
4 private int numNuts = 0;
5
6 public void growNut() {
7 numNuts = numNuts + 1;
8 }
9
10 public boolean pickNut(int numToPick) {
11 if (numToPick < 0) return false;
12 if (numToPick > numNuts) return false;
13 numNuts = numNuts – numToPick;
14 return true;
15 }
16
17 public int getNumNuts() {
18 return numNuts;
19 }
20
21 public boolean setNumNuts(int newNumNuts) {
22 if (newNumNuts < 0) return false;
23 numNuts = newNumNuts;
24 return true;
25 }
26 }
As you can see on line 4, the numNuts property
is now private, meaning that only code within this class is allowed to access
it. The growNut and pickNut properties remain
unchanged; they can continue to update the numNuts property
directly (the constraints in pickNut ensure that the value of
numNuts remains legal). Since we still want code to be able to determine
the number of nuts in a tree, we have added a public getNumNuts
method that simply returns the value of the numNuts property. As
for setting the number of nuts, we have added a setNumNuts method
that takes an integer value as a parameter. That value is checked to ensure that
it is positive or zero (since we can't have a negative number of nuts) and then
sets the numNuts property to this new value.
These two new methods, getNumNuts and
setNumNuts, are known as accessor methods; that
is, they are methods used for accessing a property. Accessors are very typical
of a well-designed object. Even in cases where any value is acceptable, you
should make your objects' properties private and provide accessor methods to
access them. Doing this allows your programs to exhibit an important feature of
object oriented programming called encapsulation.
Encapsulation means that the internal representation of an object is separated from the interface it presents to other objects in your program. In other words, a programmer that uses your class only needs to know what the public methods do, not how they work. The advantage is that you can change how your class works to improve performance or add new features without breaking any code that relies on the methods provided by your original class.
For example, if you decided you wanted to represent each
coconut as an individual object of class Coconut instead of using a
single integer variable to keep count, you could make the necessary changes and
still have the same four methods as the implementation above. Old code that was
written with the original interface in mind would continue to work as before,
while new code could take advantage of the new features (which would of course
be provided by new methods).
As an exercise, rewrite the Tree class so that
it correctly encapsulates its height property
A constructor is a special type of method that is invoked automatically when an object is created. Constructors allow you to specify stating values for properties, and other such initialization details.
Consider once again our Tree class;
specifically, the declaration of its height property (which should
now be private and accompanied by accessor methods):
private int height = 0;
It's the "= 0" part that concerns us here. Why
should all new trees be of height zero? Using a constructor, we can let users of
this class specify the initial height of the tree. Here's what it looks like:
private int height;
public Tree(int height) {
if (height < 0) this.height = 0;
else this.height = height;
}
At first glance, this looks just like a normal method. There are two differences, however:
void, int, boolean,
etc.) in their declaration. Tree class, its
constructor must also be named Tree. By convention, this is the
only case where a method name should be capitalized.
So dissecting this line by line, we are declaring a public
constructor that takes a single parameter and assigns its value to an integer
variable height. Note that this is not the object property
height, as we shall see momentarily. The second line checks to see
if the height variable is less than zero. If it is, we set the
height property of the tree to zero (since we don't want to allow
negative tree heights). If not, we assign the value of the parameter to the
property.
Notice that since we have a local variable called
height, we must refer to the height property of the current
object as this.height. this is a special variable in
Java that always refers to the object in which the current code is executing. If
this confuses you, you could instead name the constructor's parameter something
like newHeight. You'd then be able to refer to the Object property
simply as height.
Since the Tree class now has a constructor
with a parameter, you must specify a value for that parameter when creating new
Trees:
Tree myTree = new Tree(10); // Initial height 10
Sometimes it makes sense to have two different versions of
the same method. For example, when we modified the pickNut method
in the CoconutTree class to require a parameter that specified the
number of nuts to pick, we lost the convenience of being able to pick a single
nut by just calling pickNut(). Java actually lets you declare both
versions of the method side by side and determines which one to use by the
number and type of the parameters passed when the method is called. Methods that
are declared with more than one version like this are called
overloaded methods.
Here's how to declare the two versions of the pickNut
method:
public boolean pickNut() {
if (numNuts == 0) return false;
numNuts = numNuts – 1;
return true;
}
public boolean pickNut(int numToPick) {
if (numToPick < 0) return false;
if (numToPick > numNuts) return false;
numNuts = numNuts – numToPick;
return true;
}
One way to save yourself some typing is to notice that
pickNut() is actually just a special case of pickNut(int
numToPick); that is, calling pickNut() is the same as
calling pickNut(1), so you can implement pickNut() by
simply making the equivalent call:
public boolean pickNut() {
return pickNut(1);
}
public boolean pickNut(int numToPick) {
if (numToPick < 0) return false;
if (numToPick > numNuts) return false;
numNuts = numNuts – numToPick;
return true;
}
Not only does this save two lines of code, but if you ever
change the way the pickNut method works, you only have to adjust
one method instead of two.
Constructors can be overloaded in the same way as normal methods. If you miss the convenience of being able to create a new Tree of height zero, you can declare a second constructor that takes no parameters:
private int height;
public Tree() {
this(0);
}
public Tree(int height) {
if (height < 0) this.height = 0;
else this.height = height;
}
Note that we have once again saved ourselves some typing by
implementing the simpler method (Tree()) by invoking a special case
of the more complex method (Tree(0)). In the case of a constructor,
however, you call it by the special name this.
I covered inheritance in Part One of this article, but I
left out one advanced issue for the sake of brevity that I'd like to cover now:
overriding methods. As you know, an object of class
CoconutTree inherits all of the features of the Tree
class, on which it is based. Thus, CoconutTrees have grow
methods just like Trees do.
But what if you wanted CoconutTrees to sprout
new coconuts when they grew? Sure, you could call the growNut
method every time you caused a CoconutTree to grow, but it would be
nicer if you could treat Trees and CoconutTrees
exactly the same way (i.e. call their grow method) and have them
both do what they're supposed to do when objects of their type grow.
To have the same method do something different in a
subclass, you must override that method with a new
definition in the subclass. Put simply, you can re-declare the grow
method in the CoconutTree class to make it do something different!
Here's a new definition for grow that you can add to your
CoconutTree class:
public void grow() {
height = height + 1;
growNut();
}
Simple, right? But what if you added new functionality to
the grow method in the Tree class? How could you make
sure that this was inherited by the CoconutTree class? Like in our
discussion of overloaded methods, where we implemented a simple method by
calling a special case of the more complicated method, we can implement a new
definition for a method in a subclass by referring to its definition in the
superclass:
public void grow() {
super.grow();
growNut();
}
The super.grow() line invokes the version of
grow defined in the superclass, thus saving us from having to
reinvent the wheel. This is especially handy when you are creating a class that
extends a class for which you do not have the source code (e.g. a class file
provided by another developer). By simply calling the superclass versions of the
methods you are overriding, you can ensure that your objects aren't losing any
functionality.
Constructors may be overridden just like normal methods.
Here's a set of constructors for the CoconutTree class, along with
the new declaration of the numNuts property without an initial
value:
private int numNuts;
public CoconutTree() {
super();
numNuts = 0;
}
public CoconutTree(int height) {
super(height);
numNuts = 0;
}
public CoconutTree(int height, int numNuts) {
super(height);
if (numNuts < 0) this.numNuts = 0;
else this.numNuts = numNuts;
}
The first two constructors override their equivalents in
the Tree class, while the third is completely new. Notice that we
call the constructor of the superclass as super(). All three of our
constructors call a constructor in the superclass to ensure that we are not
losing any functionality.
If you went back and examined every code example we have seen so far, there should only remain one keyword that puzzles you. Surprisingly, it appears in the very first article in this series, and at the beginning of every Java program we have written so far:
public static void main(String[] args) {
In case you didn't spot it, the keyword in question is
static. Both methods and properties can be
declared static. Static members belong to the class instead of to Objects of
that class. Before I explain why the main method is declared static, let's look
at a simpler case.
It might be useful to know the total number of Trees
that had been created in our program. To this end, we could create a static
property called totalTrees in the Tree class, and
modify the constructor to increase its value by one every time a Tree was
created. Then, using a static method called getTotalTrees, we could
check the value at any time by calling Tree.getTotalTrees().
Here's the code for the modified Tree class:
public class Tree {
private static int totalTrees = 0;
private int height;
public Tree() {
this(0);
}
public Tree(int height) {
totalTrees = totalTrees + 1;
if (height < 0) this.height = 0;
else this.height = height;
}
public static int getTotalTrees() {
return totalTrees;
}
...
}
Static members are useful in two main situations:
The main function is an example of the latter
case. Since it doesn't make sense to have more than once instance of the
main function (i.e. a program can only have one program), it is declared
static.
Another example of a static member that we have seen is the
out property of the System class (also known as
System.out, we have used its println method on many
occasions). Since there is only one system on which this program is running, it
is represented by a class containing static properties (e.g. out)
and methods (e.g. exit), rather than an instance of a class.
Don't worry too much if you can't quite wrap your head
around the reasoning behind the use of static members in the program and the
System classes. As long as you can grasp how the tree-counting
example above keeps track of the total number of Tree objects
created, you're in good shape.
I wouldn't blame you for feeling a little overwhelmed at this point. If you're anything like me, your first impression of Object Oriented Programming (OOP) in Java is that it is extremely powerful, extremely complicated, and very different from anything you have worked with before.
Fortunately, you get used to it.
As you follow along through the rest of this series, the sometimes frightening concepts presented in this article will blend into a natural way of working with software components that model real-world things and work together in sensible ways to achieve the desired outcome. The more Java you see and write yourself, the more you'll get used to this way of working, and the less you'll want to return to the old way of doing things. Ultimately, Object Oriented Programming is more fun!
You now have an effectively complete grasp of the Java language itself. What remains for you to learn before you can put that knowledge to practical use is a set of classes. Java includes packages of classes for performing all sorts of tasks, from building graphical user interfaces to creating dynamic Web sites. In the next article in this series, I'll introduce you to the classes related to building Java Servlets, the most basic component of Java-powered dynamic Web sites.
Kevin
began developing for the Web in 1995 and is a highly respected technical
author. He wrote
"Build your own Database Driven Website using PHP and MySQL", a practical
step-by-step guide published by SitePoint.com, and he's editor of the
SitePoint Tech
Times, a bi-weekly newsletter for technically-minded Web developers. Kev
believes that any good Webmaster should have seen at least one episode of
MacGyver.
Kevin Yank has written 65 articles for SitePoint with an average reader rating of 8.9.
Whether you consider yourself to be an experienced Java developer or not, it's a safe bet that you've heard of Java Applets. Applets are little Java programs that run as part of a Web page. Since they're sort of 'mini-applications', they were dubbed 'applets'. Java Servlets got their name in a similar way.
Think of Servlets as highly efficient CGI programs written in Java. When a Servlet-capable Web server receives a request for a URL that corresponds to a Java Servlet, the server hands the request off to the Servlet for processing. The Servlet dynamically produces a response to the request (typically an HTML Web page) and sends it back to the requesting browser. If you think of Servlets in this context as 'mini-servers', their name makes perfect sense.
In this article, I'll take you through the basics of writing and deploying Java Servlets on your own Web server. I'll begin with the assumption that you're already equipped with a Servlet-capable Web server. While there are many offerings in this arena, the free combination of Apache and Tomcat is the most readily available. Most experienced Java developers prefer one of the slick, commercial solutions such as Caucho Resin, IBM WebSphere, or Allaire JRun (see a complete list); and while most of these are free for non-commercial use, the standard, "nitty gritty" methods supported by Tomcat are what we'll work with in this article. If you haven't already set up Apache and Tomcat, now would be a good time. See my JSP Quick-Start Guide for a helpful walkthrough, upon which the assumed configuration in this article is based.
By their very nature as Java programs, Servlets require a significant amount of knowledge to develop with. At the very least, you'll need to be familiar with the basics of the Java language before you undertake the task of writing your first Java Servlet. The previous articles in this series, Getting Started with Java, Java Language Basics and Object Oriented Concepts in Java Part 1 and Part 2 are definitely required reading if you're just making your start in Java programming.
If you're relatively comfortable with the features of the Java language presented in those articles, and you've got Apache and Tomcat running together on your server, you're ready to go! Let's write a Servlet!
When it comes right down to it, a Servlet is just a Java class, and you should already know how to write a Java class:
public class MyClassName {
// ... properties and methods ...
}
But not just any class will do. Servlets for use on the Web
should be subclasses of the javax.servlet.http.HttpServlet class,
which is built into every Web server that supports servlets. Although different
servers may implement this class differently, the properties and methods
supported by it are dictated by the
Java Servlet Specification. As of this writing, version 2.2 is the latest
release of the spec, though version 2.3 is in the final draft stage. The
documentation that makes up the specification includes a
reference of all of the classes that Servlet-capable servers must provide.
So creating a Servlet is as simple as creating a subclass
of HttpServlet:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class MyServlet extends HttpServlet {
// ... properties and methods ...
}
Notice that we're importing the three packages
java.io, javax.servlet and javax.servlet.http
in the above. javax.servlet.http contains the HttpServlet
class that we're extending, while javax.servlet contains a number
of classes related to working with Servlets and java.io contains
all the standard Java classes for performing input and output. Since the vast
majority of Servlets make use of classes in those latter two packages, it's best
to just include them right off the bat so we don't forget later.
A Servlet must provide at least one method that is used by
the Web server to handle requests. The name of the method(s) depends on the type
of request we want to handle. An HTTP GET request is the simplest form of page
request, and comes about either as a result of the user typing a URL or clicking
on a link. To let your Servlet handle GET requests, you must provide a method
called doGet as follows:
public void doGet(HttpServletRequest req,
HttpServletResponse rsp)
throws ServletException, IOException {
// ... handle GET requests
}
As you can see, doGet must be a public
method that returns nothing (void), and takes two parameters:
HttpServletRequest object (this class is
part of the javax.servlet.http package), which in the above
example we assign to a variable called req. HttpServletResponse object (also in
javax.servlet.http), which we assign to rsp.
When this method is called, the HttpServletRequest
(req) passed as a parameter will be an object that provides access
to all the information related to the browser request that triggered this
Servlet. Using various methods of HttpServletRequest, you can find
out things like the IP address of the requesting browser, or the values sent in
the URL query string (e.g. index.html?name=value). Meanwhile the
HttpServletResponse (rsp) represents the response to
be sent to the browser. It is this object that allows us to send HTML code back
to the browser, for instance. But more on req and rsp
in a moment.
If you're worried about the throws ServletException,
IOException portion of the function declaration, don't be. We haven't
covered this in any of the previous articles in this series, but it's really
pretty simple. All this does is indicate the types of Exceptions
(errors) that may occur as a result of calling this method. In this case, when
the Web server calls the doGet function in order to process a GET
request, it must be prepared for the fact that a ServletException
or an IOException may occur, and it must handle these errors
gracefully. While this sounds scary, it actually makes our job easier. An
IOException, for example, could occur if the Web browser was closed
before it finished downloading the response our Servlet was sending it. But
since the doGet function is declared such that it may throw (cause)
IOExceptions, we don't have to worry about these errors, since the
Web server will handle them for us when they do occur!
Now, in this example, we'll make our Servlet send a simple
HTML page to the browser in response to its request. Here's the complete code
for the doGet method:
public void doGet(HttpServletRequest req,
HttpServletResponse rsp)
throws ServletException, IOException {
rsp.setContentType("text/html");
PrintWriter out = rsp.getWriter();
out.println("<html>");
out.println("<head><title> Simple Servlet </title></head>");
out.println("<body>");
out.println("<p>This is a simple Servlet!</p>");
out.println("</body></html>");
}
This again isn't as complicated as it may seem at first glance. Let's step through the body of this method one line at a time:
rsp.setContentType("text/html");
On this line, we are calling the setContentType
method of the rsp variable (which you'll recall contains an
HttpServletResponse object). This method sets the HTTP Content-Type
header to the "text/html" MIME type, which tells the Web browser to
expect an HTML Web page. Any Servlet that generates a Web page must start by
setting this content type. Likewise, a Servlet that generates a plain text file
would set the Content-Type to "text/plain", and a
Servlet that generated a GIF file would use "image/gif".
PrintWriter out = rsp.getWriter();
Now, since we're going to generate a Web page, we'll want
to send HTML code to the Web browser. HTML code is simply plain text, and the
standard Java I/O class for outputting plain text data is
java.io.PrintWriter. On this line, we declare a variable called out
to store a PrintWriter (recall that we imported the java.io
package, so we can refer to this class directly without giving its fully
qualified name). To obtain a PrintWriter object that is set up to
output text as the response to the Web browser, we simply call the
getWriter method of rsp, which contains our response object,
and assign the returned value to our new out variable.
out.println("<html>");
The rest of the doGet method simply uses the
PrintWriter (out) to output HTML code to the browser.
Just as in the sample programs in previous articles, where we could output text
to the screen with System.out.println (System.out is
also a PrintWriter), we can output lines of text to the Web browser
with the println method of our out object. Recall that
println automatically starts a new line at the end of the
String that it is told to output. If you don't want to start a new line
in the HTML code, you can use the print method instead of
println.
Download the full
MyServlet.java file or type it out from the listings above and save it
somewhere convenient on your computer (I use a directory called D:\JavaDev,
for example). Next, we'll see how to compile and deploy a Servlet.
All of the Java programs we've seen so far were very simple
to compile. Unfortunately, if you try to compile the MyServlet.java
file we produced in the previous section, you'll get a number of pretty ugly
error messages:
D:\javadev> javac MyServlet.java
MyServlet.java:2: package javax.servlet does not exist
import javax.servlet.*;
^
MyServlet.java:3: package javax.servlet.http does not exist
import javax.servlet.http.*;
^
MyServlet.java:5: cannot resolve symbol
symbol : class HttpServlet
location: class MyServlet
public class MyServlet extends HttpServlet {
^
...
Now, the best tactic I find when tackling compilation
errors is to look at the errors listed at the top first, since those errors
could actually be causing some of the other errors that are appearing lower
down. In this case, for example, the four "cannot resolve symbol" errors you're
likely to see are actually a result of the two "package does not exist" errors
at the top. Looking more closely, you'll notice that the compiler is choking on
the two import commands that we used to import the
javax.servlet and javax.servlet.http packages. Since it
can't import those packages, we won't be able to use any of the classes that
reside in them, and it turns out that all of the "cannot resolve symbol" errors
refer to places where we're trying to do so.
So why can't it find those two packages? Well, these two
packages aren't actually built into Java like java.io is. Instead,
they come with the Servlet-capable Web server (e.g. Tomcat). So before the Java
compiler will be able to compile our Servlet, we need to let it know where to
find the classes in these two packages.
The classes required are normally stored in a file called
servlet.jar. The exact location of this file will depend on the
particular Web server software you use, but in the case of Tomcat you can find
it in the lib subdirectory of the main Tomcat installation
directory (e.g. d:\Program Files\Apache Group\jakarta-tomcat-3.2.3\lib\servlet.jar).
For the Java compiler to be able to compile Servlets, you need to add this file
to your Java class path.
By default, Java looks for classes in the current directory (".")
only. Thus, "." is the default class path. If you change the class
path to include the servlet.jar file (".;d:\...\lib\servlet.jar"
under Windows, ".:/usr/.../lib/servlet.jar" in Unix), then the
Servlet should compile just fine.
You can specify a class path to use when you run
javac.exe as follows:
d:\javadev> javac -classpath ".;d:\Program
Files\Apache Group\
jakarta-tomcat-3.2.3\lib\servlet.jar" MyServlet.java
Obviously, the path to servlet.jar can be
quite long and painful to type every time you want to compile a Servlet. As an
alternative, you can set an environment variable called CLASSPATH
to your desired class path. Set this the same way you do the PATH
environment in the particular operating system you are using (instructions for
adjusting the PATH environment variable in various operating
systems are provided in the install instructions for the JDK if you need them).
To temporarily set the CLASSPATH environment variable under
Windows, you can use the SET command on the MS-DOS Command Prompt:
d:\javadev> SET CLASSPATH=.;d:\Program Files\Apache
Group\
jakarta-tomcat-3.2.3\lib\servlet.jar
d:\javadev> javac MyServlet.java
Whichever way you go about setting your class path, you
should now be able to successfully compile MyServlet.java to obtain
MyServlet.class (or download it
here).
In its default configuration, Tomcat expects you to place
compiled Servlets in the webapps\ROOT\WEB-INF\classes subdirectory
of the Tomcat installation directory to deploy them. Place your compiled
MyServlet.class file in that directory, then (assuming Tomcat is running
on your local computer) load http://localhost:8080/servlet/MyServlet.
If you did everything right, you should see a Web page a lot like this one:
If
you have Apache installed to interface with Tomcat using mod_jk,
you should also be able to view your Servlet with http://localhost/servlet/MyServlet
(or http://localhost:8000/servlet/MyServlet if you have configured
Apache to run on port 8000).
Most of the time, that's all you need to do to deploy a
Servlet! There are some situations, however, where you'd like to make your
Servlet available from a different address. One common case is when you assign a
package name to a Servlet. For example, consider what would happen if placed the
MyServlet class in the package com.sitepoint.web by
adding the line
package com.sitepoint.web;
to the top of the MyServlet.java file. To
deploy the MyServlet.class file, you would place it in
webapps\ROOT\WEB-INF\classes\com\sitepoint\web (recall that the locations
of .class files must reflect their package names), and load it with
its fully-qualified class name (http://localhost:8080/servlet/com.sitepoint.web.MyServlet).
Already this is a fairly ugly URL, and things can get a lot messier with log
package or class names.
For this reason, you may want to assign an alternate name to your Servlet. This is done with the
web.xml file in the WEB-INF
directory (e.g. webapps\ROOT\WEB-INF\web.xml). This is an XML file
that lets you configure the Servlets you have deployed. Since XML files are
plain text, you can simply open it in Notepad to make the required changes. When
you first install Tomcat, web.xml doesn't contain any configuration
information:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
</web-app>
By adding tags between <web-app> and
</web-app>, you can add configuration information for your servlets.
Here's how to assign the name 'my' to MyServlet:
<web-app>
<servlet>
<servlet-name>
my
</servlet-name>
<servlet-class>
MyServlet
</servlet-class>
</servlet>
</web-app>
If you save the above changes, then shutdown and restart
Tomcat, you will be able to access your Servlet as
http://localhost:8080/servlet/my. This may not seem like a big deal, but
when your Servlet's class name is 25 characters in length and is deeply nested
in a package, you'll appreciate being able to give it a nice, short name.
Assigning your Servlet a name also lets you use that name
to specify additional configuration parameters for your Servlet. The
<servlet-mapping> tag, for instance, lets you map your Servlet to any URL
or URL pattern on your server:
<web-app>
<servlet>
<servlet-name>
my
</servlet-name>
<servlet-class>
MyServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>
my
</servlet-name>
<url-pattern>
/my.html
</url-pattern>
</servlet-mapping>
</web-app>
The above code will let you access you Servlet as
http://localhost:8080/my.html -- completely hiding the fact that you're
using a Servlet at all! You can also specify a <url-pattern> with a
wildcard character such as /my/*, which would use your Servlet to
display any URL that started with "http://localhost:8080/my/", or
*.blah, which would map all requests for filenames ending in
.blah to your Servlet. Since the HttpServletRequest object
that your Servlet receives lets your Servlet examine the URL that was requested,
you could conceivably map a single Servlet to /* and have it handle
every request on your Website, sending different responses depending on the URL
requested!
If you have Apache set up as your main Web server using
mod_jk to forward requests for Servlets and JavaServer Pages (JSPs)
to Tomcat, you'll find that <url-pattern> doesn't work as expected.
This is because, by default, Apache will only forward requests for files ending
in .jsp or files in the /servlet directory to Tomcat
for processing. To forward additional URL patterns to Tomcat, you must use the
JkMount directive in your Apache configuration file. Make sure you
do this after the line where you Include Tomcat's mod_jk.conf-auto
file (which loads the module required for JkMount to work). For
example, to map /my/*.blah (all .blah files in the /my
directory) to Tomcat, you would add the following:
JkMount /my/*.blah ajp13
Note that we specify the more efficient ajp13
protocol for communication between Apache and Tomcat for this mapping (Tomcat's
mod_jk.conf-auto file currently uses the older, less efficient
ajp12 for its default mappings). With that change made, restart
Tomcat and Apache and your mapping should now work through your Apache server.
As you can see, all this deployment and configuration of
Servlets is a fairly messy business when done by standard methods. Commercial
Web servers like those I mentioned in the introduction often provide nice,
graphical administration interfaces that make all these low-level modifications
for you in the background. The format of the web.xml file, however,
is defined in the Servlet standard, and is supported by all Servlet-enabled
servers, even if easier methods are provided for managing the settings it
contains
The simple Servlet (MyServlet) that we have
worked with so far isn't terribly exciting, because it displays the same thing
every time it is loaded. The power of Servlets is that they can generate a new
dynamic response every time they are loaded. Common uses of Servlets include
retrieving dynamic content from a database, displaying XML documents as HTML
using XSL stylesheets, and processing form submissions and taking appropriate
actions (e.g. ecommerce applications).
For our first dynamic Servlet, we'll display the current server date and time. Here's the code for the servlet (Time.java):
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Date;
public class Time extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse rsp)
throws ServletException, IOException {
rsp.setContentType("text/html");
PrintWriter out = rsp.getWriter();
Date now = new Date(); // The current date/time
out.println("<html>");
out.println("<head><title> Time Check </title></head>");
out.println("<body>");
out.println("<p>The time is: " + now + "</p>");
out.println("</body></html>");
}
}
All in all, this Servlet is very similar to MyServlet.
Let's look at what's new:
import java.util.Date;
We import Java's built-in Date class from the
java.util package. You can read up on this class in the Java API
documentation if you're curious about its properties and methods.
Date now = new Date(); // The current date/time
We create a new variable called now and store
a new Date object in it. When a Date object is created, it contains
the date and time at which it was created, and will display them when it is
printed out as part of a String:
out.println("<p>The time is: " + now + "</p>");
Compile this file (or download
Time.class) and deploy it as shown in the previous section. Now, when you
load http://localhost:8080/servlet/Time you'll see a page like this
one:
Click
Reload a few times in your browser and watch the page change each time.
In this article, we learned the basics of Java Servlets -- small Java programs that run inside your Web server and process browser requests and return dynamically-generated Web pages in response. We saw how to write, compile, and deploy a simple Servlet using standard methods supported by all Servlet-enabled Web servers. Finally, we saw a slightly more complex example that displays the current time whenever it is loaded.
There's a lot more to Servlets than what we saw here! In
Part 2, we'll see how to use the HttpServletRequest object to
process form submissions with a Servlet. We'll also look at the
HttpServletResponse object to see what else it's able to do. Finally,
we'll learn a few more tricks that can be used in web.xml to
fine-tune the Servlets installed on our Web server.
For
a complete and thorough look at Servlets and everything they're capable of, I
recommend Jason Hunter and William Crawford's excellent book,
Java Servlet Programming 2nd Edition. Not only does it cover everything
there is to know about Servlets with an incredible level of detail, but it does
so while supporting every point with practical examples and lucid, and sometimes
humorous discussion. The book also delves into many of the technologies that are
built on top of the Servlets framework, such as JavaServer Pages (JSP), the
Element Construction Set (ECS), and the Tea Framework.
Kevin
began developing for the Web in 1995 and is a highly respected technical
author. He wrote
"Build your own Database Driven Website using PHP and MySQL", a practical
step-by-step guide published by SitePoint.com, and he's editor of the
SitePoint Tech
Times, a bi-weekly newsletter for technically-minded Web developers. Kev
believes that any good Webmaster should have seen at least one episode of
MacGyver.
Kevin Yank has written 65 articles for SitePoint with an average reader rating of 8.9.
“Content is king.” Cliché, yes; but it has never been more true. Once you've mastered HTML and learned a few neat tricks in JavaScript and Dynamic HTML, you can probably design a pretty impressive-looking Website. But your next task must be to fill that fancy page layout with some real information. Any site that successfully attracts repeat visitors has to have fresh and constantly updated content. In the world of traditional site building, that means HTML files—and lots of 'em.
The problem is that, more often than not, the people who provide the content for a site are not the same people who handle its design. Frequently, the content provider doesn't even know HTML. How, then, is the content to get from the provider onto the Website? Not every company can afford to staff a full-time Webmaster, and most Webmasters have better things to do than copying Word files into HTML templates anyway.
Maintenance of a content-driven site can be a real pain, too. Many sites (perhaps yours?) feel locked into a dry, outdated design because rewriting those hundreds of HTML files to reflect a new look would take forever. Server-side includes (SSIs) can help alleviate the burden a little, but you still end up with hundreds of files that need to be maintained should you wish to make a fundamental change to your site.
The solution to these headaches is database-driven site design. By achieving complete separation between your site's design and the content you want to present, you can work with each without disturbing the other. Instead of writing an HTML file for every page of your site, you only need to write a page for each kind of information you want to be able to present. Instead of endlessly pasting new content into your tired page layouts, create a simple content management system that allows the writers to post new content themselves without a lick of HTML!
In this book, I'll provide you with a hands-on look at what's involved in building a database-driven Website. We'll use two tools for this, both of which may be new to you: the PHP scripting language and the MySQL relational database management system. If your Web host provides PHP and MySQL support, you're in great shape. If not, we'll be looking at the setup procedures under Linux, Windows, and Mac OS X, so don't sweat it.
These articles are aimed at intermediate or advanced Web designers looking to make the leap into server-side programming. You'll be expected to be comfortable with simple HTML, as I'll make use of it without much in the way of explanation. No knowledge of JavaScript is assumed or required, but if you do know JavaScript, you'll find it will make learning PHP a breeze.
By the end of the series, you can expect to have a grasp of what's involved in setting up and building a database-driven Website. If you follow the examples, you'll also learn the basics of PHP (a server-side scripting language that gives you easy access to a database, and a lot more) and Structured Query Language (SQL — the standard language for interacting with relational databases) as supported by MySQL, one of the most popular free database engines available today. Most importantly, you'll come away with everything you need to get started on your very own database-driven site in no time!
This series comprises the following 4 chapters. Read them in order from beginning to end to gain a complete understanding of the subject, or skip around if you need a refresher on a particular topic.
Before you can start building your database-driven Web presence, you must first ensure that you have the right tools for the job. In this first chapter, I'll tell you where to obtain the two essential components you'll need: the PHP scripting language and the MySQL database management system. I'll step you through the setup procedures on Windows, Linux, and Mac OS X, and show you how to test that PHP is operational on your Web server.
Chapter 2: Getting Started with MySQL
Although I'm sure you'll be anxious to get started building dynamic Web pages, I'll begin with an introduction to databases in general, and the MySQL relational database management system in particular. If you've never worked with a relational database before, this should definitely be an enlightening chapter that will whet your appetite for things to come! In the process, we'll build up a simple database to be used in later chapters.
Chapter 3: Getting Started with PHP
Here's where the fun really starts. In this chapter, I'll introduce you to the PHP scripting language, which can be easily used to build dynamic Web pages that present up-to-the-moment information to your visitors. Readers with previous programming experience will probably be able to get away with a quick skim of this chapter, as I explain the essentials of the language from the ground up. This is a must-read chapter for beginners, however, as the rest of this book relies heavily on the basic concepts presented here.
Chapter 4: Publishing MySQL Data on the Web
In this chapter we bring together PHP and MySQL, which you'll have seen separately in the previous two chapters, to create some of your first database-driven Web pages. We'll explore the basic techniques of using PHP to retrieve information from a database and display it on the Web in real time. I'll also show you how to use PHP to create Web-based forms for adding new entries to, and modifying existing information in, a MySQL database on-the-fly.
The
four chapters in this series are actually only the first part of a book.
Build Your Own Database Driven Website Using PHP & MySQL
contains not only the four chapters above, but eight more chapters that cover
advanced database concepts, the design of a complete content management system,
MySQL server administration, and much, much more! The book also includes a
complete set of appendices to make it the ideal desk reference for PHP and MySQL
Web development. For more information, see the
book page.
If you prefer to read the Adobe Acrobat PDF version of these first four chapters, you can Download the first Four Chapters FREE.
If you have a question about any of the information covered in this series, your best chance of a quick response is to post your query in the SitePoint.com Forums.
If you can't find your answer through the forums, or if you wish to contact me for any other reason, the best place to write is here. We have a well-manned email support system set up to track your inquiries, and if our support staff is unable to answer your question, they send it straight to me. Suggestions for improvement as well as notices of any mistakes you may find are especially welcome.
And so, without further ado, let's get started!
Kevin
began developing for the Web in 1995 and is a highly respected technical
author. He wrote
"Build your own Database Driven Website using PHP and MySQL", a practical
step-by-step guide published by SitePoint.com, and he's editor of the
SitePoint Tech
Times, a bi-weekly newsletter for technically-minded Web developers. Kev
believes that any good Webmaster should have seen at least one episode of
MacGyver.
Kevin Yank has written 65 articles for SitePoint with an average reader rating of 8.9.
JavaServer Pages (JSP) is a server-side technology that allows developers to create Web-based applications that can make use of components that are developed in the Java programming language, according to the JavaBeans specification. In some respects, it can be compared to server-side scripting languages such as ASP and PHP. JSP is similar to PHP in the C-style syntax of the Java language, but JSP was also designed to be extendable using components like ASP.
When it comes right down to it, however, JSP is a technology like no other. Extremely fast, platform independent, highly scaleable with built-in support for distributed processing, compatible with all major Web servers, and FREE for most uses, one might wonder why JSP isn't used more than it is.
Well, as I see it, there are two main reasons for that:
In this article, I'll attempt to remedy the latter point by guiding you through the process of setting up a JSP-enabled Web server on a Linux machine. Hopefully, this will give you the head start you need to jump into the world of JSP development. I'll take you as far as getting a basic JSP page working on your server, and then you can dive into our JSP article series, The JSP Files fully equipped!
As for the Windows users in the audience, don't fret! Just see my JSP Quick-Start Guide for Windows!
While there are some great commercial servers out there for testing JSP pages (including IBM WebSphere, BEA WebLogic, and others), these can be beyond the reach of the average Web developer who just wants to add a new skill to his or her repertoire. For this reason, the server I recommend for people getting started with JSP is Apache Server. By hooking it up to the Jakarta Project's Tomcat Server (which we'll install in the next section), we can give it the ability to handle JSP pages, as well as related technologies like Java Servlets and Enterprise Java Beans (EJBs)!
Now, if you've already got Apache running (as most Linux users do), you don't have to reinstall it. This will be good news to people who are already using Apache to run PHP scripts or whatnot, because you'll be able to simply add JSP support to your existing server without disrupting whatever else you have set up.
If you don't have Apache installed, now is the time to do it. Just use your distribution's package manager to install Apache. When you're done, you can skip ahead to the next section. If you're not sure how to use your distribution's package manager, or if you prefer installing software yourself to letting the package manager do it, read on.
You'll need to go to
The Apache HTTP Server
Project's Web site to download the latest stable source release of Apache
Server for Unix. As of this writing, the current version is 2.0.44 (the filename
is httpd-2.0.44.tar.gz), and can be downloaded from the following
address:
http://www.apache.org/dist/httpd/.
Once you've downloaded the file, extract it to your home
directory (or wherever you find convenient) to create a directory called
httpd-2.0.44:
[kevin@sp kevin]$
tar xfz httpd-2.0.44.tar.gz
[kevin@sp kevin]$ cd httpd-2.0.44/
[kevin@sp httpd-2.0.44]$
Note, the [kevin@sp kevin]$ portion of the
above represents the command prompt. You only need to type the commands shown in
bold.
Next, you need to configure Apache so that it will be
compiled with the features you need and installed where you want it to go. The
following command (which should be typed all on one line) sets up Apache to be
installed in /usr/local/apache2 and enables dynamic module support
(which we'll need to interface with Tomcat) and the mod_rewrite
module (which is not important for this article, but is a useful feature you'll
probably want at some point):
[kevin@sp httpd-2.0.44]$
./configure --with-prefix=/usr/local/apache2
--enable-so --enable-rewrite
After all the diagnostic messages have scrolled by, you
should return to the command prompt. Now type the make command to
compile Apache server:
[kevin@sp httpd-2.0.44]$
make
Again, pages of messages will scroll by. When they're done,
the last step is to install Apache. Unless you specified a target directory
beneath your home directory above, you'll need to log in as the root
user (type su to do this) before you can proceed:
[kevin@sp httpd-2.0.44]$
su
Password: ********
[root@sp httpd-2.0.44]# make install
With Apache installed, you can run it by logging in as
root and running the apachectl program in the /usr/local/apache2/bin
directory with the start argument:
[root@sp /]# /usr/local/apache2/bin/apachectl
start
Open your Web browser and type http://localhost/
in the address field and press Enter. A Web page with the Powered by Apache logo
at the bottom should appear, explaining that Apache is correctly installed.
Congratulations, you've successfully installed Apache!
Obviously, you don't want to have to start Apache manually every time you start your computer. To get Linux to launch Apache at start-up, you need to place a link to the apachectl program in the start-up folder for each runlevel (or operating system mode) where you want Apache to run.
Here's the series of commands that will set up Apache to run automatically in runlevels 2, 3, 4, and 5 (all the normal operating modes of Linux systems), and shut down when the computer shuts down:
[root@sp /]# cd
/etc
[root@sp etc]# ln -s /usr/local/apache2/bin/apachectl init.d/apache2
[root@sp etc]# ln -s init.d/apache2 rc2.d/S91apache2
[root@sp etc]# ln -s init.d/apache2 rc3.d/S91apache2
[root@sp etc]# ln -s init.d/apache2 rc4.d/S91apache2
[root@sp etc]# ln -s init.d/apache2 rc5.d/S91apache2
[root@sp etc]# ln -s init.d/apache2
rc0.d/K20apache2
That should do it! To try it out, shut down your computer,
start it back up again, and see if you can still access the Apache server at
http://localhost/.
Since Apache doesn't support JSP out of the box, we need to add something else to the mix to provide that support. Unfortunately, JSP is too complicated to be supported by a simple Apache module; thus, we need to install an entirely new program to provide that support, then instruct Apache to forward requests for JSP pages to that program (note: this may sound like CGI, but it isn't; just wait and see). The program we'll be using is called Tomcat, and is also written by the Apache Group.
Tomcat is in fact a simple Web server in its own right. It doesn't support any of the advanced features of Apache, however; that's not its job! By linking Tomcat and Apache together, you get a system that provides full support for JSP (thanks to Tomcat) while maintaining the performance and expandability (PHP, Perl, SSL, etc.) of Apache.
Your first step should be to download and install the Java
2 Software Development Kit (Java 2 SDK) from Sun. This is required both to run
Tomcat (which is a Java program), and for Tomcat to be able to compile JSPs for
use. The current version of the Java 2 SDK (also called the JDK) as of this
writing is version 1.4.1_01, and is available for download
here. Download the ~42MB "Linux self-extracting file" (be sure to download
the SDK, not the JRE!). The filename should be
j2sdk-1_4_1_01-linux-i586.bin. Extract this file into your /usr/local
directory with this series of commands:
[kevin@sp kevin]$ su
Password: ********
[root@sp kevin]# chmod u+x j2sdk-1_4_1_01-linux-i586.bin
[root@sp kevin]# mv j2sdk-1_4_1_01-linux-i586.bin /usr/local/
[root@sp kevin]# cd /usr/local
[root@sp local]#
./j2sdk-1_4_1_01-linux-i586.bin
You can delete the j2sdk-1_4_1_01-linux-i586.bin
file now, or put it someplace safe for future use; you're done with it.
Java is now installed, but you need to do a few things to
settle it smoothly into your system. First, make a symbolic link so you can
access the Java installation with the easier-to-type name /usr/local/java:
[root@sp local]# ln
-s j2sdk1.4.1_01 java
Next, make links to the important programs that make up the
Java SDK in the /usr/local/bin directory, so you can run them from
anywhere:
[root@sp local]# ln -s java/bin/java /usr/local/bin/java
[root@sp local]# ln -s java/bin/javac /usr/local/bin/java
[root@sp local]# ln -s java/bin/jar /usr/local/bin/java
Now, we need to edit a couple of environment variables on
your system. Still as root, open the /etc/profile on
your system in your preferred text editor. Look for a line beginning with
PATH=. When you type a program name at the command prompt, this line sets
the directories that your system checks for that program. Check to make sure
/usr/local/bin is in the list. If it isn't, add the following line
right after the existing PATH= line:
PATH="$PATH:/usr/local/bin"
You also need to set the JAVA_HOME environment
variable to point to your Java installation. To do this, scroll right down to
the bottom of the file and add these two lines to the end:
JAVA_HOME="/usr/local/java"
export JAVA_HOME
Save the changes, log out, and then log back in. Java
should now be nicely installed and integrated with your system. To test it, you
can type java -version at the command prompt and make sure that it
reports your Java version correctly.
Now you're ready to install Tomcat. Download the latest
release from the Jakarta
Project Web site. As of this writing, the latest version was 4.1.18, and was
available at http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.1.18/bin/.
The file should be called jakarta-tomcat-4.1.18-LE-jdk14.tar.gz,
and is about 5.1MB.
Once you've downloaded the file, move it to your /usr/local
directory and extract it:
[kevin@sp kevin]$ su
Password: ********
[root@sp kevin]# mv jakarta-tomcat-4.1.18-LE-jdk14.tar.gz /usr/local/
[root@sp local]# tar xfz
jakarta-tomcat-4.1.18-LE-jdk14.tar.gz
You can delete the
jakarta-tomcat-4.1.18-LE-jdk14.tar.gz file now, or put it somewhere safe
for future use; you're done with it.
As with the Java SDK, create a link to the installation directory with a neater name for convenience:
[root@sp local]# ln
-s jakarta-tomcat-4.1.18-LE-jdk14 tomcat
Like Java, Tomcat requires an environment variable of its
own to be set for it to run properly. Open up your /etc/profile
file one more time and add these two lines to the end:
CATALINA_HOME="/usr/local/tomcat"
export CATALINA_HOME
Once again, save your changes, log out, then log back in for changes to take effect.
You're ready to start Tomcat! Log in as root
and type the following command to launch it:
[root@sp kevin]# $CATALINA_HOME/bin/startup.sh
If all goes well, the startup.sh script should
display the values of a few environment variables, and then Tomcat will launch
quietly in the background. Congrats -- Tomcat is up and running!
As I said before, Tomcat provides its own simple Web
server, and we can use this to test that it is working properly. Tomcat's Web
server is set up to use port 8080 by default, so open your Web browser and load
http://localhost:8080/. You should see the Tomcat home page, with
links to some examples that come preinstalled on the server.
Have a play with these examples if you're curious, and notice how the JSP examples take considerable time to load the first time you use them, but then work very quickly upon subsequent accesses. This happens because the first time a JSP page is accessed, Tomcat needs to compile it into a Java Servlet, which is a piece of pure Java code that can be run very quickly to process requests. That Servlet is then held in memory to process subsequent requests for the same JSP at blazing speed.
When you're done playing with Tomcat, shut it down by
running the shutdown.sh script the same way you ran the
startup.sh script above ($CATALINA_HOME/bin/shutdown.sh).
Tomcat will shut down after a few moments.
If you've got Apache running automatically at system
start-up, you'll probably want to do the same for Tomcat. Start by copying
(not linking) the catalina.sh script that came with Tomcat to your
/etc/init.d/ directory:
[root@sp kevin]# cd /etc
[root@sp etc]# cp /usr/local/tomcat/bin/catalina.sh
init.d/
This script relies on the JAVA_HOME and
CATALINA_HOME environment variables we set earlier, but these variables
do not exist while the system is starting up. We must therefore edit the script
a little so that it can serve as a system startup script.
Open the file in your favourite text editor, and scroll
down to the first blank line following the opening comments (any line that
begins with a # is a comment). Add these two lines at that point:
JAVA_HOME="/usr/local/java"
CATALINA_HOME="/usr/local/tomcat"
This script actually makes an attempt at detecting
CATALINA_HOME itself, but this attempt backfires if the script is not
actually in the Tomcat directory (which in this case it isn't). Scroll down and
look for a line that begins with CATALINA_HOME=. It should look
like this:
CATALINA_HOME=`cd "$PRGDIR/.." ; pwd`
Comment it out by putting a # at the start of
that line:
#CATALINA_HOME=`cd "$PRGDIR/.." ; pwd`
That completes the adjustments to catalina.sh.
You can now assign this as a start-up script in the various runlevels (operating
modes) of your computer:
[root@sp etc]# ln -s init.d/catalina.sh
rc2.d/S90tomcat
[root@sp etc]# ln -s init.d/catalina.sh rc3.d/S90tomcat
[root@sp etc]# ln -s init.d/catalina.sh rc4.d/S90tomcat
[root@sp etc]# ln -s init.d/catalina.sh rc5.d/S90tomcat
[root@sp etc]# ln -s init.d/catalina.sh
rc0.d/K19tomcat
That should do it! To try it out, shut down your computer,
start it back up again, and see if you can load the Tomcat home page at
http://localhost:8080/.
mod_jkNow that you've got Apache and Tomcat running side by side,
you need to link them together so that Apache can process JSP requests by
handing them off to Tomcat. There are actually several ways to do this, and all
involve installing an Apache module. The first option is to use mod_jk,
which was designed specifically for Tomcat 3.x to work with various servers and
uses a fairly efficient protocol for communication with Tomcat.
As of Tomcat 4.0, a new mechanism for linking Apache and
Tomcat is available: mod_webapp. This Apache module provides
efficient communication between Apache and Tomcat, and is exceedingly easy to
configure. Unfortunately, the developer in charge of mod_webapp has
some pretty strong feelings against Windows, so mod_webapp does not
work reliably on that platform. Rather than use a different module for each
platform, I prefer to stick with mod_jk on both Windows and Linux.
That way I know I've got a solution that works, whatever platform I need for a
particular job.
A revamped implementation of mod_jk called
mod_jk2 is available as of Tomcat 4.1. It was written to be more
modular, offer better performance, and improve the ease of configuration.
Unfortunately, documentation on mod_jk2 is still a little sketchy;
therefore, mod_jk is the module we'll install in this article.
mod_jkmod_jk comes in two
parts: a connector plug-in for Tomcat and an Apache module. The connector
plug-in is included with every copy of Tomcat 4.1. The other half of the
equation, the Apache module, is a different story.
Because Apache 2.0 is in a constant state of flux, older
versions of the mod_jk module will usually not be compatible with
newer versions of Apache 2.0. In general, you need a copy of mod_jk
that was compiled after the Apache 2.0 release you want to use it with. The
Jakarta team always tries to maintain a downloadable copy of mod_jk
that is compatible with the latest Apache 2.0 release on their Web site.
At this time, the latest release of mod_jk is
available from
http://jakarta.apache.org/builds/jakarta-tomcat-connectors/jk/release/v1.2.2/bin/linux/i386/.
The file is called mod_jk-2.0.43.so to signify that it was compiled
to work with Apache 2.0.43 (it will also work with 2.0.44). Download the file,
rename it to mod_jk.so, and copy it to the modules
subdirectory of your Apache 2.0 installation (/usr/local/apache2/modules).
With the Apache module installed and the Tomcat plug-in
built into the server, we must now configure both Apache and Tomcat to use
mod_jk to communicate with each other.
Now we need to configure Tomcat to use mod_jk.
Locate the server.xml file in the conf subdirectory of
your Tomcat directory and open it in a text editor of your choice.
Immediately following the <Server port="8005" ...>
tag near the top of the file, add the following:
<Listener className="org.apache.ajp.tomcat4.config.ApacheConfig"
modJk="/usr/local/apache2/modules/mod_jk.so" jkDebug="info"
workersConfig="/usr/local/tomcat/conf/jk/workers.properties"
jkLog="/usr/local/tomcat/logs/mod_jk.log" />
Be sure to replace the paths in bold with those on your system if they differ.
About halfway through the file, find the <Host name="localhost"
...> tag and add the following immediately after it:
<Listener className="org.apache.ajp.tomcat4.config.ApacheConfig"
append="true" />
Close server.xml, then create a new directory
called jk in that same directory (conf). This
directory is where we'll create the workers.properties file
mentioned in the first <Listener> tag above. Open up your text
editor again and type (or copy) in the following:
workers.tomcat_home=/usr/local/tomcat
workers.java_home=$(JAVA_HOME)
workers.th=$(workers.tomcat_home)
ps=\
worker.list=ajp13, ajp14
worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
worker.ajp13.lbfactor=1
worker.ajp14.port=8010
worker.ajp14.host=localhost
worker.ajp14.type=ajp14
worker.ajp14.secretkey=secret
worker.ajp14.credentials=myveryrandomentropy
worker.ajp14.lbfactor=1
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=ajp13
worker.inprocess.type=jni
worker.inprocess.class_path=$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar
worker.inprocess.cmd_line=start
worker.inprocess.jvm_lib=$(workers.th)$(ps)jre$(ps)bin$(ps)classic$(ps)jvm.dll
worker.inprocess.stdout=$(workers.th)$(ps)logs$(ps)inprocess.stdout
worker.inprocess.stderr=$(workers.th)$(ps)logs$(ps)inprocess.stderr
Be sure to adjust the tomcat_home line (shown
in bold) to match your system. Save the file as workers.properties
in your newly-created jk directory.
Restart Tomcat. If you haven't missed any steps, it should
automatically create another directory in its conf directory called
auto with a file called mod_jk.conf inside it. This
file contains everything that Apache needs to know to use Tomcat to process JSPs.
Because Tomcat generates all the configuration information
for Apache automatically as mod_jk.conf, all we need to do is point
Apache at that file! Open your Apache 2.0 configuration file (/usr/local/apache2/conf/httpd.conf)
in a text editor. Scroll down about 1/4 of the way through the file to find the
section entitled Dynamic Shared Object (DSO) Support. After the
LoadModule lines that appear below this heading, add the following
line (adjusted to match your Tomcat directory):
Include "/usr/local/tomcat/conf/auto/mod_jk.conf"
With that line added to httpd.conf, save your
changes and restart Apache (apachectl graceful). You should now get
the same page whether you load http://localhost:8080/examples/jsp/
(from Tomcat), or http://localhost/examples/jsp/ (from Apache).
Okay, playing with the examples can be fun (spoiler: the two colours you're looking for are Black and Cyan), but the real test is to set up a JSP of your own and make it run.
Open NotePad or your favourite text editor, and type in the following:
<hr />This example brought to you by JSP and
SitePoint.com!
Save the file as theEnd.html in a new
subdirectory of Tomcat's webapps directory called sitepoint.
Create a second new file in NotePad and type in the following:
<%@ page language="Java" %>
<html>
<head>
<title>A Simple JSP</title>
</head>
<body>
<p>
<% String num = request.getParameter("num");
if (num == null) { // No number specified
// Display the form
%>
<form action="<%= HttpUtils.getRequestURL(request) %>">
What should I count to? <input type="text" size="2" name="num" />
<input type="submit" />
</form>
<%
} else for (int i=1; i<=Integer.parseInt(num); i++) {
%>
Counting: <%= i %><br />
<% }
%>
</p>
<%@ include file="theEnd.html" %>
</body>
</html>
Save this as count.jsp in your new
sitepoint directory alongside theEnd.html.
Now, to make these two files visible, you need to create a
Java Web application to contain them. Doing this is nice and simple. Create a
subdirectory of your new sitepoint directory called WEB-INF.
In that subdirectory, create a text file called web.xml and type
the following into it:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
</web-app>
Save the file and then restart Tomcat or reboot your system
to allow Tomcat to become aware of the new Web application. You can then view
the page through Tomcat with the URL http://localhost:8080/sitepoint/count.jsp.
To make your new Web application visible through Apache, simply restart Apache. When you restarted Tomcat, it created a new automatic configuration file for Apache; restarting Apache will read in this new config file and add your new Web application to the lineup. Whenever you add a new Web application to Tomcat you need to perform this "Restart Tomcat, Restart Apache" process; fortunately, this doesn't happen often.
Once Apache is back up and running, open http://localhost/sitepoint/count.jsp.
There you have it: your first working JSP in Apache!
If you've worked in PHP or another scripting language before, then the simple example above may have left you a little underwhelmed. "That's it?" you may ask. "I went to all that trouble just to do something I could have done in 30 seconds with PHP?" Of course not! As a simple example, the above does not make use of any of the more powerful features of JSP, most of which require a fairly thorough understanding of the Java programming language to use.
Thus, your first step should be to learn Java if you haven't already. There are plenty of good books out there (check the Related Articles below for a review of my favourite), but if you're in a hurry or on a budget, my article Getting Started with Java and its successors should get you going.
Once you're up to speed on Java (and I don't mean to trivialize that -- it will take some work), you can turn your attention to Java Servlets, and then JavaServer Pages. My article, Java Servlets, should get you going with the former; as for the latter, a 8-part tutorial series, The JSP Files, is now available on SitePoint.com to teach you all you need to know. Enjoy!
Good luck! If you hit any snags along the way, the SitePoint.com Forum members are here to help! And if all else fails, you can always contact me through the email link at the top of this article.
| Tables Of Contents With Full Details: Page Title, Comment and Date Last Modified | ||||
| Alphabetical List Of All Company Policies | Table Of Data in Title Order | Staff Assignments showing titles | Programs & Projects In Title Order | Table of Notes In Title Order |
| Policies In Order Of Last Modified | Data In Order of Last Modified | Staff Assignments showing date last modified | Programs & Projects In Order of Last Modified | Table of Notes In Order Date Last Modified |