Monday, December 15, 2014

Using the JdbcTemplate in Spring

Outline

  1. Why use the JDBC Template?
  2. Configure the JDBC Template
  3. Perform CRUD Operations with the JDBC Template
  4. Map Result Sets to Objects using RowMapper and ResultSetExtractor



Benefits of using the JDBC Template

  1. No connection management
  2. No exception handling required
    1. Exceptions are unchecked, which means you can catch them if you like, but you are not obligated to
    2. Checked vs Unchecked Exceptions
The JDBC Template is one of the core features of Spring's data access support. Using the JDBC support allows us to avoid try/catch block, support vfor iterating through result sets, mapping to sets, under trad JDBC approach.

Using JDBC Template doesn't have the auto-magicallity of a full JPA stack-implementation, but in my experience, what you lose in code in shifting to JPA, you typically pick up in configuration.  Use of the JDBC Template loses just enough of the boilerplate code, yet retains enough simplicity, that a developer accustomed to traditional JDBC development can pick it up quickly, and the slightly higher learning curve with JPA is avoided.



Proposed Architecture



Package Structure and Files:
  • src/
    • main/
      • java
        • com.mycompany.project
          • data
            • entities
              • Media.java
              • Rental.java
              • RentalLocation.java
            • repositories
              • RentalLocationRepository.java
              • RentalLocationRepositoryImpl.java
              • RentalLocationResultsExtractor.java
              • Repo.java
            • service
              • RentalService.java
      • resources
        • config
          • application-config.xml
    • test
      • java
        • com.mycompany.project
          • RentalLocationRepositoryTest
  • pom.xml



Configure the JDBC Template


src/main/resources/config/application-context.xml

 <?xml version="1.0" encoding="UTF-8"?>  
 <beans xmlns="http://www.springframework.org/schema/beans"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">  
   
      <context:component-scan base-package="com.mycompany.project.data" />  
   
      <bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource">  
           <property name="url" value="jdbc:mysql://localhost:3306/myschema" />  
           <property name="username" value="myuser" />  
           <property name="password" value="mypassword" />  
           <property name="driverClassName" value="com.mysql.jdbc.Driver" />  
      </bean>  
   
 </beans>  



Repository Interface

 public interface RentalLocationRepository extends Repo<RentalLocation> {   
      // add custom methods here   
 }   
   
 public interface Repo<T> {  
      void insert(T entity);  
      void update(T entity);  
      void delete(T entity);  
      T findById();  
 }  



Concrete Repository Implementation

 package com.mycompany.project.data.repositories;  
   
 import java.sql.Connection;  
 import java.sql.PreparedStatement;  
 import java.sql.ResultSet;  
 import java.sql.SQLException;  
 import java.sql.Statement;  
 import java.util.List;  
 ...  
   
 @Repository
 public class RentalLocationRepositoryImpl implements RentalLocationRepository {  
   
      private JdbcTemplate          template;  
   
      @Autowired  
      public RentalLocationRepositoryImpl(DataSource dataSource) {  
           this.template = new JdbcTemplate(dataSource);  
      }  
   
      ...  
 }  
   

Notice the basic design here.

In a jUnit test case, the RentalLocationRepositoryImpl is constructed like this:
 ApplicationContext context = new ClassPathXmlApplicationContext("config/application-context.xml");  
 assertNotNull(context);  
   
 DataSource dataSource = context.getBean("datasource", DataSource.class);  
 assertNotNull(dataSource);  
   
 RentalLocationRepositoryImpl repo = new RentalLocationRepositoryImpl(dataSource);  
 assertNotNull(repo);  

The Datasource is retrieved from the configured application-context and passed into the Repository class. That's it. Everything else is managed by Spring. No further annotation is needed

Perform CRUD Operations with the JDBC Template


