Servlet

Servlet & Ajax: in Javascript you assign a callback function after posting the request to the server, the response will be a paramter to that function.


Export Servlet Source    $ svn export https://glassfish-svn.dev.java.net/svn/glassfish-svn/trunk/v3/web/javax.servlet  servlet-svn --username myUsername


Servlets allow developers to extend and customize any java-enabled server - a web server, a mail server, an application server, or any custom server - with a hitherto unknown degree of portability, flexibility and ease. Imagine for example a java-based FTP server that handles each command with a separate servlet. New commands can be added by simply plugging in new servlets. Or, imagine a mail server that allows servlets to extend its functionality, perhaps by performing a virus scan on all attached documents or handling mail filtering tasks.

Although most servlet developers will design and deploy servlets for use with HTTP servers, servlets are rather generic and HTTP servlets is a small portion.

A generic servlet (protocol independent) extends javax.servlet.GenericServlet;

http servlets extensd javax.servlet.http.HttpServlet;

Each time the server dispatches a request to a servlet, uit invokes the servlet's service(reqObj, respObj) method. A servlet should override service, reqObj contains req and respObj can be used to respond back. HTTPServlet has already overridden service method and has provided doGet or doPost and extending classes should override those or other doXXX() (other http methods) instead.

Adjust Apache Tomcat


For me J2EE JDK installed the Tomcat so must be the same for you and no need to install it separately. But to make sure everything goes right, we add the following environment variable as before (It points to the directory apache was installed):

CATALINA_HOME="/home/morteza/apache-tomcat-6.0.18"

Run Apache Tomcat

first time

$ cd $CATALINA_HOME
CATALINA_HOME$ chmode +x startup.sh
[CATALINA_HOME$ chmode +x setclasspath.sh]  (catalina.sh)
Go to Apache Tomcat bin directory and run startup.sh:

>cd /home/morteza/apache-tomcat-6.0.18/bin/
/home/morteza/apache-tomcat-6.0.18/bin/>./startup.sh

Now, you can use the ubuntu firefox browser and got to the address:

http://localhost:8080/

It must show the Apache Tomcat local page on your computer.
Hint: to shut down the Apache Tomcat web server simply Go to Apache Tomcat bin directory and run startup.sh:

>cd /home/morteza/apache-tomcat-6.0.18/bin/
/home/morteza/apache-tomcat-6.0.18/bin/>./startup.sh

Create Your Web Application


Web pages should be contained in a web application (it is like a container or a bowl to contain web pages most likely as a directory structure form); and a web application server is something that executes a web page, once someone wants to see the web page by typing http://mywebpage in the address bar of his or her web browser (e.g. Firefox or Internet Explorer).

Here, we create our first Hello web application. Web applications are placed in the
/apache-tomcat-6.0.18/webapps/ directory. Web Applications should have a specific directory structure.
  1. A web application is in a folder, we create our web application in folder my. So we create a directory named my in the webapps directory.
2. A web application should have a folder named WEB-INF. So we create a directory named WEB-INF in the my folder.
3. There should be a file called web.xml in the WEB-INF folder. So we create an empty file, name it web.xml and put the following lines in the file:

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

</web-app>

You can also go to one of the sibling directories of the my folder, for example, examples folder, copy its web.xml file from its WEB-INF directory remove everything except the above and put it in your WEB-INF directory.

Run your hello.html

make a simple hello.html with whatever text it might have, in the my directory. I did the following

<html>
<title> Hi Title </title>
<body> Hi! </body>
</html>

Run the web application server (tomcat). Use firefox and go to address:

http://localhost:8080/my/a.html

There comes your hello web application!

Your First Servlet

A servlet is a java class that writes somethings in a print stream and that print stream appears all at onces as a complete web page. The following is our hello servlet, copy it in a file named Hello.java and compile it using the javax.servlet .jar file. I found the jar file in the eclipse plug-ins directory named as (javax.servlet_2.5.0.v200806031605.jar).

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

