You are previewing Learning Java, 4th Edition.

Learning Java, 4th Edition

Cover of Learning Java, 4th Edition by Daniel Leuck... Published by O'Reilly Media, Inc.
  1. Learning Java
  2. Preface
    1. Who Should Read This Book
    2. New Developments
      1. New in This Edition (Java 6 and 7)
    3. Using This Book
    4. Online Resources
    5. Conventions Used in This Book
    6. Using Code Examples
    7. Safari® Books Online
    8. How to Contact Us
    9. Acknowledgments
  3. 1. A Modern Language
    1. Enter Java
      1. Java’s Origins
      2. Growing Up
    2. A Virtual Machine
    3. Java Compared with Other Languages
    4. Safety of Design
      1. Simplify, Simplify, Simplify...
      2. Type Safety and Method Binding
      3. Incremental Development
      4. Dynamic Memory Management
      5. Error Handling
      6. Threads
      7. Scalability
    5. Safety of Implementation
      1. The Verifier
      2. Class Loaders
      3. Security Managers
    6. Application and User-Level Security
    7. A Java Road Map
      1. The Past: Java 1.0–Java 1.6
      2. The Present: Java 7
      3. The Future
      4. Availability
  4. 2. A First Application
    1. Java Tools and Environment
    2. Configuring Eclipse and Creating a Project
      1. Importing the Learning Java Examples
    3. HelloJava
      1. Classes
      2. The main() Method
      3. Classes and Objects
      4. Variables and Class Types
      5. HelloComponent
      6. Inheritance
      7. The JComponent Class
      8. Relationships and Finger Pointing
      9. Package and Imports
      10. The paintComponent() Method
    4. HelloJava2: The Sequel
      1. Instance Variables
      2. Constructors
      3. Events
      4. The repaint() Method
      5. Interfaces
    5. HelloJava3: The Button Strikes!
      1. Method Overloading
      2. Components
      3. Containers
      4. Layout
      5. Subclassing and Subtypes
      6. More Events and Interfaces
      7. Color Commentary
      8. Static Members
      9. Arrays
      10. Our Color Methods
    6. HelloJava4: Netscape’s Revenge
      1. Threads
      2. The Thread Class
      3. The Runnable Interface
      4. Starting the Thread
      5. Running Code in the Thread
      6. Exceptions
      7. Synchronization
  5. 3. Tools of the Trade
    1. JDK Environment
    2. The Java VM
    3. Running Java Applications
      1. System Properties
    4. The Classpath
      1. javap
    5. The Java Compiler
    6. JAR Files
      1. File Compression
      2. The jar Utility
      3. The pack200 Utility
    7. Policy Files
      1. The Default Security Manager
      2. The policytool Utility
      3. Using a Policy File with the Default Security Manager
  6. 4. The Java Language
    1. Text Encoding
      1. Javadoc Comments
    3. Types
      1. Primitive Types
      2. Reference Types
      3. A Word About Strings
    4. Statements and Expressions
      1. Statements
      2. Expressions
    5. Exceptions
      1. Exceptions and Error Classes
      2. Exception Handling
      3. Bubbling Up
      4. Stack Traces
      5. Checked and Unchecked Exceptions
      6. Throwing Exceptions
      7. try Creep
      8. The finally Clause
      9. Try with Resources
      10. Performance Issues
    6. Assertions
      1. Enabling and Disabling Assertions
      2. Using Assertions
    7. Arrays
      1. Array Types
      2. Array Creation and Initialization
      3. Using Arrays
      4. Anonymous Arrays
      5. Multidimensional Arrays
      6. Inside Arrays
  7. 5. Objects in Java
    1. Classes
      1. Accessing Fields and Methods
      2. Static Members
    2. Methods
      1. Local Variables
      2. Shadowing
      3. Static Methods
      4. Initializing Local Variables
      5. Argument Passing and References
      6. Wrappers for Primitive Types
      7. Autoboxing and Unboxing of Primitives
      8. Variable-Length Argument Lists
      9. Method Overloading
    3. Object Creation
      1. Constructors
      2. Working with Overloaded Constructors
      3. Static and Nonstatic Initializer Blocks
    4. Object Destruction
      1. Garbage Collection
      2. Finalization
      3. Weak and Soft References
    5. Enumerations
      1. Enum Values
      2. Customizing Enumerations
  8. 6. Relationships Among Classes
    1. Subclassing and Inheritance
      1. Shadowed Variables
      2. Overriding Methods
      3. Special References: this and super
      4. Casting
      5. Using Superclass Constructors
      6. Full Disclosure: Constructors and Initialization
      7. Abstract Methods and Classes
    2. Interfaces
      1. Interfaces as Callbacks
      2. Interface Variables
      3. Subinterfaces
    3. Packages and Compilation Units
      1. Compilation Units
      2. Package Names
      3. Class Visibility
      4. Importing Classes
    4. Visibility of Variables and Methods
      1. Basic Access Modifiers
      2. Subclasses and Visibility
      3. Interfaces and Visibility
    5. Arrays and the Class Hierarchy
      1. ArrayStoreException
    6. Inner Classes
      1. Inner Classes as Adapters
      2. Inner Classes Within Methods
  9. 7. Working with Objects and Classes
    1. The Object Class
      1. Equality and Equivalence
      2. Hashcodes
      3. Cloning Objects
    2. The Class Class
    3. Reflection
      1. Modifiers and Security
      2. Accessing Fields
      3. Accessing Methods
      4. Accessing Constructors
      5. What About Arrays?
      6. Accessing Generic Type Information
      7. Accessing Annotation Data
      8. Dynamic Interface Adapters
      9. What Is Reflection Good For?
    4. Annotations
      1. Using Annotations
      2. Standard Annotations
      3. The apt Tool
  10. 8. Generics
    1. Containers: Building a Better Mousetrap
      1. Can Containers Be Fixed?
    2. Enter Generics
      1. Talking About Types
    3. “There Is No Spoon”
      1. Erasure
      2. Raw Types
    4. Parameterized Type Relationships
      1. Why Isn’t a List<Date> a List<Object>?
    5. Casts
    6. Writing Generic Classes
      1. The Type Variable
      2. Subclassing Generics
      3. Exceptions and Generics
      4. Parameter Type Limitations
    7. Bounds
      1. Erasure and Bounds (Working with Legacy Code)
    8. Wildcards
      1. A Supertype of All Instantiations
      2. Bounded Wildcards
      3. Thinking Outside the Container
      4. Lower Bounds
      5. Reading, Writing, and Arithmetic
      6. <?>, <Object>, and the Raw Type
      7. Wildcard Type Relationships
    9. Generic Methods
      1. Generic Methods Introduced
      2. Type Inference from Arguments
      3. Type Inference from Assignment Context
      4. Explicit Type Invocation
      5. Wildcard Capture
      6. Wildcard Types Versus Generic Methods
    10. Arrays of Parameterized Types
      1. Using Array Types
      2. What Good Are Arrays of Generic Types?
      3. Wildcards in Array Types
    11. Case Study: The Enum Class
    12. Case Study: The sort() Method
    13. Conclusion
  11. 9. Threads
    1. Introducing Threads
      1. The Thread Class and the Runnable Interface
      2. Controlling Threads
      3. Death of a Thread
    2. Threading an Applet
      1. Issues Lurking
    3. Synchronization
      1. Serializing Access to Methods
      2. Accessing class and instance Variables from Multiple Threads
      3. The wait() and notify() Methods
      4. Passing Messages
      5. ThreadLocal Objects
    4. Scheduling and Priority
      1. Thread State
      2. Time-Slicing
      3. Priorities
      4. Yielding
    5. Thread Groups
      1. Working with ThreadGroups
      2. Uncaught Exceptions
    6. Thread Performance
      1. The Cost of Synchronization
      2. Thread Resource Consumption
    7. Concurrency Utilities
      1. Executors
      2. Locks
      3. Synchronization Constructs
      4. Atomic Operations
    8. Conclusion
  12. 10. Working with Text
    1. Text-Related APIs
    2. Strings
      1. Constructing Strings
      2. Strings from Things
      3. Comparing Strings
      4. Searching
      5. Editing
      6. String Method Summary
      7. StringBuilder and StringBuffer
    3. Internationalization
      1. The java.util.Locale Class
      2. Resource Bundles
    4. Parsing and Formatting Text
      1. Parsing Primitive Numbers
      2. Tokenizing Text
    5. Printf-Style Formatting
      1. Formatter
      2. The Format String
      3. String Conversions
      4. Primitive and Numeric Conversions
      5. Flags
      6. Miscellaneous
    6. Formatting with the java.text Package
      1. MessageFormat
    7. Regular Expressions
      1. Regex Notation
      2. The java.util.regex API
  13. 11. Core Utilities
    1. Math Utilities
      1. The java.lang.Math Class
      2. Big/Precise Numbers
      3. Floating-Point Components
      4. Random Numbers
    2. Dates and Times
      1. Working with Calendars
      2. Time Zones
      3. Parsing and Formatting with DateFormat
      4. Printf-Style Date and Time Formatting
    3. Timers
    4. Collections
      1. The Collection Interface
      2. Iterator
      3. Collection Types
      4. The Map Interface
      5. Collection Implementations
      6. Hash Codes and Key Values
      7. Synchronized and Unsynchronized Collections
      8. Read-Only and Read-Mostly Collections
      9. WeakHashMap
      10. EnumSet and EnumMap
      11. Sorting Collections
      12. A Thrilling Example
    5. Properties
      1. Loading and Storing
      2. System Properties
    6. The Preferences API
      1. Preferences for Classes
      2. Preferences Storage
      3. Change Notification
    7. The Logging API
      1. Overview
      2. Logging Levels
      3. A Simple Example
      4. Logging Setup Properties
      5. The Logger
      6. Performance
    8. Observers and Observables
  14. 12. Input/Output Facilities
    1. Streams
      1. Basic I/O
      2. Character Streams
      3. Stream Wrappers
      4. Pipes
      5. Streams from Strings and Back
      6. Implementing a Filter Stream
    2. File I/O
      1. The Class
      2. File Streams
      3. RandomAccessFile
      4. Resource Paths
    3. The NIO File API
      1. FileSystem and Path
      2. NIO File Operations
      3. Directory Operations
      4. Watching Paths
    4. Serialization
      1. Initialization with readObject()
      2. SerialVersionUID
    5. Data Compression
      1. Archives and Compressed Data
      2. Decompressing Data
      3. Zip Archive As a Filesystem
    6. The NIO Package
      1. Asynchronous I/O
      2. Performance
      3. Mapped and Locked Files
      4. Channels
      5. Buffers
      6. Character Encoders and Decoders
      7. FileChannel
      8. Scalable I/O with NIO
  15. 13. Network Programming
    1. Sockets
      1. Clients and Servers
      2. author="pat” timestamp="20120926T110720-0500” comment="one of those sections I hate to get rid of but is less relevant in terms of the example... should probably find a more modern example...”The DateAtHost Client
      3. The TinyHttpd Server
      4. Socket Options
      5. Proxies and Firewalls
    2. Datagram Sockets
      1. author="pat” timestamp="20120926T141346-0500” comment="I actually rewrote this as a standalone client but then decided to leave it as an applet”The HeartBeat Applet
      2. InetAddress
    3. Simple Serialized Object Protocols
      1. A Simple Object-Based Server
    4. Remote Method Invocation
      1. Real-World Usage
      2. Remote and Nonremote Objects
      3. An RMI Example
      4. RMI and CORBA
    5. Scalable I/O with NIO
      1. Selectable Channels
      2. Using Select
      3. LargerHttpd
      4. Nonblocking Client-Side Operations
  16. 14. Programming for the Web
    1. Uniform Resource Locators (URLs)
    2. The URL Class
      1. Stream Data
      2. Getting the Content as an Object
      3. Managing Connections
      4. Handlers in Practice
      5. Useful Handler Frameworks
    3. Talking to Web Applications
      1. Using the GET Method
      2. Using the POST Method
      3. The HttpURLConnection
      4. SSL and Secure Web Communications
      5. URLs, URNs, and URIs
    4. Web Services
      1. XML-RPC
      2. WSDL
      3. The Tools
      4. The Weather Service Client
  17. 15. Web Applications and Web Services
    1. Web Application Technologies
      1. Page-Oriented Versus “Single Page” Applications
      2. JSPs
      3. XML and XSL
      4. Web Application Frameworks
      5. Google Web Toolkit
      6. HTML5, AJAX, and More...
    2. Java Web Applications
      1. The Servlet Lifecycle
      2. Servlets
      3. The HelloClient Servlet
      4. The Servlet Response
      5. Servlet Parameters
      6. The ShowParameters Servlet
      7. User Session Management
      8. The ShowSession Servlet
      9. The ShoppingCart Servlet
      10. Cookies
      11. The ServletContext API
      12. Asynchronous Servlets
    3. WAR Files and Deployment
      1. Configuration with web.xml and Annotations
      2. URL Pattern Mappings
      3. Deploying HelloClient
      4. Error and Index Pages
      5. Security and Authentication
      6. Protecting Resources with Roles
      7. Secure Data Transport
      8. Authenticating Users
      9. Procedural Authorization
    4. Servlet Filters
      1. A Simple Filter
      2. A Test Servlet
      3. Declaring and Mapping Filters
      4. Filtering the Servlet Request
      5. Filtering the Servlet Response
    5. Building WAR Files with Ant
      1. A Development-Oriented Directory Layout
      2. Deploying and Redeploying WARs with Ant
    6. Implementing Web Services
      1. Defining the Service
      2. Our Echo Service
      3. Using the Service
      4. Data Types
    7. Conclusion
  18. 16. Swing
    1. Components
      1. Peers and Look-and-Feel
      2. The MVC Framework
      3. Painting
      4. Enabling and Disabling Components
      5. Focus, Please
      6. Other Component Methods
      7. Layout Managers
      8. Insets
      9. Z-Ordering (Stacking Components)
      10. The revalidate() and doLayout() Methods
      11. Managing Components
      12. Listening for Components
      13. Windows, Frames and Splash Screens
      14. Other Methods for Controlling Frames
      15. Content Panes
      16. Desktop Integration
    2. Events
      1. Event Receivers and Listener Interfaces
      2. Event Sources
      3. Event Delivery
      4. Event Types
      5. The java.awt.event.InputEvent Class
      6. Mouse and Key Modifiers on InputEvents
      7. Focus Events
    3. Event Summary
      1. Adapter Classes
      2. Dummy Adapters
    4. The AWT Robot!
    5. Multithreading in Swing
  19. 17. Using Swing Components
    1. Buttons and Labels
      1. HTML Text in Buttons and Labels
    2. Checkboxes and Radio Buttons
    3. Lists and Combo Boxes
    4. The Spinner
    5. Borders
    6. Menus
    7. Pop-Up Menus
      1. Component-Managed Pop Ups
    8. The JScrollPane Class
    9. The JSplitPane Class
    10. The JTabbedPane Class
    11. Scrollbars and Sliders
    12. Dialogs
      1. File Selection Dialog
      2. The Color Chooser
  20. 18. More Swing Components
    1. Text Components
      1. The TextEntryBox Application
      2. Formatted Text
      3. Filtering Input
      4. Validating Data
      5. Say the Magic Word
      6. Sharing a Data Model
      7. HTML and RTF for Free
      8. Managing Text Yourself
    2. Focus Navigation
      1. Trees
      2. Nodes and Models
      3. Save a Tree
      4. Tree Events
      5. A Complete Example
    3. Tables
      1. A First Stab: Freeloading
      2. Round Two: Creating a Table Model
      3. Round Three: A Simple Spreadsheet
      4. Sorting and Filtering
      5. Printing JTables
    4. Desktops
    5. Pluggable Look-and-Feel
    6. Creating Custom Components
      1. Generating Events
      2. A Dial Component
      3. Model and View Separation
  21. 19. Layout Managers
    1. FlowLayout
    2. GridLayout
    3. BorderLayout
    4. BoxLayout
    5. CardLayout
    6. GridBagLayout
      1. The GridBagConstraints Class
      2. Grid Coordinates
      3. The fill Constraint
      4. Spanning Rows and Columns
      5. Weighting
      6. Anchoring
      7. Padding and Insets
      8. Relative Positioning
      9. Composite Layouts
    7. Other Layout Managers
    8. Absolute Positioning
  22. 20. Drawing with the 2D API
    1. The Big Picture
    2. The Rendering Pipeline
    3. A Quick Tour of Java 2D
      1. Filling Shapes
      2. Drawing Shape Outlines
      3. Convenience Methods
      4. Drawing Text
      5. Drawing Images
      6. The Whole Iguana
    4. Filling Shapes
      1. Solid Colors
      2. Color Gradients
      3. Textures
      4. Desktop Colors
    5. Stroking Shape Outlines
    6. Using Fonts
      1. Font Metrics
    7. Displaying Images
      1. The Image Class
      2. Image Observers
      3. Scaling and Size
    8. Drawing Techniques
      1. Double Buffering
      2. Limiting Drawing with Clipping
      3. Offscreen Drawing
    9. Printing
  23. 21. Working with Images and Other Media
    1. Loading Images
      1. ImageObserver
      2. MediaTracker
      3. ImageIcon
      4. ImageIO
    2. Producing Image Data
      1. Drawing Animations
      2. BufferedImage Anatomy
      3. Color Models
      4. Creating an Image
      5. Updating a BufferedImage
    3. Filtering Image Data
      1. How ImageProcessor Works
      2. Converting an Image to a BufferedImage
      3. Using the RescaleOp Class
      4. Using the AffineTransformOp Class
    4. Saving Image Data
    5. Simple Audio
    6. Java Media Framework
  24. 22. JavaBeans
    1. What’s a Bean?
      1. What Constitutes a Bean?
    2. The NetBeans IDE
      1. Installing and Running NetBeans
    3. Properties and Customizers
    4. Event Hookups and Adapters
      1. Taming the Juggler
      2. Molecular Motion
    5. Binding Properties
      1. Constraining Properties
    6. Building Beans
      1. The Dial Bean
      2. Design Patterns for Properties
    7. Limitations of Visual Design
    8. Serialization Versus Code Generation
    9. Customizing with BeanInfo
      1. Getting Properties Information
    10. Handcoding with Beans
      1. Bean Instantiation and Type Management
      2. Working with Serialized Beans
      3. Runtime Event Hookups with Reflection
    11. BeanContext and BeanContextServices
    12. The Java Activation Framework
    13. Enterprise JavaBeans and POJO-Based Enterprise Frameworks
  25. 23. Applets
    1. The Politics of Browser-Based Applications
    2. Applet Support and the Java Plug-in
    3. The JApplet Class
      1. Applet Lifecycle
      2. The Applet Security Sandbox
      3. Getting Applet Resources
      4. The <applet> Tag
      5. Attributes
      6. Parameters
      7. ¿Habla Applet?
      8. The Complete <applet> Tag
      9. Loading Class Files
      10. Packages
      11. appletviewer
    4. Java Web Start
    5. Conclusion
  26. 24. XML
    1. The Butler Did It
    2. A Bit of Background
      1. Text Versus Binary
      2. A Universal Parser
      3. The State of XML
      4. The XML APIs
      5. XML and Web Browsers
    3. XML Basics
      1. Attributes
      2. XML Documents
      3. Encoding
      4. Namespaces
      5. Validation
      6. HTML to XHTML
    4. SAX
      1. The SAX API
      2. Building a Model Using SAX
      3. XMLEncoder/Decoder
    5. DOM
      1. The DOM API
      2. Test-Driving DOM
      3. Generating XML with DOM
      4. JDOM
    6. XPath
      1. Nodes
      2. Predicates
      3. Functions
      4. The XPath API
      5. XMLGrep
    7. XInclude
      1. Enabling XInclude
    8. Validating Documents
      1. Using Document Validation
      2. DTDs
      3. XML Schema
      4. The Validation API
    9. JAXB Code Binding and Generation
      1. Annotating Our Model
      2. Generating a Java Model from an XML Schema
      3. Generating an XML Schema from a Java Model
    10. Transforming Documents with XSL/XSLT
      1. XSL Basics
      2. Transforming the Zoo Inventory
      3. XSLTransform
      4. XSL in the Browser
    11. Web Services
    12. The End of the Book
  27. A. The Eclipse IDE
    1. The IDE Wars
    2. Getting Started with Eclipse
      1. Importing the Learning Java Examples
    3. Using Eclipse
      1. Getting at the Source
      2. The Lay of the Land
      3. Running the Examples
      4. Building the Ant-Based Examples
      5. Loner Examples
    4. Eclipse Features
      1. Coding Shortcuts
      2. Autocorrection
      3. Refactoring
      4. Diffing Files
      5. Organizing Imports
      6. Formatting Source Code
    5. Conclusion
  28. B. BeanShell: Java Scripting
    1. Running BeanShell
    2. Java Statements and Expressions
      1. Imports
    3. BeanShell Commands
    4. Scripted Methods and Objects
      1. Scripting Interfaces and Adapters
    5. Changing the Classpath
    6. Learning More . . .
  29. Glossary
  30. Index
  31. About the Authors
  32. Colophon
  33. Copyright