Create

      @Override  
      public void insert(final RentalLocation entity) {  
           KeyHolder keyHolder = new GeneratedKeyHolder();  
           this.template.update(new PreparedStatementCreator() {  
   
                @Override  
                public PreparedStatement createPreparedStatement(Connection con) throws SQLException {  
                     PreparedStatement statement = con.prepareStatement(INSERT_STATEMENT, Statement.RETURN_GENERATED_KEYS);  
                     statement.setString(1, entity.getName());  
                     statement.setString(2, entity.getAddress1());  
                     statement.setString(3, entity.getAddress2());  
                     statement.setString(4, entity.getCity());  
                     statement.setString(5, entity.getState());  
                     statement.setString(6, entity.getPostalCode());  
                     return statement;  
                }  
   
           }, keyHolder);  
   
           entity.setRentalLocationId(keyHolder.getKey().intValue());  
      }  
   
      ...

      @Test  
      public void insert() throws Throwable {  
             
           ApplicationContext context = new ClassPathXmlApplicationContext("config/application-context.xml");  
           DataSource dataSource = context.getBean("datasource", DataSource.class);  
           RentalLocationRepositoryImpl repo = new RentalLocationRepositoryImpl(dataSource);  
   
           RentalLocation entity = dummy();  
           repo.insert(entity);  
           System.err.println("Auto Generated ID (retrieved by-reference): " + entity.getRentalLocationId());  
           assertNotNull(repo.findById(entity.getRentalLocationId()));  
   
           ((ConfigurableApplicationContext) context).registerShutdownHook();  
      }  

The insert statement is
 insert into rental_location (rental_location_id, name, address1, address2, city, state, postal_code) values (null, ?, ?, ?, ?, ?, ?)  

Read


 public RentalLocation findById(Integer id) {  
      try {  
           return this.template.queryForObject(FIND_BY_ID_QUERY, new Object[] { id }, new RentalLocationRowMapper());  
      } catch (EmptyResultDataAccessException e) {  
           return null;  
      }  
 }  
   
 public List<RentalLocation> findLocationsByState1(String state) {  
      return this.template.query(FIND_BY_STATE_QUERY_01, new Object[] { state }, new RentalLocationRowMapper());  
 }  
   
 public List<RentalLocation> findLocationsByState2(String state) {  
      return this.template.query(FIND_BY_STATE_QUERY_02, new Object[] { state }, new RentalLocationResultExtractor());  
 }  



Map Result Sets to Objects using RowMapper and ResultSetExtractor

Friday, December 12, 2014

Using Spring to Load Dictionaries from Local Resources

Introduction


Spring contains some useful design patterns for accessing local resources at runtime in a platform-independent manner.


Properties File


I debated initially whether the dictionary paths should be abstracted to a properties file. To do so without reason beyond "that's how it's always done" isn't sufficient. However, a maintenance justification may be found that any path changes will not require Spring bean changes, potentially eliminating the introduction of configuration errors.

Locations to the dictionary files are listed here:
 properties.adjectives.path          = dictionaries/adjectives.dat  
 properties.measurementWords.path    = dictionaries/measurement-words.dat  
 properties.nounPhrases.path         = dictionaries/noun-phrases.dat  
 properties.stopWords.path           = dictionaries/stop-words.dat  

I've added this properties file to this path:
commons-dict\src\main\resources\config\paths.properties
and the actual sources files (not listed here) exist at that location.


Dictionary Bean


 package org.swtk.common.dict.beans; 
 
 import java.util.Set;  
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.beans.factory.annotation.Value;  
 import org.springframework.context.annotation.Lazy;  
 import org.springframework.core.io.Resource;  
 import org.springframework.stereotype.Component;  
 import org.swtk.common.dict.DictionaryBase;  
 import org.swtk.common.env.LogManager;  

 @Lazy  
 @Component("nounPhrasesDictionary")  
 public class NounPhrasesDictionary extends DictionaryBase {  

      public static LogManager     logger     = new LogManager(NounPhrasesDictionary.class);  

      @Autowired  
      @Value("${properties.nounPhrases.path}")  
      private Resource               resource;  

      @Override  
      public Set<String> entries() {  
           return set(resource);  
      }  
 }  

Path:
commons-dict\src\main\java\org\swtk\common\dict\beans\NounPhrasesDictionary.java



Dictionary Base