public class Hello extends HttpServlet {

    public void doGet(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {

        res.setContentType("text/html");
        PrintWriter out = res.getWriter();

        out.println("<HTML>");
        out.println("<HEAD>");
        out.println("<TITLE>");
       
out.println("Hello"
       
out.println("</TITLE>"
       
out.println("</HEAD>");
        out.println("<BODY>");
        out.println("<H1>Hello World</H1>");
        out.println("Today is: " + (new java.util.Date().toString()));
        out.println("</BODY></HTML>");  

    }
}

$ cd myProjects/beerV1
$ javac -classpath /home/morteza/applications/tomcat/common/lib/servlet-api.jar:classes:. -d bin src/com/firstServlet/Hello.java

-d means put  the compiled classes in the bin directory preserving their structure.


I copied the jar file to the directory of the Hello.java we created from here and compiled it using following command line.
>javac Hello.java -classpath ./javax.servlet_2.5.0.v200806031605.jar

Servlets should be in a directory named class in the WEB-INF directory. Then, put the resultant class file in the directory you just made and named class in the WEB-INF direstory. To finally see our servlet we need to add some lines to the web.xml file. Sp our web.xml files looks likes this:

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

    <servlet>
      <servlet-name>HelloServlet</servlet-name>
      <servlet-class>Hello</servlet-class>
    </servlet>

    <servlet-mapping>
      <servlet-name>HelloServlet</servlet-name>
      <url-pattern>/hi</url-pattern>
    </servlet-mapping>

</web-app>

Start or restart your application server (tomcat) and browse to http://localhost:8080/my/hi . Here comes your first Servlet! /hi is thte url pattern we assigned for our servlet.

Packages

When you want to have your servlet in a package. First of all the package declaration should be in the servlet java file. The web.xml should be like this (the servlet is in the hall package):

<servlet>
     <servlet-name>myHeaders</servlet-name>
     <servlet-class>hall.ShowRequestHeaders</servlet-class>
 </servlet>
 <servlet-mapping>
     <servlet-name>myHeaders</servlet-name>
     <url-pattern>/hall/headers</url-pattern>
 </servlet-mapping>

To call the servlet from an html:
<FORM ACTION="hall/headers" METHOD="POST">

Pass HTML Forms to Servlets

Write a static html page with a form and anything in the form that you want. add a submit button. Give the address of the following servlet as the action of the form. It will show all the received parameters.

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AllFieldsReporter extends HttpServlet {

    protected void doGet(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {

        res.setContentType("text/html");
        PrintWriter out = res.getWriter();

        out.print("<html><title>AllFieldsReporter title</title><body>");
        out.print("Hi!");
        out.print("<table border=\"1\">");
        Enumeration<String> paramEnum = req.getParameterNames();
        while (paramEnum.hasMoreElements()) {
            out.print("<tr>");
            out.print("<td>");
            String param = (String) paramEnum.nextElement();
            out.print(param);
            System.out.println(param);
            out.print("</td>");
            out.print("<td>");
            String[] parameterValues = req.getParameterValues(param);
            for (int j = 0; j < parameterValues.length; j++) {
                out.print(parameterValues[j]);
                out.print("<br>");
            }

            out.print("</td>");
            out.print("</tr>");
        }
        out.print("</table>");
        out.print("</body></html>");
    }

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

  service() methods take generic requests and responses:
     service(ServletRequest request, ServletResponse response)
  doGet() or doPost() take HTTP requests and responses:
     doGet(HttpServletRequest request, HttpServletResponse response)
     doPost(HttpServletRequest request, HttpServletResponse response)

Forward Servlet Data (as Controller Class) to JSP File (as View Class)

request.setAttribute("styles", result); // request-life-time attribute

RequestDispatcher requestDispatcher = request.getRequestDispatcher("result.jsp"); //at implementation time, the control should know where the view will be at deploy time !!!??
view.forward(request, response);

OR  requestDispatcher.include(request, response); // will call the dispatcher destination it will perform some calculations on the request and return back to current servlet

Redirect makes the client do the work, requestDispatch makes something else ON the server do the work.


Life Cycle

Once a Servlet object is created, it remains in memory. each call will be a new thread to the object. Each registered name for a servlet (not each alias) is associated with one servlet.
A Server uses a new ClassLoader each time it reloads a servlet.
Hence, MyServlet servlet = (MyServlet)getServletContext().getServlet("MyServlet"); might work correctly or not since might be a different version than of the current calling servlet (different parent class loaders). A ClassCastException might occur while its of type MyServlet. Because its new ClassLoader won't find MyServlet using the primordial class loader and will load its own copy of MyServlet.


Get Application Server Parameter

Servlet Config is one for the whole web application, servlet context is just for one servlet
in the web.xml in <web-app ...> tag add a new tag
<context-param>
        <param-name>name</param-name>
        <param-value>morte</param-value>
    </context-param>
in servlet in init(ServletConfig) method, getServletContext().getInitParameter("name");
in the JSP: application.getInitParam("name"); will return morte


We can also have servlet specific parameters
<servlet>
  <init-param>
        <param-name>name</param-name>
        <param-value>morte</param-value>
  </init-param>
</servlet>>
getServletConfig().getInitParameter("name");

Initializing objects for all shared servlets

in the listener, get the servletContext, get its parameters, initialize the objects you want add them as the servletContext attributes.
public class GlobalInit implements ServletContextListener{
void contextInitialized(ServletContextEvent){
}
void contextDestroyed(ServletContextEvent){
}
}  

It should be introduced in the Deployment Descriptor (DD)  web.xml
<listener>
<listener-class>
com.example.myProject1.MyServletContextListener
</listener-class>
</listener>

Listener

Server will know which event a class listens to by checking the interfaces it implemets.
ServletContextListener (contextInitialized & contextDestroyed)
ServletContextAttributeListener (attributeAdded & attributeRemoved & attributeReplaced)
ServletRequestListener (requestInitialized & requestDestroyed)
ServletRequestAttributeListener (attributeAdded & attributeRemoved & attributeReplaced)
HttpSessionListener (sessionCreated & sessionDestroyed)   //count, track active sessions
HttpSessionBindingListener (valueBound & valueUnbound)   // you have an attribute class (a class for an object that will be stored as an attribute) and you want objects of this type to be notified when they are bound to or removed from a session -- good for EJB entities, to synchronize the content of an object with the database when its being bound to a session or write it back when done.
HttpSessionAttributeListener  (attributeAdded & attributeRemoved & attributeReplaced)
HttpSessionActivationListener  (sessionDidActivate, sessionWillPassivate)   //You have an attribute class and you want objects of this type to be notified when the session to which they are bound is migrating to and from another JVM -- Also, when the session migrates between servers, the sessionWillPassivate is called and once it is successfully moved, the sessionDidActivate will be called. It is interesting to note that the sesssion is not yet ready for service at the time the sessionDidActivate method is called.  --  the class that implements a HttpSessionActivationlistener is mostly the attribute class that would be bound to a session - it gives attributes a chance to be ready for migration if they are not serializable, then work around activation/passivation callbacks to wrk it out. The readObject() writeObject() methods if a Serializable object may not be called. use sessiondidpassivate/activate instead)

Scope : context, session, request

Thread Safety

//for context attributes
: synchronized (getServletContext()){
 getServletContext().setAttribute("foo", 42);
getServletContext().getAttribute("foo");
}

//for session attibutes (a client can open two browser windows-both are thought of belonging to same server) synchronize on HttpSession
: synchronize (request.getSession()){

}

// SingleThreadModel Interface //depracated
if a servlet implements this interface, you are guaranteed that no two threadds will execute concurrently in the servlets service method. The servlet container can make this guarantee by synchronizing access to a single instance of the servlet or by maintaining a pool of servlet instances, and dispatching each new request to a free servlet. - one instance per thread -- depends on vendor implementation

Only request attributes and local variables aer thread safe, and Nothing ELSE.
There is always only one instance of servlet with many threads.

Save Servlet info in File

in init:
FileReader fr = new FileReader(fileName);
BufferedReader bf = new BufferedReader(fr);
initial = bf.readLine();
count = Integer.parseInt(initial);
in destroy:
FileWriter fw = new FileWriter(fileName);//saved in user home
          String countStr = Integer.toString(count);
          fw.write(countStr, 0, countStr.length());
          fw.close();

Background Processing

Servlets can initialize thread which would be running as servlets gets requests and responds
For the case of a background thread that searches to find the next prime number, by setting the getLastModified() method, A client that has the page in its cache will ask to see if the last modified time is newer than its cache time, then it will not be given the same content and just redisplays the page. HTTP response 304 "Not Modified"
--------------------------------------------------------------------------
getLastModified()
is called twice: 1. when sending a response to set the Last-Modified header 2. handling GET requests with a If-Modified-Since header

Retrieve the raw query string using ServletRequest.getQueryString() for the invalid cases like /servlet/Sqrt?576

sending a path to a servlet: /servlet/Dictionary/dict/definitions.txt passes /dict/definitions.txt to the Dictionary servlet accessible via HTTPServletRequest.getPathInfo() or getPathTranslated()

ServletContext.getMimeType(String file)

Which servlet? HttpServletRequest.getRequestURI() can be used in a filter servlet to keep track of count of each servlet as their address.

HTTP Header Referer : the document that contains the link the client followed to access this document.

Check for content length before getParameter to avoid DoS attack

File Upload:
<form action="/jsrv/InitCounter" enctype="multipart/form-data" method="post" >
<input type="file" name="file">
<input type=submit name="upload" value="upload">
</form>


Which Submit Button?

<form action="/jsrv/InitCounter" method="post">
  <input type=submit name="Direction" value="left">
  <input type=submit name="Direction" value="right">
</form>

Reduce Socket Connections

Use a socket to send multiple resources: Keep-Alive, specify content lengths and send a byte stream instead of each content separately
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class KeepAlive extends HttpServlet {
  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/html");
  
 // Set up a PrintStream built around a special output stream

    ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024);
    PrintWriter out = new PrintWriter(bytes, true); // true forces flushing
  
    out.println("<HTML>"
<BODY>);   
    out.println("Hello World");
    out.println("</BODY></HTML>");

    // Set the content length to the size of the buffer
    res.setContentLength(bytes.size());

    // Send the buffer

    bytes.writeTo(res.getOutputStream());
  }
}


<<<< HTTP sends status codes and headers before the content body >>>>

to rediret:

res.setStatus(res.SC_MOVED_TEMPORARILY);
res.setHeader("Location", "http://www.yahoo.com");
OR
res.sendRedirect("http://www.yahoo.com");--- res.encodeRedirectURL(); // url reqriting for redirects

Client Pull

Browser displays first page explaining page has moved, and redirests automatically after a specified amount of time to new page.
setHeader("Refresh", "3");  /// refreshes current page after 3 secs
setHeader("Refresh", "3; http://www.yahoo.com"); //fetches yahoo after 3 secs

Log

ServletContext.log(String msg)
ServletContext.log(Exception e, String msg)
OR
GenericServlet.log(msg) OR log()

getStackTraceAsString(Exception e){
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
PrintWriter writer = new PrintWriter(bytes, true);
e.printStackTrace(writer);
return bytes.toString();
}

Stop

When the client stops, servlet will see an IO exception when trying to write the output. The PrintWriter does not throw exception, so you should check the checkError() regularly. It is wise to free up resources in a finally block.

Session Tracking

HTTP User Authorization: req.getRemoteUser() //requires log-in, one session per user
Hidden Form Fields: sent back to server, it can keep track of the shopping cart as it evolves, user can shop anonymously until check-out
<form>
<input type="hidden" name="zipCode" value="63532">
</form>
URL rewriting: e.g. append a session id. This can be embeded in the action part of a form, so when a user submits, it is returned back to server
private static String generateSessionId() {
  String uid = new java.rmi.server.UID().toString(); // guaranteed unique
  return java.net.URLEncoder.encode(uid); // encode any special chars
}
This id can be added to hrefs to keep track of the user. This is not available in using Hidden Form Fields because they are not subject of a form submission.
Cookie: Sent using HTTP headers. hence, should be added before you send the page content. Browsers are only required to accept 20 cookies per site, 300 total per user, and they can limit each cookie's size to 4096 bytes. Cookies might be disabled on the browser.
public cookie(String name, String value);
HttpServletResponse.addCookie(Cookie cookie): public Cookie[] HttpServletRequest.getCookies();

Cookie.setDomain(String pattern);  begins with a dot and contains two dots. Pattern only matches one entry beyond that dot. e.g. ".foo.com" matches www.foo.com and upload.foo.com and not www.upload.foo.com
Cookie.setMaxAge(int expiry); maximum age of cookie in seconds before it expires
Cookie.setPath(String uri); subset of uris the cookie should be sent to. "/" indicates that cookie should be sent to all pages on a server, if /servlet/MyPage sets a cookie the default path will be /servlet it means cookie should be sent to /servlet/otherPage and /servlet/subdir/birdServlet  , /servlet and any of its subdirectories

The application Server might have the ability to revert using URL rewriting if cookies fail.or it can even store session objects to disk if memory fills up or server shuts down.


Session Migration in a Distributed Application

Only HttpSession objects and their attributes are migrated from one VM to another. Other objects are all duplicated. There is one servlet context per VM and one ServletConfig per Servlet per VM. Once a load balancing server sends a request (with a session
 ID) to another server, the session object will migrate to the new server.

Wrapped Session Tracking

javax.servlet.http.HttpSession    HttpServletRequest.getSession(boolean create)  //maintaining the cookie and sedn/rcv of it are done automatically --- uf you do encode urls the container will first attempt cookies and if it fails it will fall back to URL rewriting. since the cotainer has no way of knowing a client it will attempt both cookies and url reqriting, if it can recognize the session by cookies it will ignore url rewriting in encode url.
out.println("<body>");
out.println("<a href=\""+request.encodeURL("/base.do") + "\"> click me</a>");
out.println("</body>");

res.encodeRedirectURL(); // url reqriting for redirects

url rewriting is automatic if you encode the urls!

HttpSession.  putValue(String name. Object Value)     String[] getValueNames()        removeValue(String name)   
HttpSession.  setMaxInactiveInterval
web.xml
<session-timeout>15</session-timeout>
Each of the methods can throw a java.lang.IllegalStateException if the session is invalid

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SessionTracker extends HttpServlet {
  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();
    // Get the current session object, create one if necessary
    HttpSession session = req.getSession(true);
    // Increment the hit count for this page. The value is saved
    // in this client's session under the name "tracker.count".
    Integer count = (Integer)session.getValue("tracker.count");
    if (count == null)
      count = new Integer(1);
    else
      count = new Integer(count.intValue() + 1);
    session.putValue("tracker.count", count);
    out.println("<HTML><HEAD><TITLE>SessionTracker</TITLE></HEAD>");
    out.println("<BODY><H1>Session Tracking Demo</H1>");
    // Display the hit count for this page
    out.println("You've visited this page " + count +
      ((count.intValue() == 1) ? " time." : " times."));
    out.println("<P>");
    out.println("<H2>Here is your session data:</H2>");
    String[] names = session.getValueNames();
    for (int i = 0; i < names.length; i++) {
      out.println(names[i] + ": " + session.getValue(names[i]) + "<BR>");
    }
    out.println("</BODY></HTML>");
  }
}

Life Cycle
Session is invalid after a specified time (according to the application server) or by manually invalidating. When a session expires (or is invalidated), the HttpSession object and the data values it contains are removed from the system. If you need to retain it, you should use an external location e.g. database and store a handle to the external data in the session object(or your own persistent cookie).
HttpSession.    isNew(); invalidate();  getCreationTime();   getLastAccessTime()  (when the client sent a associated with this session;

// Get the current session object, create one if necessary
HttpSession session = req.getSession(true);
// Invalidate the session if it's more than a day old or has been
// inactive for more than an hour.
if (!session.isNew()) { // skip new sessions
  Date dayAgo = new Date(System.currentTimeMillis() − 24*60*60*1000);
  Date hourAgo = new Date(System.currentTimeMillis() − 60*60*1000);
  Date created = new Date(session.getCreationTime());
  Date accessed = new Date(session.getLastAccessedTime());
  if (created.before(dayAgo) || accessed.before(hourAgo)) {
    session.invalidate();
    session = req.getSession(true); // get a new session
  }


Session Context:     HttpSession.getSessionContext();    HttpSessionContext.getIds();    getSession(String sessionID);

If a client gets to know another client's session id, it can join the second client's session , by a forged cookie or URL.

There can be more than one session context.
HttpServletResponse.encodeUrl(String url);  rewrites (encodes) the url to include current session id.    encodeRedirectUrl(String url);   for urls passed to the send redirect

To perform some action or transaction when a new session occurs, a class can implement HttpSessionBindingListener. It will be notified when  session is bound or unbound. (e.g. for a database transaction) its HttpSessionBindingListener.valueBound(HttpSessionBindingEvent) will be called.

Security

Servlet has various authorization mechanisms, the simple of which is a list of username-pass words. In case of Apache Tomcat, this list is at $CATALINA_HOME/conf/tomcat-users.xml to start we modify it like this:
<?xml version="1.0" encoding="UTF-8"?>
<role rolename="test" />
<user username="user" password="pass" roles="test" />
</tomcat-users>
We set the type of authorization to MemoryRealm at $CATALINA_HOME/conf/server.xml, to do so we delete any other realm tags in the <engine> tag and add the following in the <Engine> tag:
<Realm className="org.apache.catalina.realm.MemoryRealm" />
Up to now we have specified the list of users and their pass words and their roles, and we have set the proper authorization type.
Now it is time to set the restrictions to web application content in the web.xml file of the web application. Add the following to the <web-ap> tag
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>
        Protected Site
      </web-resource-name>
      <!-- This would protect the entire site -->
      <url-pattern> /* </url-pattern>
      <!-- If you list http methods,
            only those methods are protected -->
      <http-method> DELETE </http-method>
      <http-method> GET </http-method>
      <http-method> POST </http-method>
      <http-method> PUT </http-method>
    </web-resource-collection>
    <auth-constraint>
      <!-- Roles that have access -->
      <role-name>test</role-name>
    </auth-constraint>
  </security-constraint>
 
  <!-- BASIC authentication -->
  <login-config>
    <auth-method> BASIC </auth-method>
    <realm-name> Example Basic Authentication </realm-name>
  </login-config>

  <!-- Define security roles -->
  <security-role>
    <description> Test role </description>
    <role-name>test</role-name>
  </security-role>

This sets access limit to all the pages of the web application.
Application server will do all the work of authorization - it will pop up a user-pass form. only proper user with a proper role and proper password will be able to see a page. It is valid as long as the session time-out occurs or it is invalidated or the user closes the browser.
HttpServletRequest.getRemoteUser();
HttpServletRequest.getAuthType();

HTTPS

1. User sends a request to an https server
2. Server signs its public key (which is signed by a famous, trusted authority) by its private key, and sends the signed public key and the public key itself..
3. Browser decrypts the signed public key using the public key and checks if it is equal to the plain public key. - the one who signed it is its owner
4. client generates an asymetric (DES) key signed by the public key of the server and sends its back
All ongoing connection will be encrypted using the key - public key is so computationally complex.

All this is transparent to the servlet. You just need to a server certificate, install it, and configure your server.

Servlet Access Control

Servlet Sandbox (Web server dependent)
Restrict servlets (esp. the ones loaded from a remote source). when the servlet tries to acces the file system or restricted resource a SecurityException is thrown.

Jar files can be signed using digital certificates, to make remote servlets trustable.
java.security.AccessController

Servlet-Servlet Interaction

Call Other Servlet's Methods

ServletContext.getServletNames();     .getServlet(String name);  name is wither servlet's registered name or
A Server uses a new ClassLoader each time it reloads a servlet.
Hence, MyServlet servlet = (MyServlet)getServletContext().getServlet("MyServlet"); might work correctly or not since might be a different version than of the current calling servlet (different parent class loaders). A ClassCastException might occur while its of type MyServlet. Because its new ClassLoader won't find MyServlet using the primordial class loader and will load its own copy of MyServlet.
Workarounds:
  • Avoid casting the returned servlet, instead use reflection. 
  • Or, make sure neither the calling servlet nor the callee servlet are not reloaded
    • You can do this by moving the servlet out of the default servlet directory (usually server_root/servlets) and into the server's standard classpath (usually server_root/classes). The servlet performing the cast can remain in the servlets directory because its ClassLoader can find MyServlet using the primordial class loader.
  • cast the returned servlet to an interface that declares the pertinent methods and place the interface in the server's standard classpath where it won't be reloaded. Every class but the interface can remain in the servlets directory. Of course, in this case, the servlet must be changed to declare that it implements the interface.

//All Servlets Status Saver
ServletContext context = getServletContext();
Enumeration names = context.getServletNames();
while (names.hasMoreElements()) {
  String name = (String)names.nextElement();
  Servlet servlet = context.getServlet(name);
  out.println("Trying to save the state of " + name + "...");
  out.flush();
  try {
    Method save = servlet.getClass().getMethod("saveState", null);
    save.invoke(servlet, null);
    out.println("Saved!");
  }
  catch (NoSuchMethodException e) {
    out.println("Not saved. This servlet has no saveState() method.");
  }
  catch (SecurityException e) {
    out.println("Not saved. SecurityException: " + e.getMessage());
  }
  catch (InvocationTargetException e) {
    out.print("Not saved. The saveState() method threw an exception: ");
    Throwable t = e.getTargetException();
    out.println(t.getClass().getName() + ": " + t.getMessage());
  }
  catch (Exception e) {
    out.println("Not saved. " + e.getClass().getName() + ": " +
                e.getMessage());
  }

Get a Servlet via a Socket HTTP request

// Get the named servlet. Try loading it through an HTTP request if
// necessary. Returns null if there's a problem. Only loads HTTP
// servlets, of course.
public static Servlet getServlet(String name,
                                 ServletRequest req,
                                 ServletContext context) {
  try {
    // Try getting the servlet the old−fashioned way
    Servlet servlet = context.getServlet(name);
    if (servlet != null) return servlet;
    // If getServlet() returned null, we have to load it ourselves.
    // Do this by making an HTTP GET request to the servlet.
    // Use a raw socket connection so we can set a timeout.
    Socket socket = new Socket(req.getServerName(), req.getServerPort());
    socket.setSoTimeout(4000); // wait up to 4 secs for a response
    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
    out.println("GET /servlet/" + name + " HTTP/1.0"); // the request
    out.println();
    try {
      socket.getInputStream().read(); // Even one byte means its loaded
    }
    catch (InterruptedIOException e) { /* timeout: ignore, hope for the best */ }
    out.close();
    // Try getting the servlet again.
    return context.getServlet(name);
  }
  catch (Exception e) {
    // If there's any problem, return null.
    return null;
  }
}

Through System.getProperty("key")     getProperties.put("key", "value");   .remove("key")

This Properties list holds the standard system properties, such as java.version and path.separator, but it can also hold application−specific properties. Or regard System.getProperties() as a Hashtable and put objects in it as a hash. Since it assumes they are Strings, this will cause ClassCastException if getProperty(), list() or save() is called.
The class of the objects put in the system properties should be somewhere that avoids their reloading to prevent version mismatches which casting.
Not persistent between restarts
Accessible by other classes in the JVM
Might be inaccessible in some servlet security managers

Shared Object

A singleton class which is in the server class path(system_root/classes) (to avoid reloads and version mismatches). Static instance of the class in the shared object.
There's one thing to watch out for when collaborating through a shared object: the garbage collector. It can reclaim the shared object if at any time the object isn't referenced by a loaded servlet. To keep the garbage collector at bay, it's wise for every servlet using a shared object to save a reference to the object.
Producer-Consumer pattern: must make sure that there is always an object having a reference to the static instance of the shared object to avoid being garbage collected where there is no running reference to it.

A Servlet as a Shared Object

Advantage: The servlet can maintain its state using its init() and destroy() methods to load and save its state (along with other servlets as a saver servlet saves all loaded servlets). Plus, a shared servlet can report (print) its current state each time it's accessed. Again, it should be in the server class path.

Common Inheritance

Easily limits access to proper subclasses. All the variables SHOULD be static. All shared methods, protected

Execute a Command (e.g. finger)

String command = "finger";
// String[] command = {"finger", "username"} //to include inline parameter
// String[] command = { "/bin/csh", "−c", "finger | grep −v jhunter" };
Runtime runtime = Runtime.getRuntime();
Process process = null;
try {
  process = runtime.exec(command);
  DataInputStream in = new DataInputStream(process.getInputStream());
  // Read and print the output
  String line = null;
  while ((line = in.readLine()) != null) {
    out.println(line);
  }
}
catch (Exception e) { 
}
the finger program executes as a separate process. It can crash or be killed without impacting the server executing the servlet.
To use pipelined command execution:

Error and Exception Notifications

web.xml: -- location of the page must be in the container - hence should start with a slash /
<error-page>
 <exception-type>exception.BookNotFoundException</exception-type>
 <location>/errorpage1.html</location>
</error-page>
<error-page>
 <exception-type>java.lang.Throwable</exception-type>
 <location>/errorpageGeneral.html</location>
</error-page>
<error-page> 
<error-code>404</error-code> <!-- html error code-->
 <location>/myNotFound.html</location>
</error-page>

To generate error:  HttpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
getServerPort() : port server is listening to
getRemotePort() : port the client sent the request from
getLocalPort() : port of the current thread dedicated to the request on the server


Send a Jar File to the client

doGet(){

response.setContentType("Application/Jar");
ServletContext ctx = getServletContext();
InputStream is = ctx.getResourceAsStream("/myFile.jar");

int read = 0;
byte[] bytes = new bytes[1024];

OutputStream os = response.getOutputStream();
while((read = is.readByte(bytes)) != -1){
os.write(bytes, 0, read);
}
os.flush();
os.close();
}

Common MIME Content Types (response.setContentType())

text/html
application/pdf
video/quicktime
application/java
image/jpg
application/jar
application/octet-stream
application/x-zip


Access Resources

getResource()   getResourceAsStream()  
ClassLoader    or     ServletContext
ClassLoader to read resources in jar files,
ServletContext   : work for only resources within the web app that are not deployed within a jar file


Deployment Descriptor (web.xml)

the container looks for a servlet - the more specific match always wins
  • exact match <url-pattern>/books/book1Info.do</url-pattern>
  • directory match <url-pattern>/books/*</url-pattern>
  • extension match <url-pattern>*.do</url-pattern>

Default Directory Page

web.xml : For each directory, the container will pick the first match it finds, starting with the first file in the welcome-file-list from top to bottom.
<web-app ...>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>


Load on Startup

<servlet>
<servlet-name>
<servlet-class>
<load-on-startup>1</load-on-startup>  0 means no
</servlet>

MIME MAPPING

<mime-mapping>
<extention>mpeg</extention>
<mime-type>video/mpeg</mime-type>

</mime-mapping>



Comments