Essentials of The Java Programming Language: A Hands-On Guide, Part 1
Essentials of The Java Programming Language: A Hands-On Guide, Part 1
experience with other languages, and are familiar with things like
displaying text or graphics or performing simple calculations, this
tutorial could be for you. It walks through how to use the Java® 2
Platform software to create and run three common types of programs
written for the Java platform—applications, applets, and servlets.
You will learn how applications, applets, and servlets are similar and
different, how to build a basic user interface that handles simple end
user input, how to read data from and write data to files and
databases, and how to send and receive data over the network. This
tutorial is not comprehensive, but instead takes you on a straight and
uncomplicated path through the more common programming features
available in the Java platform.
If you have no programming experience at all, you might still find this
tutorial useful; but you also might want to take an introductory
programming course or read Teach Yourself Java 2 Online in Web Time
before you proceed.
Contents
Writing a Program
API Documentation
More Information
Constructors
To Summarize
More Information
Application to Applet
Packages
More Information
Swing APIs
Import Statements
Class Declaration
Global Variables
Constructor
Action Listening
Event Handling
Main Method
Applets Revisited
More Information
HTML Form
Servlet Backend
More Information
Exception Handling
Restricting Applications
Appending
More Information
Database Setup
o JDBC Driver
More Information
o Program Behavior
o File Summary
RemoteSend Class
Send Interface
RMIClient1 Class
RMIClient2 Class
More Information
In Closing
Lesson 1: Compiling and Running
A Simple Program
The computer age is here to stay. Households and businesses all over
the world use computers in one way or another because computers
help individuals and businesses perform a wide range of tasks with
speed, accuracy, and efficiency. Computers can perform all kinds of
tasks ranging from running an animated 3D graphics application with
background sound to calculating the number of vacation days you
have coming to handling the payroll for a Fortune 500 company.
But before you can write and compile programs, you need to
understand what the Java platform is, and set your computer up to run
the programs.
Writing a Program
Code Comments
API Documentation
More Information
Java programs are run (or interpreted) by another program called the
Java VM. If you are familiar with Visual Basic or another interpreted
language, this concept is probably familiar to you. Rather than running
directly on the native operating system, the program is interpreted by
the Java VM for the native operating system. This means that any
computer system with the Java VM installed can run Java programs
regardless of the computer system on which the applications were
originally developed.
Before you can write and run the simple Java program in this lesson,
you need to install the Java platform on your computer system.
Note: Make sure you have the Java platform installed and
configured for your system before you try to write and run
the simple program presented next.
Writing a Program
The easiest way to write a simple program is with a text editor. So,
using the text editor of your choice, create a text file with the following
text, and be sure to name the text file ExampleProgram.java. Java
programs are case sensitive, so if you type the code in yourself, pay
particular attention to the capitalization.
//A Very Simple Example
class ExampleProgram {
public static void main(String[] args){
System.out.println("I'm a Simple Program");
}
}
Here is the ExampleProgram.java source code file if you do not want to
type the program text in yourself.
The Java compiler is invoked at the command line on Unix and DOS
shell operating systems as follows:
javac ExampleProgram.java
Once your program successfully compiles into Java bytecodes, you can
interpret and run applications on any Java VM, or interpret and run
applets in any Web browser with a Java VM built in such as Netscape
or Internet Explorer. Interpreting and running a Java program means
invoking the Java VM byte code interpreter, which converts the Java
byte codes to platform-dependent machine codes so your computer
can understand and run the program.
The Java interpreter is invoked at the command line on Unix and DOS
shell operating systems as follows:
java ExampleProgram
At the command line, you should see:
I'm a Simple Program
Here is how the entire sequence looks in a terminal window:
Code Comments
Double Slashes
Double slashes (//) are used in the C++ programming language, and
tell the compiler to treat everything from the slashes to the end of the
line as text.
//A Very Simple Example
class ExampleProgram {
public static void main(String[] args){
System.out.println("I'm a Simple Program");
}
}
C-Style Comments
Doc Comments
API Documentation
More Information
See Java 2 SDK Tools for more information on setting the class path
and using the javac, and java commands.
You can also view the API Documentation for the Java 2 Platform on
the java.sun.com site.
_______
1
As used on this web site, the terms "Java virtual machine" or "JVM"
mean a virtual machine for the Java platform.
All programs written in the Java language (Java programs) are built
TM
from classes. Because all classes have the same structure and share
common elements, all Java programs are very similar.
Constructors
More Information
Application Structure and Elements
For example, a very simple class might store a string of text and
define one method to set the string and another method to get the
string and print it to the console. Methods that work on the data are
called accessor methods.
Every application needs one class with a main method. This class is the
entry point for the program, and is the class name passed to the java
interpreter command to run the application.
The code in the main method executes first when the program starts,
and is the control point from which the controller class accessor
methods are called to work on the data.
class ExampleProgram {
public static void main(String[]
args){
System.out.println("I'm a Simple
Program");
}
}
The main method for the simple example does not create an instance
of the ExampleProgram class because none is needed. The
ExampleProgram class has no other methods or fields, so no class
instance is needed to access them from the main method. The Java
platform lets you execute a class without creating an instance of that
class as long as its static methods do not call any non-static methods
or fields.
class LessonTwoA {
static String text = "I'm a Simple Program";
public static void main(String[] args){
System.out.println(text);
}
}
The LessonTwoB.java and LessonTwoC.java programs add a getText
method to the program to retrieve and print the text.
Note: The field and method return values are all type
String.
class LessonTwoB {
String text = "I'm a Simple Program";
static String text2 = "I'm static text";
String getText(){
return text;
}
String getStaticText(){
return text2;
}
public static void main(String[] args){
LessonTwoB progInstance = new LessonTwoB();
String retrievedText = progInstance.getText();
String retrievedStaticText =
progInstance.getStaticText();
System.out.println(retrievedText);
System.out.println(retrievedStaticText);
}
}
The LessonTwoC.java program accesses the static text field with the
static getText method. Static methods and fields are called class
methods and fields. This approach allows the program to call the static
getText method directly without creating an instance of the
LessonTwoC class.
class LessonTwoC {
static String text = "I'm a Simple Program";
//Accessor method
static String getText(){
return text;
}
public static void main(String[] args){
String retrievedText = getText();
System.out.println(retrievedText);
}
}
So, class methods can operate only on class fields, and instance
methods can operate on class and instance fields.
You might wonder what the difference means. In short, there is only
one copy of the data stored or set in a class field but each instance has
its own copy of the data stored or set in an instance field.
The figure
above shows
three class
instances with
one static field
and one
instance field.
At runtime, there is one copy of the value for static Field A and each
instance points to the one copy. When setFieldA(50) is called on the
first instance, the value of the one copy changes from 36 to 50 and all
three instances point to the new value. But, when setFieldB(25) is
called on the first instance, the value for Field B changes from 0 to 25
for the first instance only because each instance has its own copy of
Field B.
Constructors
class LessonTwoD {
String text;
//Constructor
LessonTwoD(){
text = "I'm a Simple Program";
}
//Accessor method
String getText(){
return text;
}
public static void main(String[] args){
LessonTwoD progInst = new LessonTwoD();
String retrievedText = progInst.getText();
System.out.println(retrievedText);
}
}
To Summarize
A simple program that prints a short text string to the console would
probably do everything in the main method and do away with the
constructor, text field, and getText method. But, this lesson used a
very simple program to show you the structure and elements in a
basic Java program.
More Information
_______
1
As used on this web site, the terms "Java virtual machine" or "JVM"
mean a virtual machine for the Java platform.
Application to Applet
Packages
More Information
Application to Applet
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Color;
public class SimpleApplet extends Applet{
String text = "I'm a simple applet";
public void init() {
text = "I'm a simple applet";
setBackground(Color.cyan);
}
public void start() {
System.out.println("starting...");
}
public void stop() {
System.out.println("stopping...");
}
public void destroy() {
System.out.println("preparing to unload...");
}
public void paint(Graphics g){
System.out.println("Paint");
g.setColor(Color.blue);
g.drawRect(0, 0,
getSize().width 1,
getSize().height 1);
g.setColor(Color.red);
g.drawString(text, 15, 25);
}
}
The SimpleApplet class is declared public so the program that runs
the applet (a browser or appletviewer), which is not local to the
program can access it.
To see the applet in action, you need an HTML file with the Applet tag
as follows:
<HTML>
<BODY>
<APPLET CODE=SimpleApplet.class WIDTH=200 HEIGHT=100>
</APPLET>
</BODY>
</HTML>
The easiest way to run the applet is with appletviewer shown below
where simpleApplet.html is a file that contains the above HTML
code:
appletviewer simpleApplet.html
The Java API Applet class provides what you need to design the
appearance and manage the behavior of an applet. This class provides
a graphical user interface (GUI) component called a Panel and a
number of methods. To create an applet, you extend (or subclass) the
Applet class and implement the appearance and behavior you want.
Extending a Class
The Applet class provides the init, start, stop, destroy, and paint
methods you saw in the example applet. The SimpleApplet class
overrides these methods to do what the SimpleApplet class needs
them to do. The Applet class provides no functionality for these
methods.
You might wonder why the Java language provides methods without
implementations. It is to provide conventions for everyone to use for
consistency across Java APIs. If everyone wrote their own method to
start an applet, for example, but gave it a different name such as
begin or go, the applet code would not be interoperable with other
programs and browsers, or portable across multiple platforms. For
example, Netscape and Internet Explorer know how to look for the
init and start methods.
Behavior
After the start method executes, the event thread calls the paint
method to draw to the applet's Panel. A thread is a single sequential
flow of control within the applet, and every applet can run in multiple
threads. Applet drawing methods are always called from a dedicated
drawing and event-handling thread.
The destroy method is called when the browser exits. Your applet
should implement this method to do final cleanup such as stop live
threads.
Appearance
The Panel provided in the Applet class inherits a paint method from
its parent Container class. To draw something onto the Applet's
Panel, you implement the paint method to do the drawing.
The paint method for the SimpleApplet draws the I'm a simple
applet string in red inside a blue rectangle.
public void paint(Graphics g){
System.out.println("Paint");
//Set drawing color to blue
g.setColor(Color.blue);
//Specify the x, y, width and height for a rectangle
g.drawRect(0, 0,
getSize().width 1,
getSize().height 1);
//Set drawing color to red
g.setColor(Color.red);
//Draw the text string at the (15, 25) xy location
g.drawString(text, 15, 25);
}
Packages
The applet code also has three import statements at the top.
Applications of any size and all applets use import statements to
access ready-made Java API classes in packages. This is true whether
the Java API classes come in the Java platform download, from a third-
party, or are classes you write yourself and store in a directory
separate from the program. At compile time, a program uses import
statements to locate and reference compiled Java API classes stored in
packages elsewhere on the local or networked system. A compiled
class in one package can have the same name as a compiled class in
another package. The package name differentiates the two classes.
You can find more information on applets in the Writing Applets trail in
The Java Tutorial.
In the last lesson you saw how the Applet class provides a Panel
component so you can design the applet's user interface. This lesson
expands the basic application from Lessons 1 and 2 to give it a user
interface using the Java Foundation Classes (JFC) Project Swing APIs
TM
Import Statements
Class Declaration
Instance Variables
Constructor
Action Listening
Event Handling
Main Method
Applets Revisited
More Information
The Project Swing code that follows builds this simple application. The
window on the left appears when you start the application, and the
window on the right appears when you click the button. Click again
and you are back to the original window on the left.
Import Statements
Here is the SwingUI.java code. At the top, you have four lines of
import statements. The lines indicate exactly which Java API classes
TM
the program uses. You could replace four of these lines with this one
line: import java.awt.*;, to import the entire awt package, but
doing that increases compilation overhead than importing exactly the
classes you need and no others.
import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
Class Declaration
The class declaration comes next and indicates the top-level frame for
the application's user interface is a JFrame that implements the
ActionListener interface.
class SwingUI extends JFrame
implements ActionListener{
The JFrame class extends the Frame class that is part of the Abstract
Window Toolkit (AWT) APIs. Project Swing extends the AWT with a full
set of GUI components and services, pluggable look and feel
capabilities, and assistive technology support. For a more detailed
introduction to Project Swing, see the Swing Connection, and
Fundamentals of Swing, Part 1.
The Java APIs provide classes and interfaces for you to use. An
interface defines a set of methods, but does not implement them. The
rest of the SwingUI class declaration indicates that this class will
implement the ActionListener interface. This means the SwingUI
class must implement all methods defined in the ActionListener
interface. Fortunately, there is only one, actionPerformed, which is
discussed below.
Instance Variables
These next lines declare the Project Swing component classes the
SwingUI class uses. These are instance variables that can be accessed
by any method in the instantiated class. In this example, they are built
in the SwingUI constructor and accessed in the actionPerformed
method implementation. The private boolean instance variable is
visible only to the SwingUI class and is used in the
actionPerformedmethod to find out whether or not the button has
been clicked.
JLabel text, clicked;
JButton button, clickButton;
JPanel panel;
private boolean _clickMeMode = true;
Constructor
button = new JButton("Click Me");
//Add button as an event listener
button.addActionListener(this);
clickButton = new JButton("Click Again");
//Add button as an event listener
clickButton.addActionListener(this);
//Create panel
panel = new JPanel();
//Specify layout manager and background color
panel.setLayout(new BorderLayout(1,1));
panel.setBackground(Color.white);
//Add label and button to panel
getContentPane().add(panel);
panel.add(BorderLayout.CENTER,
text);
panel.add(BorderLayout.SOUTH,
button);
}
The code uses the BorderLayout layout manager, which arranges user
interface components in the five areas shown at left. To add a
component, specify the area (north, south, east, west, or center).
//Create panel
panel = new JPanel();
//Specify layout manager and background color
panel.setLayout(new BorderLayout(1,1));
panel.setBackground(Color.white);
//Add label and button to panel
getContentPane().add(panel);
panel.add(BorderLayout.CENTER, text);
panel.add(BorderLayout.SOUTH, button);
}
To find out about some of the other available layout managers and
how to use them, see the JDC article Exploring the AWT Layout
Managers.
Action Listening
In addition to implementing the ActionListener interface, you have
to add the event listener to the JButton components. An action listener
is the SwingUI object because it implements the ActionListener
interface. In this example, when the end user clicks the button, the
underlying Java platform services pass the action (or event) to the
actionPerformed method. In your code, you implement the
actionPerformed method to take the appropriate action based on which
button is clicked..
button = new JButton("Click Me");
//Add button as an event listener
button.addActionListener(this);
Event Handling
Main Method
The main method creates the top-level frame, sets the title, and
includes code that lets the end user close the window using the frame
menu.
public static void main(String[] args){
//Create toplevel frame
SwingUI frame = new SwingUI();
frame.setTitle("Example");
//This code lets you close the window
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
frame.addWindowListener(l);
//This code lets you see the frame
frame.pack();
frame.setVisible(true);
}
}
The code for closing the window shows an easy way to add event
handling functionality to a program. If the event listener interface you
need provides more functionality than the program actually uses, use
an adapter class. The Java APIs provide adapter classes for all listener
interfaces with more than one method. This way, you can use the
adapter class instead of the listener interface and implement only the
methods you need. In the example, the WindowListener interface has
7 methods and this program needs only the windowClosing method so
it makes sense to use the WindowAdapter class instead.
This approach takes only a few lines of code, while implementing the
WindowListener interface would require 6 empty method
implementations. Be sure to add the WindowAdapter object to the
frame object so the frame object will listen for window events.
WindowListener l = new WindowAdapter() {
//The instantiation of object l is extended to
//include this code:
public void windowClosing(WindowEvent e){
System.exit(0);
}
};
frame.addWindowListener(l);
Applets Revisited
Using what you learned in Lesson 3: Building Applets and this lesson,
convert the example for this lesson into an applet. Give it a try before
looking at the solution.
More Information
For more information on Project Swing, see the Swing Connection, and
Fundamentals of Swing, Part 1.
Also see The JFC Project Swing Tutorial: A Guide to Constructing GUIs.
To find out about some of the other available layout managers and
how to use them, see the JDC article Exploring the AWT Layout
Managers.
Servlets are easy to write. All you need is the Java® 2 Platform
software, and JavaServer Web Development Kit (JWSDK). You can
TM
This lesson shows you how to create a very simple form that invokes a
basic servlet to process end user data entered on the form.
HTML Form
Servlet Backend
More Information
A browser accepts end user input through an HTML form. The simple
form used in this lesson has one text input field for the end user to
enter text and a Submit button. When the end user clicks the Submit
button, the simple servlet is invoked to process the end user input.
In this example, the
simple servlet returns
an HTML page that
displays the text
entered by the end
user.
HTML Form
The HTML form is embedded in this HTML file. The diagram shows how
the HTML page looks when it is opened in a browser.
Note: To run the example, you have to put the servlet and
HTML files in the correct directories for the Web server you
are using. For example, with Java WebServer 1.1.1, you
place the servlet in the ~/JavaWebServer1.1.1/servlets
and the HTML file in the
~/JavaWebServer1.1.1/public_html directory.
Servlet Backend
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ExampServlet extends HttpServlet {
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<title>Example</title>" +
"<body bgcolor=FFFFFF>");
out.println("<h2>Button Clicked</h2>");
String DATA = request.getParameter("DATA");
if(DATA != null){
out.println(DATA);
} else {
out.println("No text entered.");
}
out.println("<P>Return to
<A HREF="../simpleHTML.html">Form</A>");
out.close();
}
}
In short, POST requests are for sending any amount of data directly
over the connection without changing the URL, and GET requests are
for getting limited amounts of information appended to the URL. POST
requests cannot be bookmarked or emailed and do not change the
Uniform Resource Locators (URL) of the response. GET requests can be
bookmarked and emailed and add information to the URL of the
response.
The parameter list for the doPost method takes a request and a
response object. The browser sends a request to the servlet and the
servlet sends a response back to the browser.
The doPost method implementation accesses information in the
request object to find out who made the request, what form the
request data is in, and which HTTP headers were sent, and uses the
response object to create an HTML page in response to the browser's
request. The doPost method throws an IOException if there is an
input or output problem when it handles the request, and a
ServletException if the request could not be handled. These
exceptions are handled in the HttpServlet class.
Method Implementation
The first part of the doPost method uses the response object to create
an HTML page. It first sets the response content type to be text/html,
then gets a PrintWriter object for formatted text output.
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<title>Example</title>" +
"<body bgcolor=#FFFFFF>");
out.println("<h2>Button Clicked</h2>");
The next line uses the request object to get the data from the text
field on the form and store it in the DATA variable. The getparameter
method gets the named parameter, returns null if the parameter was
not set, and an empty string if the parameter was sent without a
value.
String DATA = request.getParameter("DATA");
The next part of the doPost method gets the data out of the DATA
parameter and passes it to the response object to add to the HTML
response page.
if(DATA != null){
out.println(DATA);
} else {
out.println("No text entered.");
}
The last part of the doPost method creates a link to take the end user
from the HTML response page back to the original form, and closes the
response.
out.println("<P>Return to
<A HREF="../simpleHTML.html">Form</A>");
out.close();
}
Note: To learn how to use the other methods available in
the HttpServlet, HttpServletRequest, and
HttpServletResponse classes, see The Java Tutorial trail
on Servlets.
More Information
You can find more information on servlets in the Servlets trail in The
Java Tutorial.
So far, you have learned how to retrieve and handle a short text string
entered from the keyboard into a simple graphical user interface
(GUI). But programs also retrieve, handle, and store data in files and
databases.
System Properties
File.separatorChar
Exception Handling
Restricting Applications
More Informattion
This section shows you how to read data from and write data to a file
on the local computer system. See The Java Tutorial trail on Reading
TM
//Instance variable for text field
JTextField textField;
FileIO(){
text = new JLabel("Text to save to file:");
clicked = new
JLabel("Text retrieved from file:");
button = new JButton("Click Me");
button.addActionListener(this);
clickButton = new JButton("Click Again");
clickButton.addActionListener(this);
//Text field instantiation
textField = new JTextField(20);
panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBackground(Color.white);
getContentPane().add(panel);
//Adjustments to layout to add text field
panel.add("North", text);
panel.add("Center", textField);
panel.add("South", button);
}
Method Changes
String outputFileName =
System.getProperty("user.home",
File.separatorChar + "home" +
File.separatorChar + "monicap") +
File.separatorChar + "text.txt";
File outputFile = new File(outputFileName);
FileOutputStream out = new
FileOutputStream(outputFile);
out.write(b);
out.close();
//Code to read from file
String inputFileName =
System.getProperty("user.home",
File.separatorChar + "home" +
File.separatorChar + "monicap") +
File.separatorChar + "text.txt";
File inputFile = new File(inputFileName);
FileInputStream in = new
FileInputStream(inputFile);
byte bt[] = new
byte[(int)inputFile.length()];
in.read(bt);
s = new String(bt);
in.close();
}catch(java.io.IOException e){
System.out.println("Cannot access text.txt");
}
//Clear text field
textField.setText("");
//Display text read from file
text.setText("Text retrieved from file:");
textField.setText(s);
button.setText("Click Again");
_clickMeMode = false;
} else {
//Save text to file
text.setText("Text to save to file:");
textField.setText("");
button.setText("Click Me");
_clickMeMode = true;
}
}
}
To write the end user text to a file, the text is retrieved from the
textField and converted to a byte array.
String text = textField.getText();
byte b[] = text.getBytes();
Next, a File object is created for the file to be written to and used to
create a FileOutputStream object.
String outputFileName =
System.getProperty("user.home",
File.separatorChar + "home" +
File.separatorChar + "monicap") +
File.separatorChar + "text.txt";
File outputFile = new File(outputFileName);
FileOutputStream out = new
FileOutputStream(outputFile);
Finally, the FileOutputStream object writes the byte array to the File
object and closes the output stream when the operation completes.
out.write(b);
out.close();
The code to open a file for reading is similar. To read text from a file, a
File object is created and used to create a FileInputStream object.
String inputFileName =
System.getProperty("user.home",
File.separatorChar + "home" +
File.separatorChar + "monicap") +
File.separatorChar + "text.txt";
File inputFile = new File(inputFileName);
FileInputStream out = new
FileInputStream(inputFile);
Next, a byte array is created the same size as the file into which the
file contents are read.
byte bt[] = new byte[(int)inputFile.length()];
in.read(bt);
Finally, the byte array is used to construct a String object, which is
used to create the text for the label component. The
FileInputStream is closed when the operation completes.
String s = new String(bt);
label.setText(s);
in.close();
System Properties
File.separatorChar
Exception Handling
In the example, the try and catch block catches and handles the
java.io.IOException checked exception. If a method does not catch
a checked exception, the method must specify that it can throw the
exception because an exception that can be thrown by a method is
really part of the method's public interface. Callers of the method must
know about the exceptions that a method can throw so they can take
appropriate actions.
public int aComputationMethod(int number1,
int number2)
throws IllegalValueException{
//Body of method
}
When you catch exceptions in your code, you should handle them in a
way that is friendly to your end users. The exception and error classes
have a toString method to print system error text and a
printStackTrace method to print a stack trace, which can be very
useful for debugging your application during development. But, it is
probably better to deploy the program with a more user-friendly
approach to handling errors.
You can provide your own application-specific error text to print to the
command line, or display a dialog box with application-specific error
text. Using application-specific error text that you provide will also
make it much easier to internationalize the application later on
because you will have access to the text.
For the example programs in this lesson, the error message for the file
input and output is handled with application-specific error text that
prints at the command line as follows:
//Do this during development
}catch(java.io.IOException e){
System.out.println(e.toString());
System.out.println(e.printStackTrace());
}
//But deploy it like this
}catch(java.io.IOException e){
System.out.println("Cannot access text.txt");
}
If you want to make your code even more user friendly, you could
separate the write and read operations and provide two try and catch
blocks. The error text for the read operation could be Cannot read
text.txt, and the error text for the write operation could be Cannot
write text.txt.
The file access code for the FileIOAppl.java code is equivalent to the
FileIO.java application, but shows how to use the APIs for handling
data in character streams instead of byte streams. You can use either
approach in applets or applications. In this lesson, the choice to handle
data in bytes streams in the application and in character streams in
the applet is purely random. In real-life programs, you would base the
decision on your specific application requirements.
public void actionPerformed(ActionEvent event){
Object source = event.getSource();
if(source == button){
//Variable to display text read from file
String s = null;
if(_clickMeMode){
try{
//Code to write to file
String text = textField.getText();
String outputFileName =
System.getProperty("user.home",
File.separatorChar + "home" +
File.separatorChar + "monicap") +
File.separatorChar + "text.txt";
File outputFile = new File(outputFileName);
FileWriter out = new
FileWriter(outputFile);
out.write(text);
out.close();
//Code to read from file
String inputFileName =
System.getProperty("user.home",
File.separatorChar + "home" +
File.separatorChar + "monicap") +
File.separatorChar + "text.txt";
File inputFile = new File(inputFileName);
FileReader in = new FileReader(inputFile);
char c[] = new
char[(char)inputFile.length()];
in.read(c);
s = new String(c);
in.close();
}catch(java.io.IOException e){
System.out.println("Cannot access text.txt");
}
//Clear text field
textField.setText("");
//Display text read from file
text.setText("Text retrieved from file:");
textField.setText(s);
button.setText("Click Again");
_clickMeMode = false;
} else {
//Save text to file
text.setText("Text to save to file:");
textField.setText("");
button.setText("Click Me");
_clickMeMode = true;
}
}
}
If you tried to run the applet example, you undoubtedly saw errors
when you clicked the Click Me button. This is because the Java 2
Platform security does not permit an applet to write to and read from
files without explicit permission.
Policy tool is a Java 2 Platform security tool for creating policy files.
The Java Tutorial trail on Controlling Applets explains how to use Policy
Tool in good detail. Here is the policy file you need to run the applet.
You can use Policy tool to create it or copy the text below into an
ASCII file.
grant {
permission java.util.PropertyPermission
"user.home", "read";
permission java.io.FilePermission
"${user.home}/text.txt", "read,write";
};
Assuming the policy file is named polfile and is in the same directory
with an HTML file named fileIO.html that contains the HTML to run
the FileIOAppl applet, you would run the application in appletviewer
like this:
appletviewer JDjava.security.policy=polfile fileIO.html
<APPLET CODE=FileIOAppl.class WIDTH=200 HEIGHT=100>
</APPLET>
</BODY>
</HTML>
Restricting Applications
You can use the default security manager and a policy file to restrict
the application's access as follows.
java Djava.security.manager
Djava.security.policy=apppolfile FileIO
Because the application runs within the security manager, which
disallows all access, the policy file needs two additional permissions.
One so the security manager can access the event queue and load the
user interface components, and another so the application does not
display the banner warning that its window was created by another
program (the security manager).
grant {
permission java.awt.AWTPermission
"accessEventQueue";
permission java.awt.AWTPermission
"showWindowWithoutWarningBanner";
permission java.util.PropertyPermission
"user.home", "read";
permission java.io.FilePermission
"${user.home}/text.txt", "read,write";
};
Although servlets are invoked from a browser, they are under the
security policy in force for the web server under which they run. When
file input and output code is added to ExampServlet.java from Lesson
5, FileIOServlet for this lesson executes without restriction under Java
WebServer 1.1.1.
TM
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class FileIOServlet extends HttpServlet {
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<title>Example<title>" +
"<body bgcolor=FFFFFF>");
out.println("<h2>Button Clicked</h2>");
String DATA = request.getParameter("DATA");
if(DATA != null){
out.println("<STRONG>Text from
form:</STRONG>");
out.println(DATA);
} else {
out.println("No text entered.");
}
try{
//Code to write to file
String outputFileName=
System.getProperty("user.home",
File.separatorChar + "home" +
File.separatorChar + "monicap") +
File.separatorChar + "text.txt";
File outputFile = new File(outputFileName);
FileWriter fout = new FileWriter(outputFile);
fout.write(DATA);
fout.close();
//Code to read from file
String inputFileName =
System.getProperty("user.home",
File.separatorChar + "home" +
File.separatorChar + "monicap") +
File.separatorChar + "text.txt";
File inputFile = new File(inputFileName);
FileReader fin = new
FileReader(inputFile);
char c[] = new
char[(char)inputFile.length()];
int i;
i = fin.read(c);
String s = new String(c);
out.println("<P>
<STRONG>Text from file:</STRONG>");
out.println(s);
fin.close();
}catch(java.io.IOException e){
System.out.println("Cannot access text.txt");
}
out.println("<P>Return to
<A HREF="../simpleHTML.html">Form</A>");
out.close();
}
}
Appending
So far the examples have shown you how to read in and write out
streams of data in their entirety. But often, you want to append data
to an existing file or read in only certain amounts. Using the
RandomAccessFile class, alter the FileIO.java class to append to the
file.
More Information
For more infomation on file input and output, see the Reading and
Writing trail in The Java Tutorial.
You can learn more about component sizing in The Java Tutorial
sections on Solving Common Layout Problems and Layout
Management.
Lesson 7: Database Access and Permissions
This lesson converts the application, applet, and servlet examples from
Lesson 6 to write to and read from a database using JDBC . JDBC is
TM
The code for this lesson is very similar to the code you saw in Lesson
6, but additional steps (beyond converting the file access code to
database access code) include setting up the environment, creating a
database table, and connecting to the database. Creating a database
table is a database administration task that is not part of your program
code. However, establishing a database connection and the resulting
database access are.
Database Setup
o Establishing a Connection
o JDBC Driver
More Information
Database Setup
You need access to a database if you want to run the examples in this
lesson. You can install a database on your machine or perhaps you
have access to a database at work. Either way, you need a database
driver and any relevant environment settings so your program can
load the driver and locate the database. The program will also need
database login information in the form of a user name and password.
Drivers either come with the database or are available from the Web.
If you install your own database, consult the documentation for the
driver for information on installation and any other environment
settings you need for your platform. If you are using a database at
work, consult your database administrator for this information.
To show you two ways to do it, the application example uses the jdbc
driver, the applet examples use the jdbc and jdbc.odbc drivers, and
the servlet example uses the jdbc.odbc driver. All examples connect
to an OracleOCI7.3.4 database.
This example converts the FileIO program from Lesson 6 to write data
to and read data from a database. The top window below appears
when you start the Dba application, and the window beneath it
appears when you click the Click Me button.
When you click the Click Me button, whatever is entered into the text
field is saved to the database. After that, the data is retrieved from the
database and displayed in the window shown on the bottom. If you
write data to the table more than once, everything written is read and
displayed in the window shown on the bottom, so you might have to
enlarge the window to see the entire list of table items.
private Connection c;
final static private String _driver =
"oracle.jdbc.driver.OracleDriver";
final static private String _url =
"jdbc:oracle:thin:username/password@(description=(
address_list=(address=(protocol=tcp)
(host=developer)(port=1521)))
(source_route=yes)(connect_data=(sid=jdcsid)))";
public void actionPerformed(ActionEvent event){
try{
//Load the driver
Class.forName(_driver);
//Establish database connection
c = DriverManager.getConnection(_url);
}catch (java.lang.ClassNotFoundException e){
System.out.println("Cannot find driver class");
System.exit(1);
}catch (java.sql.SQLException e){
System.out.println("Cannot get connection");
System.exit(1);
}
try{
//Code to write to database
String theText = textField.getText();
Statement stmt = c.createStatement();
String updateString = "INSERT INTO dba VALUES
('" + theText + "')";
int count = stmt.executeUpdate(updateString);
SQL commands are String objects, and therefore, follow the rules of
String construction where the string is enclosed in double quotes (" ")
and variable data is appended with a plus (+). The variable theText
has single and double quotes to tell the database the SQL string has
variable rather than literal data.
//Code to read from database
ResultSet results = stmt.executeQuery(
"SELECT TEXT FROM dba ");
while(results.next()){
String s = results.getString("TEXT");
displayText.append(s + "\n");
}
stmt.close();
} catch(java.sql.SQLException e){
System.out.println(e.toString());
}
//Display text read from database
panel.removeAll();
panel.add("North", clicked);
panel.add("Center", displayText);
panel.add("South", clickButton);
panel.validate();
panel.repaint();
}
However, if you run the applet without a policy file, you get a stack
trace indicating permission errors. The Granting Applets Permission
section in Lesson 6 introduced you to policy files and how to launch an
applet with the permission it needs. The Lesson 6 applet example
provided the policy file and told you how to launch the applet with it.
This lesson shows you how to read the stack trace to determine the
permissions you need in a policy file.
Both applets do the same operations to the same database table using
different drivers. Each applet has its own policy file with different
permission lists and has different requirements for locating the
database driver
JDBC Driver
The JDBC driver is used from a program written exclusively in the Java
language (Java program). It converts JDBC calls directly into the
protocol used by the DBMS. This type of driver is available from the
DBMS vendor and is usually packaged with the DBMS software.
<HTML>
<BODY>
<APPLET CODE=DbaAppl.class
WIDTH=200
HEIGHT=100>
</APPLET>
</BODY>
</HTML>
appletviewer DbaAppl.html
cannot find driver
This error means the DriverManager looked for the JDBC driver in the
directory where the applet HTML and class files are and could not find
it. To correct this error, copy the driver to the directory where the
applet files are, and if the driver is bundled in a zip file, unzip the zip
file so the applet can access the driver.
Once you have the driver in place, launch the applet again.
appletviewer DbaAppl.html
Reading a Stack Trace: Assuming the driver is locally available to
the applet, if the DbaAppl.java applet is launched without a policy file,
the following stack trace is generated when the end user clicks the
Click Me button.
java.security.AccessControlException: access denied
(java.net.SocketPermission developer resolve)
The first line in the above stack trace tells you access is denied. This
means this stack trace was generated because the applet tried to
access a system resource without the proper permission. The second
line means to correct this condition you need a SocketPermission that
gives the applet access to the machine (developer) where the
database is located.
You can use Policy tool to create the policy file you need, or you can
create it with an ASCII editor. Here is the policy file with the
permission indicated by the stack trace:
grant {
permission java.net.SocketPermission "developer",
"resolve";
"accessClassInPackage.sun.jdbc.odbc";
};
Run the applet again, this time with a policy file named DbaApplPol
that has the above permission in it:
appletviewer JDjava.security.policy=DbaApplPol
DbaAppl.html
You get a stack trace again, but this time it is a different error
condition.
java.security.AccessControlException: access denied
(java.net.SocketPermission
129.144.176.176:1521 connect,resolve)
Now you need a SocketPermission that allows access to the Internet
Protocol (IP) address and port on the developer machine where the
database is located.
Here is the DbaApplPol policy file with the permission indicated by the
stack trace added to it:
grant {
permission java.net.SocketPermission "developer",
"resolve";
permission java.net.SocketPermission
"129.144.176.176:1521", "connect,resolve";
};
Run the applet again. If you use the above policy file with the Socket
permissions indicated, it works just fine.
appletviewer JDjava.security.policy=DbaApplPol
DbaAppl.html
Start the Applet: Here is the DbaOdb.html file for running the
DbaOdbAppl applet:
<HTML>
<BODY>
<APPLET CODE=DbaOdbAppl.class
WIDTH=200
HEIGHT=100>
</APPLET>
</BODY>
</HTML>
And here is how to start the applet:
appletviewer DbaOdb.html
java.security.AccessControlException: access denied
(java.lang.RuntimePermission
accessClassInPackage.sun.jdbc.odbc )
The first line in the above stack trace tells you access is denied. This
means this stack trace was generated because the applet tried to
access a system resource without the proper permission. The second
line means you need a RuntimePermission that gives the applet
access to the sun.jdbc.odbc package. This package provides the
JDBC-ODBC bridge functionality to the Java1 virtual machine (VM).
You can use Policy tool to create the policy file you need, or you can
create it with an ASCII editor. Here is the policy file with the
permission indicated by the stack trace:
grant {
permission java.lang.RuntimePermission
"accessClassInPackage.sun.jdbc.odbc";
};
Run the applet again, this time with a policy file named DbaOdbPol
that has the above permission in it:
appletviewer JDjava.security.policy=DbaOdbPol
DbaOdb.html
You get a stack trace again, but this time it is a different error
condition.
java.security.AccessControlException:
access denied (java.lang.RuntimePermission
file.encoding read)
The stack trace means the applet needs read permission to the
encoded (binary) file. Here is the DbaOdbPol policy file with the
permission indicated by the stack trace added to it:
grant {
permission java.lang.RuntimePermission
"accessClassInPackage.sun.jdbc.odbc";
permission java.util.PropertyPermission
"file.encoding", "read";
};
Run the applet again. If you use the above policy file with the Runtime
and Property permissions indicated, it works just fine.
appletviewer JDjava.security.policy=DbaOdbPol
DbaOdb.html
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.net.*;
import java.io.*;
public class DbaServlet extends HttpServlet {
private Connection c;
final static private String _driver =
"sun.jdbc.odbc.JdbcOdbcDriver";
final static private String _user = "username";
final static private String _pass = "password";
final static private String
_url = "jdbc:odbc:jdc";
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<title>Example<title>" +
"<body bgcolor=FFFFFF>");
out.println("<h2>Button Clicked</h2>");
String DATA = request.getParameter("DATA");
if(DATA != null){
out.println("<STRONG>Text from
form:</STRONG>");
out.println(DATA);
} else {
out.println("No text entered.");
}
//Establish database connection
try{
Class.forName (_driver);
c = DriverManager.getConnection(_url,
_user,
_pass);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try{
//Code to write to database
Statement stmt = c.createStatement();
String updateString = "INSERT INTO dba " +
"VALUES ('" + DATA + "')";
int count = stmt.executeUpdate(updateString);
//Code to read from database
ResultSet results = stmt.executeQuery(
"SELECT TEXT FROM dba ");
while(results.next()){
String s = results.getString("TEXT");
out.println("<BR>
<STRONG>Text from database:</STRONG>");
out.println(s);
}
stmt.close();
}catch(java.sql.SQLException e){
System.out.println(e.toString());
}
out.println("<P>Return to
<A HREF="../dbaHTML.html">Form</A>");
out.close();
}
}
More Information
_______
1
As used on this web site, the terms "Java virtual machine" or "JVM"
mean a virtual machine for the Java platform.
interface (API) enables client and server communications over the net.
Typically, client programs send requests to a server program, and the
server program responds to those requests.
o Program Behavior
o File Summary
RemoteServer Class
Send Interface
RMIClient1 Class
RMIClient2 Class
More Information
This lesson converts the File Input and Output application from Lesson
6: File Access and Permissions to the RMI API.
Program Behavior
File Summary
RMIClient1.
java: Client
program that
calls the
sendData
method on the
RemoteServer server object.
Here is the command sequence for the Unix and Win32 platforms; an
explanation follows.
Unix:
cd /home/zelda/classes
javac Send.java
javac RemoteServer.java
javac RMIClient2.java
javac RMIClient1.java
rmic d . RemoteServer
cp RemoteServer*.class /home/zelda/public_html/classes
cp Send.class /home/zelda/public_html/classes
Win32:
cd \home\zelda\classes
javac Send.java
javac RemoteServer.java
javac RMIClient2.java
javac RMIClient1.java
rmic d . RemoteServer
copy RemoteServer*.class \home\zelda\public_html\classes
copy Send.class \home\zelda\public_html\classes
The first two javac commands compile the RemoteServer and Send
class and interface. The third javac command compiles the
RMIClient2 class. The last javac command compiles the RMIClient1
class.
The next line runs the rmic command on the RemoteServer server
class. This command produces output class files of the form
ClassName_Stub.class and ClassName_Skel.class. These output
classes let clients invoke methods on the RemoteServer server object.
The first copy command moves the RemoteServer class file with its
associated skel and stub class files to a publicly accessible location in
the /home/zelda/public_html/classes directory, which is on the
server machine, so they can be publicly accessed and downloaded.
They are placed in the public_html directory to be under the web
server running on the server machine because these files are accessed
by client programs using URLs.
The second copy command moves the Send class file to the same
location for the same reason. The RMIClient1 and RMIClient2 class
files are not made publicly accessible; they communicate from their
client machines using URLs to access and download the remote object
files in the public_html directory.
Before you start the RMI Registry, make sure the shell or window in
which you run the rmiregistry command does not have a CLASSPATH
environment variable that points to the remote object classes,
including the stub and skel classes, anywhere on your system. If the
RMI Registry finds these classes when it starts, it will not load them
from the server-side Java VM, which will create problems when clients
try to download the remote server classes.
The following commands unset the CLASSPATH and start the RMI
Registry on the default 1099 port. You can specify a different port by
adding the port number as follows: rmiregistry 4444 &. If you
specify a different port number, you must specify the same port
number in your server-side code as well.
Unix:
cd /home/zelda/public_html/classes
unsetenv CLASSPATH
rmiregistry &
Win32:
cd \home\zelda\public_html\classes
set CLASSPATH=
start rmiregistry
Unix:
cd /home/zelda/public_html/classes
java
Djava.rmi.server.codebase=http://kq6py/~zelda/classes
Djava.rmi.server.hostname=kq6py.eng.sun.com
Djava.security.policy=java.policy RemoteServer
Win32:
cd \home\zelda\public_html\classes
java Djava.rmi.server.codebase=file:
c:\home\zelda\public_html\classes
Djava.rmi.server.hostname=kq6py.eng.sun.com
Djava.security.policy=java.policy RemoteServer
Here is the command sequence for the Unix and Win32 platforms; an
explanation follows.
The lines beginning at java should be all on one line with spaces
where the lines break. Properties specified with the D option to the
java interpreter command are program attributes that manage the
behavior of the program for this invocation.
Unix:
cd /home/zelda/classes
java Djava.rmi.server.codebase=
http://kq6py/~zelda/classes/
Djava.security.policy=java.policy
RMIClient1 kq6py.eng.sun.com
Win32:
cd \home\zelda\classes
java Djava.rmi.server.codebase=
file:c:\home\zelda\classes\
Djava.security.policy=java.policy
RMIClient1 kq6py.eng.sun.com
Run RMIClient2
Here is the command sequence for the Unix and Win32 platforms; an
explanation follows.
The lines beginning at java should be all on one line with spaces
where the lines break. The properties specified with the D option to
the java interpreter command are program attributes that manage the
behavior of the program for this invocation.
Unix:
cd /home/zelda/classes
java Djava.rmi.server.codebase=
http://kq6py/~zelda/classes
Djava.security.policy=java.policy
RMIClient2 kq6py.eng.sun.com
Win32:
cd \home\zelda\classes
java Djava.rmi.server.codebase=
file:c:\home\zelda\public_html\classes
Djava.security.policy=java.policy
RMIClient2 kq6py.eng.sun.com
RemoteServer Class
class RemoteServer extends UnicastRemoteObject
implements Send {
String text;
public RemoteServer() throws RemoteException {
super();
}
public void sendData(String gotText){
text = gotText;
}
public String getData(){
return text;
}
The main method installs the RMISecurityManager and opens a
connection with a port on the machine where the server program runs.
The security manager determines whether there is a policy file that
lets downloaded code perform tasks that require permissions. The
main method creates a name for the the RemoteServer object that
includes the server name (kq6py) where the RMI Registry and remote
object run, and the name, Send.
By default the server name uses port 1099. If you want to use a
different port number, you can add it with a colon as follows:
kq6py:4444. If you change the port here, you must start the RMI
Registry with the same port number.
The try block creates an instance of the RemoteServer class and binds
the name to the remote object to the RMI Registry with the
Naming.rebind(name, remoteServer); statement.
public static void main(String[] args){
if(System.getSecurityManager() == null) {
System.setSecurityManager(new
RMISecurityManager());
}
String name = "//kq6py.eng.sun.com/Send";
try {
Send remoteServer = new RemoteServer();
Naming.rebind(name, remoteServer);
System.out.println("RemoteServer bound");
} catch (java.rmi.RemoteException e) {
System.out.println("Cannot create
remote server object");
} catch (java.net.MalformedURLException e) {
System.out.println("Cannot look up
server object");
}
}
}
public void sendData(String text)
throws RemoteException;
public String getData() throws RemoteException;
}
RMIClient1 Class
actionPerformed Method
if(source == button){
//Send data over socket
String text = textField.getText();
try{
send.sendData(text);
} catch (java.rmi.RemoteException e) {
System.out.println("Cannot send data to server");
}
textField.setText(new String(""));
}
}
main Method
if(System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
//args[0] contains name of server where Send runs
String name = "//" + args[0] + "/Send";
send = ((Send) Naming.lookup(name));
} catch (java.rmi.NotBoundException e) {
System.out.println("Cannot look up
remote server object");
} catch(java.rmi.RemoteException e){
System.out.println("Cannot look up
remote server object");
} catch(java.net.MalformedURLException e) {
System.out.println("Cannot look up
remote server object");
}
RMIClient2 Class
actionPerformed Method
if(source == button){
try{
String text = send.getData();
textArea.append(text);
} catch (java.rmi.RemoteException e) {
System.out.println("Cannot send data
to server");
}
}
}
}
main Method
RMIClient2 frame = new RMIClient2();
if(System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
String name = "//" + args[0] + "/Send";
send = ((Send) Naming.lookup(name));
} catch (java.rmi.NotBoundException e) {
System.out.println("Cannot look up remote
server object");
} catch(java.rmi.RemoteException e){
System.out.println("Cannot look up remote
server object");
} catch(java.net.MalformedURLException e) {
System.out.println("Cannot look up remote
server object");
}
More Information
You can find more information on the RMI API in the RMI trail of The
Java Tutorial.
In Closing
You can also explore programming in the Java language on your own
with the help of the articles, training materials, other documents
available on the Docs & Training page.