All dictionary beans extend this base class:
 package org.swtk.common.dict;  
   
 import java.io.BufferedReader;  
 import java.io.IOException;  
 import java.io.InputStreamReader;  
 import java.util.Set;  
 import java.util.TreeSet;  
   
 import org.springframework.core.io.Resource;  
 import org.swtk.common.env.LogManager;  
   
 public abstract class DictionaryBase implements Dictionary {  
   
      public static LogManager     logger     = new LogManager(DictionaryBase.class);  
   
      private String     beanName;  
   
      public String getBeanName() {  
           return beanName;  
      }  
   
      public Set<String> set(Resource resource) {  
           Set<String> set = new TreeSet<String>();  
   
           try {  
   
                BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));  
                for (String line = reader.readLine(); line != null; line = reader.readLine())  
                     set.add(line);  
   
           } catch (IOException e) {  
                logger.error(e, "Failed to Load Dictionary (name = %s)", getBeanName());  
           }  
   
           return set;  
      }  
   
      @Override  
      public void setBeanName(String beanName) {  
           this.beanName = beanName;  
      }  
 }  
   



application-config.xml


 <?xml version="1.0" encoding="UTF-8"?>  

 <beans xmlns="http://www.springframework.org/schema/beans"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
      xmlns:jpa="http://www.springframework.org/schema/data/jpa"  
      xmlns:repository="http://www.springframework.org/schema/data/repository"  
      xmlns:tx="http://www.springframework.org/schema/tx"  
      xsi:schemaLocation="http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository-1.6.xsd  
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">  

      <context:component-scan base-package="org.swtk.common.dict.beans" />  
      <context:property-placeholder location="classpath:config/paths.properties" />  

 </beans>  

Path:
commons-dict\src\main\resources\config\application-context.xml



Container Access


If you have other projects in your workspace that are not Spring-enabled, you may find it useful to manage the application-context transparently.

I've encapsulated the context in a factory, and exposed each dictionary via an enum parameter:
 package org.swtk.common.dict;  

 import org.springframework.context.ApplicationContext;  
 import org.springframework.context.ConfigurableApplicationContext;  
 import org.springframework.context.support.ClassPathXmlApplicationContext;  
 import org.swtk.common.env.LogManager;  

 public class DictionaryContext {  

      private static DictionaryContext     instance;  

      public static LogManager               logger     = new LogManager(DictionaryContext.class);  

      public static DictionaryContext getInstance() {  
           if (null == instance) instance = new DictionaryContext();  
           return instance;  
      }  

      private ApplicationContext     context;  

      private DictionaryContext() {}  

      public void close() {  
           ((ConfigurableApplicationContext) getContext()).close();  
           setContext(null);  
      }  

      private ApplicationContext getContext() {  
           if (null == context) setContext(new ClassPathXmlApplicationContext("config/application-context.xml"));  
           return context;  
      }  

      public Dictionary getDictionary(DictionaryName dictionary) {  
           Dictionary dict = getContext().getBean(dictionary.toString(), Dictionary.class);  
           return dict;  
      }  

      private void setContext(ApplicationContext context) {  
           this.context = context;  
      }  
 }  



Dictionary Name Enum


Unfortunately, we are maintaining the beanId in two places now: this enum, and within the @Component annotation on each Spring Bean. This increases our maintenance burden slightly, but does make life easier for the consumer. Ultimately, I think this is worth it.

 package org.swtk.common.dict; 
 
 public enum DictionaryName {  

      ADJECTIVES("adjectivesDictionary"),  
      MEASUREMENT_WORDS("measurementWordsDictionary"),  
      NOUN_PHRASES("nounPhrasesDictionary"),  
      STOP_WORDS("stopWordsDictionary");  

      private String     beanId;  

      private DictionaryName(String beanId) {  
           setBeanId(beanId);  
      }  

      private String getBeanId() {  
           return beanId;  
      }  

      private void setBeanId(String beanId) {  
           this.beanId = beanId;  
      }  

      @Override  
      public String toString() {  
           return getBeanId();  
      }  
 }  



Test Client


The test client is simple, and the use of Spring transparent to the consumer:
 Dictionary dictionary = DictionaryContext.getInstance().getDictionary(DictionaryName.NOUN_PHRASES);  
 assertNotNull(dictionary.entries());  
 assertFalse(dictionary.entries().isEmpty());  

Wednesday, December 10, 2014

Introduction to Inversion of Control and Dependency Injection

Developers of software strive to reduce dependencies between components in software for various reasons.

This leads to a new problem:
How can a component know all the other components it needs to fulfill its purpose?

Dependency Injection (DI) is a technique that supplies external dependencies to a software component.