O'Reilly logo

Java Web Applications

So far we’ve used the term web application generically, referring to any kind of browser-based application that is located on a web server. Now we are going to be more precise with that term. In the context of the Java Servlet API, a web application is a collection of servlets and Java web services that support Java classes, content such as HTML or JSP pages and images, and configuration information. For deployment (installation on a web server), a web application is bundled into a WAR file. We’ll discuss WAR files in detail later, but suffice it to say that they are really just JAR archives that contain all the application files along with some deployment information. The important thing is that the standardization of WAR files means not only that the Java code is portable, but also that the process of deploying the application to a server is standardized.

Most WAR archives have at their core a web.xml file. This is an XML configuration file that describes which servlets are to be deployed, their names and URL paths, their initialization parameters, and a host of other information, including security and authentication requirements. In recent years, however, the web.xml file has become optional for many applications due to the introduction of Java annotations that take the place of the XML configuration. In most cases, you can now deploy your servlets and Java web services simply by annotating the classes with the necessary information and packaging them into the WAR file, or using a combination of the two. We’ll discuss this in detail later in the chapter.

Web applications, or web apps, also have a well-defined runtime environment. Each web app has its own “root” path on the web server, meaning that all the URLs addressing its servlets and files start with a common unique prefix (e.g., The web app’s servlets are also isolated from those of other web applications. Web apps cannot directly access each other’s files (although they may be allowed to do so through the web server, of course). Each web app also has its own servlet context. We’ll discuss the servlet context in more detail, but in brief, it is a common area for servlets within an application to share information and get resources from the environment. The high degree of isolation between web applications is intended to support the dynamic deployment and updating of applications required by modern business systems and to address security and reliability concerns. Web apps are intended to be coarse-grained, relatively complete applications—not to be tightly coupled with other web apps. Although there’s no reason you can’t make web apps cooperate at a high level, for sharing logic across applications you might want to consider web services, which we’ll discuss later in this chapter.

The Servlet Lifecycle

Let’s jump now to the Servlet API and get started building servlets. We’ll fill in the gaps later when we discuss various parts of the APIs and WAR file structure in more detail. The Servlet API is very simple (reminiscent of the old Applet API). The base Servlet class has three lifecycle methods—init(), service(), and destroy()—along with some methods for getting configuration parameters and servlet resources. However, these methods are not often used directly by developers. Generally developers will implement the doGet() and doPost() methods of the HttpServlet subclass and access shared resources through the servlet context, as we’ll discuss shortly.

Generally, only one instance of each deployed servlet class is instantiated per container. More precisely, it is one instance per servlet entry in the web.xml file, but we’ll talk more about servlet deployment later. In the past, there was an exception to that rule when using the special SingleThreadModel type of servlet. As of Servlet API 2.4, single-threaded servlets have been deprecated.

By default, servlets are expected to handle requests in a multithreaded way; that is, the servlet’s service methods may be invoked by many threads at the same time. This means that you should not store per-request or per-client data in instance variables of your servlet object. (Of course, you can store general data related to the servlet’s operation, as long as it does not change on a per-request basis.) Per-client state information can be stored in a client session object on the server or in a client-side cookie, which persists across client requests. We’ll talk about client state later as well.

The service() method of a servlet accepts two parameters: a servlet “request” object and a servlet “response” object. These provide tools for reading the client request and generating output; we’ll talk about them (or rather their HttpServlet versions) in detail in the examples.


The package of primary interest to us here is javax.servlet.http, which contains APIs specific to servlets that handle HTTP requests for web servers. In theory, you can write servlets for other protocols, but nobody really does that and we are going to discuss servlets as if all servlets were HTTP-related.

The primary tool provided by the javax.servlet.http package is the HttpServlet base class. This is an abstract servlet that provides some basic implementation details related to handling an HTTP request. In particular, it overrides the generic servlet service() request and breaks it out into several HTTP-related methods, including doGet(), doPost(), doPut(), and doDelete(). The default service() method examines the request to determine what kind it is and dispatches it to one of these methods, so you can override one or more of them to implement the specific protocol behavior you need.

doGet() and doPost() correspond to the standard HTTP GET and POST operations. GET is the standard request for retrieving a file or document at a specified URL. POST is the method by which a client sends an arbitrary amount of data to the server. HTML forms utilize POST to send data as do most web services.

To round these out, HttpServlet provides the doPut() and doDelete() methods. These methods correspond to a less widely used part of the HTTP protocol, which is meant to provide a way to upload and remove files or file-like entities. doPut() is supposed to be like POST but with slightly different semantics (a PUT is supposed to logically replace the item identified by the URL, whereas POST presents data to it); doDelete() would be its opposite.

HttpServlet also implements three other HTTP-related methods for you: doHead(), doTrace(), and doOptions(). You don’t normally need to override these methods. doHead() implements the HTTP HEAD request, which asks for the headers of a GET request without the body. HttpServlet implements this by default in the trivial way, by performing the GET method and then sending only the headers. You may wish to override doHead() with a more efficient implementation if you can provide one as an optimization. doTrace() and doOptions() implement other features of HTTP that allow for debugging and simple client/server capabilities negotiation. You shouldn’t normally need to override these.

Along with HttpServlet, javax.servlet.http also includes subclasses of the objects ServletRequest and ServletResponse, HttpServletRequest and HttpServletResponse. These subclasses provide, respectively, the input and output streams needed to read and write client data. They also provide the APIs for getting or setting HTTP header information and, as we’ll see, client session information. Rather than document these dryly, we’ll show them in the context of some examples. As usual, we’ll start with the simplest possible example.

The HelloClient Servlet

Here’s our servlet version of “Hello, World,” HelloClient:

public class HelloClient extends HttpServlet 
    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException 
        response.setContentType("text/html"); // must come first
        PrintWriter out = response.getWriter();
            "<html><head><title>Hello Client!</title></head><body>"
            + "<h1>Hello Client!</h1>"
            + "</body></html>" );

If you want to try this servlet right away, skip ahead to WAR Files and Deployment, where we walk through the process of deploying this servlet. Because we’ve included the WebServlet annotation in our class, this servlet does not need a web.xml file for deployment. All you have to do is bundle the class file into a particular folder within a WAR archive (a fancy ZIP file) and drop it into a directory monitored by the Tomcat server. For now, we’re going to focus on just the servlet example code itself, which is pretty simple in this case.

Let’s have a look at the example. HelloClient extends the base HttpServlet class and overrides the doGet() method to handle simple requests. In this case, we want to respond to any GET request by sending back a one-line HTML document that says “Hello Client!” First, we tell the container what kind of response we are going to generate, using the setContentType() method of the HttpServletResponse object. We specify the MIME type “text/html” for our HTML response. Then, we get the output stream using the getWriter() method and print the message to it. It is not necessary for us to explicitly close the stream. We’ll talk more about managing the output stream throughout this chapter.


The doGet() method of our example servlet declares that it can throw a ServletException. All of the service methods of the Servlet API may throw a ServletException to indicate that a request has failed. A ServletException can be constructed with a string message and an optional Throwable parameter that can carry any corresponding exception representing the root cause of the problem:

    throw new ServletException("utter failure", someException );

By default, the web server determines exactly what is shown to the user whenever a ServletException is thrown; often there is a “development mode” where the exception and its stack trace are displayed. Using the web.xml file, you can designate custom error pages. (See the section Error and Index Pages for details.)