An alternative to DI is to hard-code dependencies:
 public class Requestor {  
   public void operation() {  
    DatabaseServiceImplementation dbs = new DatabaseServiceImplementation();  
    dbs.performOperation1();  
   }  
 }  


DI is a form of Inversion of Control (IoC) where the concern being inverted is the process of obtaining the needed dependency:
 public class Requestor {  
   public void operation() {  
    DatabaseServiceInterface dbs = beanFactory.getClass("databaseServices", DatabaseServiceInterface.class);  
    dbs.performOperation1();  
   }  
 }  


This line:
 beanFactory.getClass(“databaseServices”, DatabaseServiceInterface.class);  

returns an interface (or, specification) that contains operations (or, services) that are defined in DatabaseServiceInterface.java.

The name (or, key) used to retrieve this interface is contained in an XML file:
  <bean   
       id="databaseServices"   
       class="com.mycompany.test.ioc.DatabaseServiceImplementation" />   


This mapping tells Spring to instantiate and return an instance of “DatabaseServiceImplementation” whenever the class is called:
 beanFactory.getClass(“databaseServices”, <Class>)   


It is possible to cast “databaseServices” to its concrete implementation as well:
  DatabaseServiceInterface dibs = beanFactory.getClass(  
       "databaseServices",   
       Reimplementation);   

You can also write code like this:
  DatabaseServiceImplementation idbs = beanFactory.getClass(  
       "databaseServices",   
       DatabaseServiceImplementation.class);   

In this case we're using the concrete implementation to instantiate the class, and at first glance there would appear to be little benefit over using an interface. However, we still gain the value of injected dependencies being made available via this approach
In both cases, there is now a dependency to DatabaseServiceImplementation.

Scenarios 3 and 4 are identical to Scenario 1, in terms of introducing a dependency on DatabaseServiceImplementation to the Requestor.

No Interface; No Dependency Injection:

Scenarios 1,3, 4


Coding to an Interface with Dependency Injection:

Scenario 2


The term “Dependency Injection” refers to the container (in this case, Spring) injecting a dependency to a class (in this case, DatabaseServiceImplementation) into the requesting code:
 beanFactory.getBean(<id>, <class>)  

Spring injects a dependency to <id> into the Requestor.

Monday, December 8, 2014

Session Management

Stateful and Stateless


HTTP is stateless

Each request is treated as an independent transaction that is unrelated to any previous request.
Request attributes live on the request object. As soon as that request is gone, the attribute is gone.

Sessions are stateful


A session is a semi-permanent interactive information interchange, also known as a dialogue, between two or more communicating devices.

Should data be stored on the client side or server side?

You don't necessarily want to store data client side (in a cookie), because you don't want the client to manipulate that data. The solution is to store the data server side, and store the unique identifier to that data on the client. This becomes a stateful session.






References

  1. What are Sessions and how do they work?
    1. The user id is stored in the session data, server-side, after successful identification. Then for every HTTP request you get from the client, the session id (given by the client) will point you to the correct session data (stored by the server) that contains the authenticated user id.

Servlet Parameters

Request Parameters


A request parameter is a parameter passed to a servlet through a request. Request parameters are the result of submitting an HTTP request with a query string that specifies the name/value pairs, or of submitting an HTML form that specifies the name/value pairs. The name and the values are always strings.

The request attribute lives on the request object. As soon as that request is gone, the attribute is gone.

In the example below, we'll perform a POST using HTML and the data will be retrieved by using request.getParameter(). Parameters are Strings, and generally can be retrieved, but not set.

Servlet Definition


 package com.swtk.web.servlets;  

 import java.io.IOException;  
 import java.io.PrintWriter;  
 import javax.servlet.ServletException;  
 import javax.servlet.annotation.WebServlet;  
 import javax.servlet.http.HttpServlet;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse;  

 @WebServlet({ "/SurveyPost", "/post/survey.do" })  

 public class SurveyPost extends HttpServlet {  

      private static final long     serialVersionUID     = 1L;  

      public SurveyPost() {  
           super();  
      }  

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}  

      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
           PrintWriter out = response.getWriter();  
           out.print(request.getParameter("menuChoice"));  
           out.close();  
      }  
 }  
mapped to this location
"/post/survey.do"