Alternatively, a servlet may throw an UnavailableException, a subclass of ServletException, to indicate that it cannot handle requests. This exception can be thrown to indicate that the condition is permanent or that it should last for a specified period of seconds.

Content type

Before fetching the output stream and writing to it, we must specify the kind of output we are sending by calling the response parameter’s setContentType() method. In this case, we set the content type to text/html, which is the proper MIME type for an HTML document. In general, though, it’s possible for a servlet to generate any kind of data, including audio, video, or some other kind of text or binary document. If we were writing a generic FileServlet to serve files like a regular web server, we might inspect the filename extension and determine the MIME type from that or from direct inspection of the data. (This is a good use for the java.nio.file.Files probeConentType() method!) For writing binary data, you can use the getOutputStream() method to get an OutputStream as opposed to a Writer.

The content type is used in the Content-Type: header of the server’s HTTP response, which tells the client what to expect even before it starts reading the result. This allows your web browser to prompt you with the “Save File” dialog when you click on a ZIP archive or executable program. When the content-type string is used in its full form to specify the character encoding (for example, text/html; charset=ISO-8859-1), the information is also used by the servlet engine to set the character encoding of the PrintWriter output stream. As a result, you should always call the setContentType() method before fetching the writer with the getWriter() method. The character encoding can also be set separately via the servlet response setCharacterEncoding() method.

The Servlet Response

In addition to providing the output stream for writing content to the client, the HttpServletResponse object provides methods for controlling other aspects of the HTTP response, including headers, error result codes, redirects, and servlet container buffering.

HTTP headers are metadata name/value pairs sent with the response. You can add headers (standard or custom) to the response with the setHeader() and addHeader() methods (headers may have multiple values). There are also convenience methods for setting headers with integer and date values:

    response.setIntHeader("MagicNumber", 42);
    response.setDateHeader("CurrentTime", System.currentTimeMillis() );

When you write data to the client, the servlet container automatically sets the HTTP response code to a value of 200, which means OK. Using the sendError() method, you can generate other HTTP response codes. HttpServletResponse contains predefined constants for all of the standard codes. Here are a few common ones:


When you generate an error with sendError(), the response is over and you can’t write any actual content to the client. You can specify a short error message, however, which may be shown to the client. (See the section A Simple Filter.)

An HTTP redirect is a special kind of response that tells the client web browser to go to a different URL. Normally this happens quickly and without any interaction from the user. You can send a redirect with the sendRedirect() method:


While we’re talking about the response, we should say a few words about buffering. Most responses are buffered internally by the servlet container until the servlet service method has exited or a preset maximum size has been reached. This allows the container to set the HTTP content-length header automatically, telling the client how much data to expect. You can control the size of this buffer with the setBufferSize() method, specifying a size in bytes. You can even clear it and start over if no data has been written to the client. To clear the buffer, use isCommitted() to test whether any data has been set, then use resetBuffer() to dump the data if none has been sent. If you are sending a lot of data, you may wish to set the content length explicitly with the setContentLength() method.

Servlet Parameters

Our first example showed how to accept a basic request. Of course, to do anything really useful, we’ll need to get some information from the client. Fortunately, the servlet engine handles this for us, interpreting both GET and POST form-encoded data from the client and providing it to us through the simple getParameter() method of the servlet request.

GET, POST, and “extra path”

There are two common ways to pass information from your web browser to a servlet or CGI program. The most general is to “post” it, meaning that your client encodes the information and sends it as a stream to the program, which decodes it. Posting can be used to upload large amounts of form data or other data, including files. The other way to pass information is to somehow encode the information in the URL of your client’s request. The primary way to do this is to use GET-style encoding of parameters in the URL string. In this case, the web browser encodes the parameters and appends them to the end of the URL string. The server decodes them and passes them to the application.

As we described in Chapter 14, GET-style encoding takes the parameters and appends them to the URL in a name/value fashion, with the first parameter preceded by a question mark (?) and the rest separated by ampersands (&). The entire string is expected to be URL-encoded: any special characters (such as spaces, ?, and & in the string) are specially encoded.

Another way to pass data in the URL is called extra path. This simply means that when the server has located your servlet or CGI program as the target of a URL, it takes any remaining path components of the URL string and hands them over as an extra part of the URL. For example, consider these URLs:


Suppose the server maps the first URL to the servlet called MyServlet. When given the second URL, the server also invokes MyServlet, but considers /foo/bar to be “extra path” that can be retrieved through the servlet request getExtraPath() method. This technique is useful for making more human-readable and meaningful URL pathnames, especially for document-centric content.

Both GET and POST encoding can be used with HTML forms on the client by specifying get or post in the action attribute of the form tag. The browser handles the encoding; on the server side, the servlet engine handles the decoding.

The content type used by a client to post form data to a servlet is: “application/x-www-form-urlencoded.” The Servlet API automatically parses this kind of data and makes it available through the getParameter() method. However, if you do not call the getParameter() method, the data remains available, unparsed, in the input stream and can be read by the servlet directly.

GET or POST: Which one to use?

To users, the primary difference between GET and POST is that they can see the GET information in the encoded URL shown in their web browser. This can be useful because the user can cut and paste that URL (the result of a search, for example) and mail it to a friend or bookmark it for future reference. POST information is not visible to the user and ceases to exist after it’s sent to the server. This behavior goes along with the protocol’s intent that GET and POST are to have different semantics. By definition, the result of a GET operation is not supposed to have any side effects; that is, it’s not supposed to cause the server to perform any persistent operations (such as making a purchase in a shopping cart). In theory, that’s the job of POST. That’s why your web browser warns you about reposting form data again if you hit reload on a page that was the result of a form posting.

The extra path style would be useful for a servlet that retrieves files or handles a range of URLs in a human-readable way. Extra path information is often useful for URLs that the user must see or remember, because it looks like any other path.

The ShowParameters Servlet

Our first example didn’t do much. This next example prints the values of any parameters that were received. We’ll start by handling GET requests and then make some trivial modifications to handle POST as well. Here’s the code:

import javax.servlet.http.*;
import java.util.*;

public class ShowParameters extends HttpServlet
    public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws IOException
        showRequestParameters( request, response );

    void showRequestParameters(HttpServletRequest request,
        HttpServletResponse response)
        throws IOException
        PrintWriter out = response.getWriter();

          "<html><head><title>Show Parameters</title></head><body>"
          + "<h1>Parameters</h1><ul>");

        Map<String, String[]> params = request.getParameterMap();
        for ( String name : params.keySet() )
            String [] values = params.get( name );
            out.println("<li>"+ name +" = "+ Arrays.asList(values) );

        out.close(  );