HTML Form Definition


 <html>  
      <head>  
           <title>Insert title here</title>  
      </head>  
      <body>  
           <form id="form1" method="post" action="/HelloWorldServlet/post/survey.do">  
                <select id="menuChoice" name="menuChoice">  
                     <option id="1" value="CA">CA</option>  
                     <option id="2" value="OR">OR</option>  
                     <option id="3" value="AZ">AZ</option>  
                </select>  
                <input type="submit" />  
           </form>  
      </body>  
 </html>  
deployed to this location in my Web Project:
WebContent/PostExample1.html

Fiddler Output


When I run the HTML page on Tomcat, and hit submit, Fiddler will show this:
 POST http://localhost:8080/HelloWorldServlet/post/survey.do HTTP/1.1  
 Host: localhost:8080  
 Connection: keep-alive  
 Content-Length: 13  
 Cache-Control: max-age=0  
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8  
 Origin: http://localhost:8080  
 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36  
 Content-Type: application/x-www-form-urlencoded  
 Referer: http://localhost:8080/HelloWorldServlet/PostExample1.html  
 Accept-Encoding: gzip, deflate  
 Accept-Language: en-US,en;q=0.8,fr;q=0.6,nb;q=0.4  
 menuChoice=OR  


Web Output


The Web output shows the attribute value:




Servlet Context

Unlike the request context, the servlet context is at the application level. This is very powerful, but requires thread safety. Why is this named servlet context if this is application level? Servlet context is application level. When we do things in the container, it generally occurs in the servlet.


Initialization Parameters (init-params)




Global Parameters (context-param)

Friday, December 5, 2014

Servlet Redirecting and Dispatching

Response Redirect

When we need to move from one servlet to another, or from a servlet to a page, it's time to send the user somewhere else. The redirect is part of the servlet HTTP response object.


Create a "StartServlet"

 package com.swtk.web.servlets;  

 import java.io.IOException;  
 import javax.servlet.ServletException;  
 import javax.servlet.annotation.WebServlet;  
 import javax.servlet.http.HttpServlet;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse;  

 @WebServlet("/StartServlet")  

 public class StartServlet extends HttpServlet {  

      private static final long     serialVersionUID     = 1L;  

      public StartServlet() {  
           super();  
      }  

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
           response.sendRedirect("myservlets/Results.do");  
      }  

      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}  
 }  



Create a "ResultsServlet"

 package com.swtk.web.servlets;  

 import java.io.IOException;  
 import java.io.PrintWriter;  
 import javax.servlet.ServletException;  
 import javax.servlet.annotation.WebServlet;  
 import javax.servlet.http.HttpServlet;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse;  

 @WebServlet(
    description = "Simple Results Servlet", 
    urlPatterns = { 
       "/ResultsServlet", 
       "/myservlets/Results.do" 
    }
 )  

 public class ResultsServlet extends HttpServlet {  

      private static final long     serialVersionUID     = 1L;  

      public ResultsServlet() {  
           super();  
      }  

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
           response.setContentType("text/html");  
           PrintWriter out = response.getWriter();  
           out.println("Redirected!");  
           out.close();  
      }  

      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}  
 }  


Start on
http://localhost:8080/HelloWorldServlet/StartServlet
and automatically redirect to




The Request Dispatcher

Defines an object that receives requests from the client and sends them to any resource (such as a servlet, HTML file, or JSP file) on the server. The servlet container creates the RequestDispatcher object, which is used as a wrapper around a server resource located at a particular path or given by a particular name.


 package com.swtk.web.servlets;  

 import java.io.IOException;  
 import javax.servlet.RequestDispatcher;  
 import javax.servlet.ServletException;  
 import javax.servlet.annotation.WebServlet;  
 import javax.servlet.http.HttpServlet;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse;  

 @WebServlet("/ServletDispatcher")  

 public class ServletDispatcher extends HttpServlet {  

      private static final long     serialVersionUID     = 1L;  

      public ServletDispatcher() {  
           super();  
      }  

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
           RequestDispatcher dispatcher = request.getRequestDispatcher("myservlets/Results.do");  
           dispatcher.forward(request, response);  
      }  

      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}  
 }  



Differences and Best Practices


When should I use
response.sendRedirect("")
vs
dispatcher.forward(request, response)