As in the first example, we override the doGet() method. We delegate the request to a helper method that we’ve created, called showRequestParameters(), a method that enumerates the parameters using the request object’s getParameterMap() method, which returns a map of parameter name to values, and prints the names and values. Note that a parameter may have multiple values if it is repeated in the request from the client, hence the map contains String []. To make thing pretty, we listed each parameter in HTML with <li> tag.

As it stands, our servlet would respond to any URL that contains a GET request. Let’s round it out by adding our own form to the output and also accommodating POST method requests. To accept posts, we override the doPost() method. The implementation of doPost() could simply call our showRequestParameters() method, but we can make it simpler still. The API lets us treat GET and POST requests interchangeably because the servlet engine handles the decoding of request parameters. So we simply delegate the doPost() operation to doGet().

Add the following method to the example:

    public void doPost( HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException 
        doGet( request, response );

Now, let’s add an HTML form to the output. The form lets the user fill in some parameters and submit them to the servlet. Add this line to the showRequestParameters() method before the call to out.close():

    out.println("</ul><p><form method=\"POST\" action=\"" 
            + request.getRequestURI() + "\">"
      + "Field 1 <input name=\"Field 1\" size=20><br>"
      + "Field 2 <input name=\"Field 2\" size=20><br>"
      + "<br><input type=\"submit\" value=\"Submit\"></form>"

The form’s action attribute is the URL of our servlet so that our servlet will get the data back. We use the getRequestURI() method to get the location of our servlet. For the method attribute, we’ve specified a POST operation, but you can try changing the operation to GET to see both styles.

So far, we haven’t done anything terribly exciting. In the next example, we’ll add some power by introducing a user session to store client data between requests. But before we go on, we should mention a useful standard servlet, SnoopServlet, that is akin to our previous example.

User Session Management

One of the nicest features of the Servlet API is its simple mechanism for managing a user session. By a session, we mean that the servlet can maintain information over multiple pages and through multiple transactions as navigated by the user; this is also called maintaining state. Providing continuity through a series of web pages is important in many kinds of applications, such as handling a login process or tracking purchases in a shopping cart. In a sense, session data takes the place of instance data in your servlet object. It lets you store data between invocations of your service methods.

Session tracking is supported by the servlet container; you normally don’t have to worry about the details of how it’s accomplished. It’s done in one of two ways: using client-side cookies or URL rewriting. Client-side cookies are a standard HTTP mechanism for getting the client web browser to cooperate in storing state information for you. A cookie is basically just a name/value attribute that is issued by the server, stored on the client, and returned by the client whenever it is accessing a certain group of URLs on a specified server. Cookies can track a single session or multiple user visits.

URL rewriting appends session-tracking information to the URL, using GET-style encoding or extra path information. The term rewriting applies because the server rewrites the URL before it is seen by the client and absorbs the extra information before it is passed back to the servlet. In order to support URL rewriting, a servlet must take the extra step to encode any URLs it generates in content (e.g., HTML links that may return to the page) using a special method of the HttpServletResponse object. We’ll describe this later. You need to allow for URL rewriting by the server if you want your application to work with browsers that do not support cookies or have them disabled. Many sites simply choose not to work without cookies.

To the servlet programmer, state information is made available through an HttpSession object, which acts like a hashtable for storing any objects you would like to carry through the session. The objects stay on the server side; a special identifier is sent to the client through a cookie or URL rewriting. On the way back, the identifier is mapped to a session, and the session is associated with the servlet again.

The ShowSession Servlet

Here’s a simple servlet that shows how to store some string information to track a session:

    import javax.servlet.ServletException;
    import javax.servlet.http.*;
    import java.util.Enumeration;

    public class ShowSession extends HttpServlet {

        public void doPost(
            HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
            doGet( request, response );

        public void doGet(
            HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
            HttpSession session = request.getSession();
            boolean clear = request.getParameter("clear") != null;
            if ( clear )
            else {
                String name = request.getParameter("Name");
                String value = request.getParameter("Value");
                if ( name != null && value != null )
                    session.setAttribute( name, value );

            PrintWriter out = response.getWriter();
              "<html><head><title>Show Session</title></head><body>");

            if ( clear )
                out.println("<h1>Session Cleared:</h1>");
            else {
                out.println("<h1>In this session:</h1><ul>");
                Enumeration names = session.getAttributeNames();
                while ( names.hasMoreElements() ) {
                    String name = (String)names.nextElement();
                    out.println( "<li>"+name+" = " +session.getAttribute( 
                        name ) );

              "</ul><p><hr><h1>Add String</h1>"
              + "<form method=\"POST\" action=\""
              + request.getRequestURI() +"\">"
              + "Name: <input name=\"Name\" size=20><br>"
              + "Value: <input name=\"Value\" size=20><br>"
              + "<br><input type=\"submit\" value=\"Submit\">"
              + "<input type=\"submit\" name=\"clear\" value=\"Clear\"></form>"

When you invoke the servlet, you are presented with a form that prompts you to enter a name and a value. The value string is stored in a session object under the name provided. Each time the servlet is called, it outputs the list of all data items associated with the session. You will see the session grow as each item is added (in this case, until you restart your web browser or the server).

The basic mechanics are much like our ShowParameters servlet. Our doGet() method generates the form, which points back to our servlet via a POST method. We override doPost() to delegate back to our doGet() method, allowing it to handle everything. Once in doGet(), we attempt to fetch the user session object from the request object using getSession(). The HttpSession object supplied by the request functions like a hashtable. There is a setAttribute() method, which takes a string name and an Object argument, and a corresponding getAttribute() method. In our example, we use the getAttributeNames() method to enumerate the values currently stored in the session and to print them.

By default, getSession() creates a session if one does not exist. If you want to test for a session or explicitly control when one is created, you can call the overloaded version getSession(false), which does not automatically create a new session and returns null if there is no session. Alternately, you can check to see if a session was just created with the isNew() method. To clear a session immediately, we can use the invalidate() method. After calling invalidate() on a session, we are not allowed to access it again, so we set a flag in our example and show the “Session Cleared” message. Sessions may also become invalid on their own by timing out. You can control session timeout in the application server or through the web.xml file (via the “session-timeout” value of the “session config” section). It is possible, through an interface we’ll talk about later in this chapter, to find out when a session times out. In general, this appears to the application as either no session or a new session on the next request. User sessions are private to each web application and are not shared across applications.

We mentioned earlier that an extra step is required to support URL rewriting for web browsers that don’t support cookies. To do this, we must make sure that any URLs we generate in content are first passed through the HttpServletResponse encodeURL() method. This method takes a string URL and returns a modified string only if URL rewriting is necessary. Normally, when cookies are available, it returns the same string. In our previous example, we could have encoded the server form URL that was retrieved from getRequestURI() before passing it to the client if we wanted to allow for users without cookies.

The ShoppingCart Servlet

Now we build on the previous example to make a servlet that could be used as part of an online store. ShoppingCart lets users choose items and add them to their basket until checkout time. The page generated is not that pretty, but you can have your web designer guy clean that up with some CSS (smiley). Here we are just concentrating on the Servlet API:

    import javax.servlet.ServletException;
    import javax.servlet.http.*;
    import java.util.Enumeration;

    public class ShoppingCart extends HttpServlet
        String [] items = new String [] {
            "Chocolate Covered Crickets", "Raspberry Roaches",
            "Buttery Butterflies", "Chicken Flavored Chicklets(tm)" };

        public void doPost(
            HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException
            doGet( request, response );

        public void doGet(
            HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
            PrintWriter out = response.getWriter();

            // get or create the session information
            HttpSession session = request.getSession();
            int [] purchases = (int [])session.getAttribute("purchases");
            if ( purchases == null ) {
                purchases = new int [ items.length ];
                session.setAttribute( "purchases", purchases );

            out.println( "<html><head><title>Shopping Cart</title>"
                         + "</title></head><body><p>" );

            if ( request.getParameter("checkout") != null )
                out.println("<h1>Thanks for ordering!</h1>");
            else  {
                if ( request.getParameter("add") != null ) {
                    addPurchases( request, purchases );
                        "<h1>Purchase added.  Please continue</h1>");
                } else {
                    if ( request.getParameter("clear") != null )
                        for (int i=0; i<purchases.length; i++)
                             purchases[i] = 0;
                    out.println("<h1>Please Select Your Items!</h1>");
                doForm( out, request.getRequestURI() );
            showPurchases( out, purchases );

        void addPurchases( HttpServletRequest request, int [] purchases ) {
            for (int i=0; i<items.length; i++) {
                String added = request.getParameter( items[i] );
                if ( added !=null && !added.equals("") )
                    purchases[i] += Integer.parseInt( added );

        void doForm( PrintWriter out, String requestURI ) {
            out.println( "<form method=POST action="+ requestURI +">" );

            for(int i=0; i< items.length; i++)
                out.println( "Quantity <input name=\"" + items[i]
                  + "\" value=0 size=3> of: " + items[i] + "<br>");
              "<p><input type=submit name=add value=\"Add To Cart\">"
              + "<input type=submit name=checkout value=\"Check Out\">"
              + "<input type=submit name=clear value=\"Clear Cart\">"
              + "</form>" );

        void showPurchases( PrintWriter out, int [] purchases )
            throws IOException {

            out.println("<hr><h2>Your Shopping Basket</h2>");
            for (int i=0; i<items.length; i++)
                if ( purchases[i] != 0 )
                    out.println( purchases[i] +"  "+ items[i] +"<br>" );

Note that ShoppingCart has some instance data: a String array that holds a list of products. We’re making the assumption that the product selection is the same for all customers. If it’s not, we’d have to generate the product list on the fly or put it in the session for the user. We cannot store any per-request or per-user data in instance variables.

We see the same basic pattern as in our previous servlets, with doPost() delegating to doGet(), and doGet() generating the body of the output and a form for gathering new data. We’ve broken down the work using a few helper methods: doForm(), addPurchases(), and showPurchases(). Our shopping cart form has three submit buttons: one for adding items to the cart, one for checkout, and one for clearing the cart. In each case, we display the contents of the cart. Depending on the button pressed (indicated by the name of the parameter), we add new purchases, clear the list, or show the results as a checkout window.

The form is generated by our doForm() method, using the list of items for sale. As in the other examples, we supply our servlet’s address as the target of the form. Next, we placed an integer array called purchases into the user session. Each element in purchases holds a count of the number of each item the user wants to buy. We create the array after retrieving the session simply by asking the session for it. If this is a new session, and the array hasn’t been created, getAttribute() gives us a null value and we create an empty array to populate. Because we generate the form using the names from the items array, it’s easy for addPurchases() to check for each name using getParameter() and increment the purchases array for the number of items requested. We also test for the value being equal to the empty string, because some web browsers send empty strings for unused field values. Finally, showPurchases() loops over the purchases array and prints the name and quantity for each item that the user has purchased.


In our previous examples, a session lived only until you shut down your web browser or the server. You can do more long-term user tracking or identification that lasts beyond a single browser session by managing cookies explicitly. You can send a cookie to the client by creating a javax.servlet.http.Cookie object and adding it to the servlet response using the addCookie() method. Later, you can retrieve the cookie information from the servlet request and use it to look up persistent information in a database. The following servlet sends a “Learning Java” cookie to your web browser and displays it when you return to the page:

import javax.servlet.*;
import javax.servlet.http.*;

public class CookieCutter extends HttpServlet
    public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws IOException, ServletException
        PrintWriter out = response.getWriter(  );

        if ( request.getParameter("setcookie") != null ) {
            Cookie cookie = new Cookie("Learningjava", "Cookies!");
            out.println("<html><body><h1>Cookie Set...</h1>");
        } else {
            Cookie[] cookies = request.getCookies(  );
            if ( cookies.length == 0 ) {
                out.println("<h1>No cookies found...</h1>");
            } else {
                for (int i = 0; i < cookies.length; i++)
                    out.print("<h1>Name: "+ cookies[i].getName() + "<br>"
                              + "Value: " + cookies[i].getValue() + "</h1>" );
            out.println("<p><a href=\""+ request.getRequestURI()
              +"Reset the Learning Java cookie.</a>");

This example simply enumerates the cookies supplied by the request object using the getCookies() method and prints their names and values. We provide a GET-style link that points back to our servlet with a parameter setcookie, indicating that we should set the cookie. In that case, we create a Cookie object using the specified name and value and add it to the response with the addCookie() method. We set the maximum age of the cookie to 3,600 seconds, so it remains in the browser for an hour before being discarded (we’ll talk about tracking a cookie across multiple sessions later). Specifying a negative time period indicates that the cookie should not be stored persistently and should be erased when the browser exits. A time period of 0 deletes any existing cookie immediately.

Two other Cookie methods are of interest: setDomain() and setPath(). These methods allow you to specify the domain name and path component that determines where the client will send the cookie. If you’re writing some kind of purchase applet for L.L. Bean, you don’t want clients sending your cookies over to Eddie Bauer. In practice, however, this cannot happen. The default domain is the domain of the server sending the cookie. (You cannot in general specify other domains for security reasons.) The path parameter defaults to the base URL of the servlet, but you can specify a wider (or narrower) range of URLs on the host server by manually setting this parameter.

The ServletContext API

Web applications have access to the server environment through the ServletContext API, a reference to which can be obtained from the HttpServlet getServletContext() method:

    ServletContext context = getServletContext();

Each web app has its own ServletContext. The context provides a shared space in which a web app’s servlets may rendezvous and share objects. Objects may be placed into the context with the setAttribute() method and retrieved by name with the getAttribute() method:

    context.setAttribute("myapp.statistics", myObject);
    Object stats = context.getAttribute("myapp.statistics");

Attribute names beginning with “java.” and “javax.” are reserved for use by Java. You can opt to use the standard package-naming conventions for your attributes to avoid conflicts.

The ServletContext provides a listener API that can be used to add items to the servlet context when the application server starts up and to tear them down when it shuts down. This is a good way to initiate shared services. We’ll show an example of this in the next section when we talk about asynchronous servlets.

One standard attribute that can be accessed through the servlet context is a reference to a private working directory represented by a object. This temp directory is guaranteed unique to the web app. No guarantees are made about it being cleared upon exit, however, so you should use the temporary file API to create files here (unless you wish to try to keep them beyond the server exit). For example:

    File tmpDir = (File)context.getAttribute("javax.servlet.context.tempdir");
    File tmpFile = File.createTempFile( "appprefix", "appsuffix", tmpDir );

The servlet context also provides direct access to the web app’s files from its root directory. The getResource() method is similar to the Class getResource() method (see Chapter 12). It takes a pathname and returns a special local URL for accessing that resource. In this case, it takes a path rooted in the servlet base directory (WAR file). The servlet may obtain references to files, including those in the WEB-INF directory, using this method. For example, a servlet could fetch an input stream for its own web.xml file:

    InputStream in = context.getResourceAsStream("/WEB-INF/web.xml");

It could also use a URL reference to get one of its images:

    URL bunnyURL = context.getResource("/images/happybunny.gif");

The method getResourcePaths() may be used to fetch a directory-style listing of all the resource files available matching a specified path. The return value is a java.util.Set collection of strings naming the resources available under the specified path. For example, the path / lists all files in the WAR; the path /WEB-INF/ lists at least the web.xml file and classes directory.

The ServletContext is also a factory for RequestDispatcher objects, which we won’t cover here, but which allow for servlets to forward to or include the results of other servlets in their responses.

Asynchronous Servlets

The following is a somewhat advanced topic, but we’ll cover it now to round out our discussion of the Servlet API. Servlets may run in an asynchronous mode, where the servlet service method is allowed to exit, but the response to the user is held open until it can be completed efficiently. While the response is held open, it does not actively consume resources or block threads in the servlet container. This is intended to support nonblocking, NIO-style services as discussed in Chapters 13 and 14.

Asynchronous servlets are an excellent way to handle very slow servlet processes, as long as there is a way to efficiently poll for or receive some truly asynchronous notification of their completion. As we discussed when talking about NIO, one of the limiting factors in the scalability of web services is thread consumption. Threads hold a lot of resources and so simply allowing them to block and wait for completion of a task is inefficient. As we saw earlier, NIO supports a style of programming where one thread can manage a large number of network connections. Asynchronous servlets allow servlets to participate in this model. The basic idea is that you pass a job to a background service and put the servlet request on the shelf until it can be completed. As long as the background processor is implemented in such a way that it can manage the jobs without waiting (via polling or receiving updates asynchronously), then there is no point where threads must block.

Later in this chapter, we’ll utilize a simple test servlet called WaitServlet that simply goes to sleep for a specified period of time before returning a result. This is a prime example of an inefficient use of threads. Our dumb WaitServlet blocks a thread (by sleeping) until it is “ready” to complete the transaction. In the following example, we’ll get ahead of ourselves a bit and create a more efficient version of this tool, BackgroundWaitServlet, that will not block any threads in the servlet container while it waits.

Before we start, let’s check our preconditions for whether an asynchronous servlet will be useful: do we have an efficient way to poll or receive notification when our “task” is complete without blocking a thread? (It’s important to ask this to avoid simply moving thread blocking from the servlet to another location.) Yes, in our case, we can use a timer to notify us when the time has passed. An efficient timer implementation like java.util.Timer will use only one thread to manage many timed requests. We’ll choose to use a ScheduledExecutorService from the java.util.concurrent package for this. It will execute any Runnable for us after a specified delay and makes a perfect shared background service for our asynchronous servlet.

The following example servlet returns a generic response after a delay of five seconds. The difference between this servlet and the naive one we use elsewhere in this chapter would become apparent if we flooded our server with requests. We should find that the asynchronous version would be limited primarily by TCP/IP resources in the host OS and not by more valuable memory on the server.

import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;
import java.util.concurrent.*;

    asyncSupported = true
public class BackgroundWaitServlet extends HttpServlet
    public void doGet( HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
        final AsyncContext asyncContext = request.startAsync();
        ScheduledExecutorService executor =
        executor.schedule( new RespondLaterJob( asyncContext ), 5,
            TimeUnit.SECONDS );

class RespondLaterJob implements Runnable
    private AsyncContext asyncContext;

    RespondLaterJob( AsyncContext asyncContext ) {
        this.asyncContext = asyncContext;

    public void run()
        try {
            ServletResponse response = asyncContext.getResponse();
            PrintWriter out = response.getWriter();
                "<html><body><h1>WaitServlet Response</h1></body></html>"
        } catch ( IOException e ) { throw new RuntimeException( e ); }


We’ve included the WebServlet annotation in this example in order to show the asyncSupported attribute. This attribute must be set on any servlets and servlet filters (discussed later) that will be involved in the request.

The implementation of our doGet() method is straightforward: we initiate the asynchronous behavior by calling the startAsync() method on the servlet request. That method returns to us an AsyncContext object that represents the caller context and includes the servlet request and response objects. At this point, we are free to arrange to service the request using any means we wish; the only requirement is that we must keep the AsyncContext object with our task so that it can be used later to send the results and close the transaction.

In our example, we look up our shared ScheduledExcecutorService from the servlet context by name (“BackgroundWaitExecutor”) and pass it a custom Runnable object. (We’ll talk about how the service got there in a bit.) We’ve created a RespondLaterJob that implements Runnable and holds onto the AsyncContext for later use. When the job runs in the future, we simply get the servlet response from the AsyncContext and send our response as usual. The final step is to call the complete() method on AsyncContext in order to close the call and return to the client.

The final step raises a couple of interesting issues: first, we do not necessarily have to call complete() immediately after writing to the response. Instead, we could write part of the result and go back to sleep, waiting for our service to wake us up when there is more data. Indeed, this is how we might work with an NIO data source. Second, instead of calling complete() to finalize the results for the client, we could use an alternate method, dispatch(), to forward the servlet request to another servlet, perhaps in a chain of servlets. The next servlet could write additional content or perhaps simply use resources put into the servlet context by the first servlet to handle the request. The dispatch() method accepts a URL string for the target servlet or, when called with no arguments, sends the request back to the original servlet.

OK, so how did our ScheduledExecutorService get into the servlet context? The best way to manage shared services and resources in the servlet context is via a ServletContextListener. A context listener has two lifecycle methods that can be used to set up and tear down services when the servlet container starts up and shuts down, respectively. We can deploy our listener simply by marking the class with a WebListener annotation and placing it in the WAR file as usual.

import javax.servlet.*;
import javax.servlet.annotation.*;
import java.util.concurrent.*;

public class BackgroundWaitService implements ServletContextListener
    ScheduledExecutorService executor;

    public void contextInitialized( ServletContextEvent sce )
        this.executor = Executors.newScheduledThreadPool( 3 );
        sce.getServletContext().setAttribute( "BackgroundWaitExecutor",
            executor );

    public void contextDestroyed(ServletContextEvent sce)
        ScheduledExecutorService executor =
            Executors.newScheduledThreadPool( 3 );

The best content for your career. Discover unlimited learning on demand for around $1/day.