RequestDispatcher is server side forwarding:

  1. The client sends a GET request
  2. The servlet forwards the request to another servlet
  3. The second servlet processes the request and returns a response ...



SendRedirect is client side redirection:

  1. The client sends a GET request. 
  2. The server returns a redirect.  The response is empty and contains a new URL
  3. The client automatically send a new GET request (with the new URL from the redirect).
  4. The server returns a response ...




Using Fiddler


Fiddler helps you debug web applications by capturing network traffic between the Internet and test computers. Among other capabilities, the tool enables you to inspect incoming and outgoing data to monitor requests and responses.

If I open the Fiddler tool, and run the servlet with RequestDispatcher, Fiddler will show me this:


If I run the Servlet with the SendRedirect, Fiddler will show me this:

Notice the two GET statements in the SendRedirect.  The output from Fiddler corresponds to our sequence diagrams above.


References


  1. Forwarding
    1. http://www.jguru.com/faq/view.jsp?EID=206736
      1. suppose you want Servlet_A to invoke Servlet_B ...
  2. Forward vs Redirect
    1. http://www.javapractices.com/topic/TopicAction.do?Id=181
      1. It's important to understand the difference between these two cases, in particular with respect to browser reloads of web pages.
    2. http://javarevisited.blogspot.in/2011/09/sendredirect-forward-jsp-servlet.html
      1. This is a classic interview question ..
    1. http://stackoverflow.com/questions/2047122/requestdispatcher-interface-vs-sendredirect

Servlet Mapping

Web XML


In the deployment descriptor (web.xml file), typically contained at WebContent/WEB-INF/web.xml, you can modify the servlet mapping:
 <?xml version="1.0" encoding="UTF-8"?>  
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xmlns="http://java.sun.com/xml/ns/javaee"  
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
      id="WebApp_ID" version="3.0">  

      <display-name>HelloWorldServlet</display-name> 
 
      <servlet>  
           <servlet-name>XYZ</servlet-name>  
           <servlet-class>com.swtk.web.servlets.HelloWorld</servlet-class>  
      </servlet>  

      <servlet-mapping>  
           <servlet-name>XYZ</servlet-name>  
           <url-pattern>/hiddenservlets/helloworld.do</url-pattern>  
      </servlet-mapping>  

      <welcome-file-list>  
           <welcome-file>index.html</welcome-file>  
           <welcome-file>index.htm</welcome-file>  
           <welcome-file>index.jsp</welcome-file>  
           <welcome-file>default.html</welcome-file>  
           <welcome-file>default.htm</welcome-file>  
           <welcome-file>default.jsp</welcome-file>  
      </welcome-file-list>  

 </web-app>  


The first part of the deployment descriptor is the creation of the servlet node:
 <servlet>  

      <!-- this is a variable name that could be anything -->
      <servlet-name>XYZ</servlet-name>  

      <!-- this is a fully qualified mapping to the servlet class -->
      <servlet-class>com.swtk.web.servlets.HelloWorld</servlet-class>  

 </servlet>  

The second part of the descriptor contains the servlet-mapping:
 <servlet-mapping>  
      
      <!-- refer to the variable name in the servlet node -->
      <servlet-name>XYZ</servlet-name>  
    
      <!-- define a mapping -->
      <url-pattern>/hiddenservlets/helloworld.do</url-pattern>  

 </servlet-mapping>  

Multiple url-pattern nodes can be defined in the same servlet-mapping block. The use of the .do extension is a convention from earlier days of web development.


Using Annotations

In Servlets 3.0, you can use annotations directly on the servlet to accomplish the same thing.
 package com.swtk.web.servlets;  

 import java.io.IOException;  
 import java.io.PrintWriter;  
 import javax.servlet.ServletException;  
 import javax.servlet.annotation.WebServlet;  
 import javax.servlet.http.HttpServlet;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse; 
 
 @WebServlet(
    description = "Simple HelloWorld Project", 
    urlPatterns = { 
       "/HelloWorld", 
       "/hiddenservlets/helloworld.do" 
    }
 )  

 public class HelloWorld extends HttpServlet {  

      private static final long     serialVersionUID     = 1L;  

      public HelloWorld() {  
           super();  
      }  

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
           PrintWriter out = response.getWriter();  
           out.print("Hello, World!");  
           out.close();  
      }  
 }