Using WebLogic HTTP Servlets
I. IntroductionThe WebLogic Server implements the JavaSoft HTTP servlet 2.1 API, available at: http://java.sun.com/products/servlet/2.1/index.html What is a servlet?In generic terms, a servlet is any class that can be invoked and executed on the server, most likely on behalf of a client. Don't confuse servlets with applets; a servlet does its work on the server, but an applet does its work on the client. Another way of phrasing what servlets do is "server-side Java". So, what is an HTTP servlet? An HTTP servlet is a Java class that handles an HTTP request and delivers an HTTP response. HTTP servlets live in an HTTP server and must extend the JavaSoft javax.servlet.http.HttpServlet class, so that they may run in a generic servlet engine framework. The WebLogic Server can be configured as a fully functional HTTP Server that delivers any arbitrary MIME type to HTTP clients. For more information on setting this up, see the Administrators Guide document, Setting up WebLogic as an HTTP server. To provide more complex web pages that accept input from the client and provide dynamic responses, you must write your own custom HTTP servlets. You can develop sophisticated web sites, such as shopping-carts or online booking forms by combining WebLogic's built-in services like EJB and JDBC, but HTTP servlets are the key to delivering this functionality to the web. You can write your own custom HTTP servlets and register them with the WebLogic Server. Your HTTP servlets live within the security of the WebLogic Server, and are called upon to service HTTP requests from clients. The work performed by HTTP servlets can be compared to that of CGI scripts, but HTTP Servlets are more sophisticated since:
This document details how to use HTTP servlets to perform server-side Java tasks in response to HTTP requests. In most cases you can use a mechanism like JSP to organize the web-page layout, since these technologies are also based upon HTTP servlets. Overview of HTTP servlet support in WebLogicHTTP servlets can take advantage of all of WebLogic's services and facilities, including EJB, RMI, and JDBC. Below is an overview of the support services offered by WebLogic for HTTP servlets:
How it all fits togetherThe WebLogic Server fulfills all of its HTTP requirements using a set of pre-built HTTP servlets. For example:
A description of these and the other HTTP servlets that WebLogic uses to handle HTTP requests is given in the next section. After you write your own HTTP servlets, you register them in the weblogic.properties file in exactly the same way as the standard internal servlets that are shipped with the WebLogic Server. Your custom servlets are treated exactly like the standard HTTP servlets that provide the HTTP capabilities. How does the WebLogic Server know which HTTP servlet should service a particular HTTP request? Each HTTP servlet is registered against a specific URL pattern, so that when a matching URL is requested, the corresponding servlet is called upon to handle the request. For details on registering HTTP servlets with the WebLogic Server, see the WebLogic Administrators Guide, Registering user-written servlets. II. The WebLogic internal servletsWebLogic uses several internal HTTP servlets to support the various types of web-related functionality. These servlets are registered in the weblogic.properties file. WebLogic does not publish their classdocs as part of the public API, but a description of each HTTP servlet is provided in the Setting WebLogic Properties document under Registering the WebLogic servlets. You can call upon these servlets from an HTTP client, and can integrate their features into your web based applications. III. WebLogic HTTP servlet API referenceWebLogic supports the javax.servlet.http package in the JavaSoft Java Servlet API. You can find documentation for the package at JavaSoft. Package javax.servlet
IV. Implementing with WebLogic HTTP servlets
General guidelines for developing an HTTP servletThis section describes the steps to develop an HTTP servlet, deploy it on the WebLogic Server, and call it from a web-browser. Writing a servletTo write an HTTP servlet class, follow these guidelines:
Let's examine a simple servlet that provides a response to an HTTP request. Later, we'll add to this example to illustrate how to use HTTP parameters, cookies, and session tracking. You can find the source and instructions on how to compile and run all the examples used in this document in the examples/servlets directory of your WebLogic distribution. First we import the packages that support the servlet functionality. Then we implement the service() method that responds with some HTML to the client's browser. Here is the code: import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class HelloWorldServlet extends HttpServlet { public void service(HttpServletRequest req, HttpServletResponse res) throws IOException { // Must set the content type first res.setContentType("text/html"); // Now obtain a PrintWriter to insert HTML into PrintWriter out = res.getWriter(); out.println("<html><head><title>" + "Hello World!</title></head>"); out.println("<body><h1>Hello World!</h1></body></html>"); // Don't forget to close the output stream out.close(); } } The HttpServletRequest object that is passed to the service() method provides information about the client making the request; we'll discuss that later in this document. The HttpServletResponse object is used to send a response back to the client. Before you can send a response back to the client, you must first set the content type of the HTTP response using the HttpServletResponse.setContentType() method. Then call the HttpServletResponse.getWriter() method to obtain the servlet output stream through which your servlet passes the HTTP response. The HttpServletResponse must know about the content type before the appropriate type of output stream can be selected. Once you have an output stream, you can use its print() method to send the contents of an HTML page. When you have sent the entire page, you must flush the output stream using the close() method. This guarantees that any buffered content is sent. Open a new command shell, and run the setEnv script provided in the root directory of the WebLogic installation. If necessary, edit the script in a text editor to point to the correct JDK and WebLogic home directory. In the directory containing your servlet Java source code, compile and place your servlet class in the servlet classpath. The setEnv script sets the environment variable %SERVLET_CLASSES% to point to the default servlet classpath directory. You can now compile you servlet with: $ javac -d %SERVLET_CLASSES% myservlet.java The servlet classpath is set up to point to the %SERVLET_CLASSES% directory in the weblogic.properties file, with the property: weblogic.httpd.servlet.classpath=\ c:/weblogic/myserver/servletclassesSearch for the property in the weblogic.properties file and uncomment it if necessary. Next, you must deploy the servlet on the WebLogic Server so that it may be called from a web-browser client.
To invoke a servlet from a browser you encode the servlet's URL into a page link, or an HTML form. However, you can test your HTTP servlet directly by typing the servlet URL into the URL location bar on a web browser, after the pattern: http://host:port/virtualName?servletArgs For our example, running on a WebLogic Server at the default location, enter this URL: http://localhost:7001/Hello Initializing a servletUsually, a servlet is initialized just before its service() method is called for the first time. Once it has been initialized, it is not initialized again for the duration of the WebLogic Server session, unless it is reloaded. You can have your servlet perform certain tasks at initialization by overriding the init() method.Initializing a servlet at server startupAlternatively, you can configure the WebLogic Server to initialize a servlet immediately after the server is started by adding the following lines to the weblogic.properties file. You should use this feature if your servlet initialization has a noticable delay the first time it is called, or if your servlet needs to be active upon server startup. # Here we register the myservletclass servlet class weblogic.httpd.register.MyServlet=\ examples.servlets.myservletclass # Configure the ServletStartup class to run MyServlet's init() # method at startup weblogic.system.startupClass.StartMyServlet=\ weblogic.servlet.utils.ServletStartup weblogic.system.startupArgs.StartMyServlet=\ servlet=MyServlet where myservletclass is the servlet you wish to initialize when you start the WebLogic Server, associated here with the virtual name MyServlet. Here is how it works. The ServletStartup class is registered as a system.startupClass and is invoked immediately after the server is started. The ServletStartup class initializes the servlet with the virtual name specified as it is "server" parameter in its startupArgs. To initialize more than one servlet at server startup time, you must register the ServletStartup class multiple times, using a different virtual name for each servlet. It is a good idea to follow a naming convention, such as that used above, so you do not clash virtual names and you can keep track of registrations. Using initialization parametersYou can use the weblogic.properties file to pass parameters to an HTTP servlet at its initialization. This allows you to customize the behavior of your servlet without having to recompile it. You associate the parameters with the servlet via its virtual name. For example, if the HelloWorldServlet is registered with the virtual name Hello, you can pass it initialization arguments using: weblogic.httpd.register.Hello=examples.servlets.HelloWorld weblogic.httpd.initArgs.Hello=greeting=howdy,person=stranger For more information on registering servlets, read the Administrators Guide, Setting WebLogic Properties.
You retrieve initialization parameters by calling the Overriding the init() methodYou can have your servlet perform actions at initialization time by overriding the init() method. It is important that you call the overridden init() method in the super class, so that it may parse the initialization arguments. It is generally a good idea to make this the first line in your implementation of the init() method. This example reads initArgs that define a greeting, and a default name that can be customized from the weblogic.properties file. String defaultGreeting; String defaultName; public void init(ServletConfig config) throws ServletException { super.init(config); if ((defaultGreeting = getInitParameter("greeting")) == null) defaultGreeting = "Hello"; if ((defaultName = getInitParameter("person")) == null) defaultName = "World"; } Here we store the values of each parameter in the class instance variables defaultGreeting and defaultName. Note that the code provides default values for these variables if the initArgs property is missing from the weblogic.properties file by checking if the getInitParameter() method returns null. You can change a few lines in the service() method to use these variables in the response. These are the relevant new lines of code: out.print("<body><h1>"); out.println(defaultGreeting + " " + defaultName + "!"); out.println("</h1></body></html>"); The full source code and instructions for compiling, installing, and trying out the HelloWorld2 example can be found in the WebLogic distribution examples/servlets directory. Don't forget to add the initArgs property to the servlet registration in the properties file: weblogic.httpd.register.Hello2=examples.servlets.HelloWorld2 weblogic.httpd.initArgs.Hello2=\ greeting=howdy,person=stranger After you restart the Weblogic Server, view the servlet in your browser with this URL: http://localhost:7001/Hello2 Using the ServletServletWhile you are developing servlets, you may find the ServletServlet useful for prototyping. The ServletServlet allows you to invoke servlets that are not registered in the weblogic.properties file. To use the ServletServlet, you must register it in the weblogic.properties file with the following line: weblogic.httpd.register.servlet=\ weblogic.servlet.ServletServlet You may find it easier to use if you set a permissive ACL (access control list) on the ServletServlet using: weblogic.allow.execute.weblogic.servlet.ServletServlet=\ everyone Now you can invoke the ServletServlet from an HTTP request to serve another servlet. You specify the indirected servlet by its full package name, given as the PATH_INFO to the ServletServlet. The PATH_INFO is the remainder of the URL used to reference the servlet. For instance, to invoke the HelloWorldServlet from the ServletServlet, you would use (entered on one line): http://localhost:7001/servlet/examples/servlets/ HelloWorldServlet The ServletServlet parses the PATH_INFO, and attempts to match it to a given class in the system CLASSPATH of the WebLogic Server or in the servlet classpath, where the slash ("/") is interpreted as a dot ("."). In this example, the class examples.servlets.HelloWorldServlet is called. If a class does not match the full PATH_INFO name, we try to match a class to the next least specific classname by truncating the last "/xxxx" from the PATH_INFO, and so on until a matching class name is found. The surplus PATH_INFO is passed on in turn to the matching class. If no matching class is found, a server error is reported. Warning: Each time the ServletServlet is used to invoke a servlet, it instantiates a new servlet object. All instance variables shall be new, and the init() method is called every time the servlet is called to service a request. Also note that it is bad practice to rely on class scope variables since there is no guarantee that they shall be accessible in other invocations. Note also that once the servlet class has been loaded, it is not loaded again when subsequent servlet objects are instantiated. If you want WebLogic to use your latest servlet class files during runtime, you must use the servlet classpath, described in the next section. When to use the ServletServletIn some special cases, you may need to use the ServletServlet as the mechanism for delivering servlets in a production release site. However, be aware that using the ServletServlet has the following disadvantages:
For these reasons, WebLogic does not recommend the use of the ServletServlet in a production system unless it is a special circumstance that explicitly requires it. Using the servlet classpathServlet classes placed in the servlet classpath are dynamically reloaded when they are modified. The WebLogic Server can be configured to check for updates periodically, or whenever a class is invoked. You can use the servlet classpath to re-deploy your HTTP servlets at runtime, as they are updated, without the need to restart the WebLogic Server. As of release 4.0, classes that are referenced by JSP or JHTML pages are also reloaded if located in the servlet classpath. Note that JSP and JHTML pages are always recompiled if modified -- however, the classes they use must be in the servlet classpath if you want them reloaded when they are modified. To use the reload-on-modify feature, follow these steps:
Although it is recommended that you use the default %SERVLET_CLASSES% directory as your servlet classpath for all of your servlets, you can use other directories by adding them to the servlet classpath property. The servlet classpath should never share directories with other classpaths used by the WebLogic Server. These include the Java system classpath, and the weblogic.class.path. The behavior is not defined if you duplicate classes in other classpaths and the servlet classpath, or point the servlet classpath to the other classpaths; you may find that the reload-on-modify feature will not work correctly, and if may be confusing to debug your code. Servlets in the servlet classpath cannot contain native methods. The Java security model prevents class loaders other than the system class loader from loading classes that contain native code. You can reference servlets in the servlet classpath from the ServletServlet. These servlets are also reloaded if modified, as is true for registered servlets. Beware if you store a reference to one of your classes in an HTTP session, and that class is loaded from the servlet classpath. If your servlet is reloaded, you will recieve a ClassCastException when you retrieve the object from the HTTP session. See the notes on The dreaded ClassCastException for more details. Providing an HTTP responseThis section describes how your HTTP servlet provides a response to the client. All responses should be delivered via the HttpServletResponse object that is passed as a parameter to the service() method of your servlet. Configuring the HttpServletResponseThere are several properties that you may set for a servlet, via the HttpServletResponse object, that translate into HTTP header information. At a minimum, you must set the content type using the setContentType() method, even before you obtain the output stream to which you write the page contents. For HTML pages, this should be set to "text/html". For example: res.setContentType("text/html"); You can set header attributes using the setHeader() method. For dynamic responses, it is useful to set the "pragma" attribute to "no-cache", causing the browser to always reload the page and ensuring the data is current. res.setHeader("Pragma", "no-cache"); If you use htmlKona to compose the servlet page, automatic header details are provided. Composing the visual pageYour servlet sends back an HTTP response via an output stream that you obtain from the HttpServletResponse object using the getWriter() or the getOutputStream() methods. You write the contents of the response to the output stream using the print() method. Note that you must close the output stream using the close() method when finished to flush the contents. htmlKona provides a more structured way to generate the response. It is a WebLogic Java API that encapsulates HTML constructs into objects. For instance, a weblogic.html.ServletPage can be used to programmatically construct a response by adding other HTML page elements. A ServletPage automatically provides any required default values such as header information and other HTML tags. For more information on using htmlKona, refer to the Developers Guide, Using htmlKona. Retrieving client inputThe HTTP servlet API provides a clean interface for retrieving user input from web pages. An HTTP request from a web browser can be accompanied by other information besides the URL, such as information about the client, the browser, cookies, and user query parameters. Query parameters used to carry user input from the browser, and are either appended to the URL address (the GET method) or included in the HTTP request header (the POST method). HTTP servlets need not deal with these details; All of the information in the request is automatically parsed, regardless of the send method, and made accessible via the HttpServletRequest object. You can arrange for query parameters to be sent from the client in a number of ways:
Query parameters are always sent in name/value pairs, and are accessed through the HttpServletRequest object. You can obtain an Enumeration of all parameter names in the query, and fetch each parameter value using its parameter name. A parameter usually has only one value, but can hold an array of values. Parameter values are always interpreted as Strings, so you may need to cast them to a more appropriate type. This sample from a service()method examines query parameter names and their values from a form. Note that request is the HttpServletRequest object. Enumeration params = request.getParameterNames(); String paramName = null; String[] paramValues = null; while (params.hasMoreElements()) { paramName = (String) params.nextElement(); paramValues = request.getParameterValues(paramName); System.out.println("\nParameter name is " + paramName); for (int i = 0; i < paramValues.length; i++) { System.out.println(", value " + i + " is " + paramValues[i].toString()); } } Useful methods of HttpServletRequest
An example using query parametersWe can extend the HelloWorld2 servlet example to accept a username as a query parameter, to build in a more personal greeting. The source code for the HelloWorld3.java example is included in the distribution in the examples\servlets directory. We have taken the service() method from the HellowWorld2 example and implemented it as shown here: public void service(HttpServletRequest req, HttpServletResponse res) throws IOException { String name, paramName[]; if ((paramName = req.getParameterValues("name")) != null) { name = paramName[0]; } else { name = defaultName; } // Set the content type first res.setContentType("text/html"); // Obtain a PrintWriter as an output stream PrintWriter out = res.getWriter(); out.print("<html><head><title>" + "Hello World!" + </title></head>"); out.print("<body><h1>"); out.print(defaultGreeting + " " + name + "!"); out.print("</h1></body></html>"); out.close(); } Here we use the getParameterValues() method to retrieve the value of the name parameter from the HTTP query parameters. We retrieve these values in an array of type String. We expect a single value for this parameter, which we assign to the first element in the name array. If the parameter is not present in the query data, null is returned; in this case, we assign name to the default name that was read from the initArgs property by the init() method. Compile and install the servlet example, then invoke it using the ServletServlet and the servlet classpath, using this URL in your browser (on one line): http://localhost:7001/servlets/examples/servlets/ HelloWorld3?name=yourNameHere We do not document how to use HTML in this document. If you need help with HTML forms, check out "The iDocs Guide to HTML". Note: Your code should never assume that parameters are included in an HTTP request. Since the deprecation of the getParameter() method, you might be tempted to shorthand the getParameterValues() method by tagging an array subscript to the end. However, this method can return null if the parameter is not available, resulting in a NullPointerException. String myStr = res.getParameterValues("paramName")[0];Instead, use.. if ((String myStr[] = res.getParameterValues("paramName"))!=null) { // Now you can use the myStr[0]; } else { // paramName was not in the query parameters! } Using session tracking from a servlet
Session tracking means that you can track a user's progress over
multiple servlets or HTML pages, which by nature are stateless. A
"session" is defined as a series of browser requests that come from
the same client, and are often related, during a certain time
period. Session tracking is important for tying together a series of
browser requests -- think of these as pages -- that may have some
meaning as a whole, such as a shopping cart application.
Before session tracking matured conceptually, developers tried to build state into their pages by stuffing information into hidden fields on a page or embedding user choices into URLs used in links with a long string of appended characters. You can see good examples of this at most search engine sites, many of which still depend on CGI. These sites track user choices with URL parameter name/value pairs that are appended to the URL, after the reserved HTTP character "?". This can result in a very long URL that the CGI script must carefully parse and manage. You can't pass this information from session to session. Once you lose control over the URL -- that is, once the user leaves one of your pages -- the user information is lost forever. Later, Netscape introduced browser cookies, which can be used to store user related information on the client for each server. At last, servers had a place to store information about a user's preferences, but some browsers still do not fully support this, and some people prefer to turn the 'cookie' options off on their browsers. Another factor that should be considered is that most browsers limit the amount of data that can be stored with a cookie. The HTTP servlet specification defines a solution that allows the server to store user details in a tangible place on the server, and protects your code from the complexities of tracking sessions. Your servlets may use an HttpSession object to track a user's input over the span of a single session and share session details between multiple servlets. Tracking a session with the HttpSession object
Under the Java Servlet API, which WebLogic implements and supports, each servlet can access a server-side session via its HttpSession object. An HttpSession object is your servlet's view of the session. You can access an HttpSession in the servlet's service() method using the HttpServletRequest object, depicted as the variable request here: HttpSession session = request.getSession(true); An HttpSession object is created if one doesn't already exist for that client when the request.getSession(true) method is called with the argument true. The session object lives on the WebLogic Server for the lifetime of the session, during which it accumulates information related to that client. Your servlet adds to or removes information from the session object as necessary. A session is associated with a particular client, although that user may not be identified as anything other than anonymous. Each time the client visits your servlet, the same associated HttpSession object is retrieved when the getSession() method is called. For more details on the methods supported by the HttpSession refer to the JavaSoft API. This example service() method counts how many times you have hit the servlet in a session. public void service(HttpServletRequest request, HttpServletResponse, response) throws IOException { // Get the session and the counter param value HttpSession session = request.getSession (true); Integer ival = (Integer) session.getValue("simplesession.counter"); if (ival == null) // Initialize the counter ival = new Integer (1); else // Increment the counter ival = new Integer (ival.intValue () + 1); // Set the new value in the session session.putValue("simplesession.counter", ival); // Output the HTML page out.print("<HTML><body>"); out.print("<center> You have hit this page "); out.print(ival + " times!"); out.print("</body></html>"); } The lifetime of a sessionA session is intended for tracking a user's selections over a series of pages in a single transaction, such as browsing for an item, adding it to a shopping cart, then billing via credit card. A session is transient, and its lifetime ends when:
For more persistent long term storage of data your servlet should
write details to a database using JDBC or EJB and associate the
client with this data via a long lived cookie and/or username and
password. Although we describe here that sessions use cookies and
persistence internally, you should not use sessions as a general
mechanism for storing data about a user.
How does the WebLogic Server know which session is associated with each client? When an HttpSession is created in a servlet it is associated with a unique ID. The browser must provide this session ID with its request in order for the server to find the session data again. The server attempts to achieve this by setting a cookie on the client. Each time the client sends a request to the server from then onwards, it includes the cookie containing the ID. The server automatically parses the cookie, and supplies the session data when your servlet calls the getSession() method.
If the client does not accept cookies, the only alternative is to
encode the ID into the URL links in the pages sent back to the client.
For this reason, you should always use the encodeURL() method when you include URLs in your
servlet response. See Using URL rewriting
later in this document. The WebLogic Server knows whether or not the
browser accepts cookies and will not unnecessarily encode URLs, so you
should make a habit of always using this method. WebLogic
automatically parses the session ID from an encoded URL, and retrieves
the correct session data when you call the getSession() method. This means no disruption to your
servlet code regardless of the method used.
After you have obtained a session using the getSession(true) method, you can tell if the session has just been created by calling the HttpSession.isNew() method. If this method returns true, then the client did not indicate that it already has a valid session, and at this point the client is unaware of the new session, until a reply is posted back from the server. You should design your application to accommodate each of these conditions in a way that suits your business logic. For example, your application might redirect the client's URL to a login/password page if you determine that the session hasn't yet started. Here is a code example: HttpSession session = request.getSession(true); if (session.isNew()) { response.sendRedirect(welcomeURL); } At the login page, you should offer the ability to login to the system, or create a new account. Setting and getting session name/valuesYou store data in an HttpSession object using name/value pairs. Use these methods from the HttpSession interface: getValue() getValueNames() putValue() removeValue() Here is a code snippet that shows how to get all of the existing name/value pairs: String[] sessionNames = session.getValueNames(); String sessionName = null; Object sessionValue = null; if (sessionNames != null) { for (int i = 0; i < sessionNames.length; i++) { sessionName = sessionNames[i]; sessionValue = session.getValue(sessionName); System.out.println("Session name is " + sessionName + ", value is " + sessionValue.toString()); } } To add or overwrite a named value, you use the putValue() method. To remove a named value altogether, use the removeValue() method. Note: You can add any Java descendant of Object as a session value and associate it with a name. However, if you are using session persistence, your 'value' objects must implement Serializable. The dreaded ClassCastException !This will invariably jump up and bite you at some point when you start using HTTP sessions seriously, and so deserves the title. Here is what happens...
Here are some suggested work arounds to this problem:
Logging out and ending a sessionIf your application deals with sensitive information you might consider offering the ability to log out of the session. This is a common feature with shopping carts and internet email accounts. When the same browser returns to the service, the user must log back into the system. To achieve this, you can invalidate the current session by calling: session.invalidate() You should not reference an invalidated session after you have called this method. If you do, an IllegalStateException will be thrown. The next time a user visits your servlet from the same browser, the session data will be missing, and a new session will be created when the getSession(true) method is called, at which point, you might send the user to the login page again. Configuring session trackingFor details on configuring session tracking, see the Administrators Guide, Setting up session management. Using URL rewritingIn some situations, a browser may not accept cookies, which makes session tracking using cookies impossible. URL rewriting is a work-around to this scenario that can be substituted automatically when the WebLogic Server detects that the browser does not accept cookies. URL rewriting involves encoding the session ID into the hyper-links on the web pages that your servlet sends back to the browser. When the user subsequently clicks these links, the WebLogic Server extracts the ID from the URL address and finds the appropriate HttpSession when your servlet calls the getSession() method. To enable URL rewriting in the WebLogic Server, you must set the following property in your weblogic.properties file: weblogic.httpd.session.URLRewriting.enable=true There are some general guidelines for how your code should handle URLs in order to support URL rewriting. You should avoid writing a URL straight to the output stream, as shown here: out.println("<a href=\"/myshop/catalog.jsp\">catalog</a>"); Rather, you should use the HttpServletResponse.encodeURL() method instead. Calling this method does two things; it both determines if the URL needs to be rewritten, and if so, it rewrites it, by including the session ID in the URL. In addition to URLs that are returned as a response to the WebLogic Server, you will also need to encode URLs that send redirects, for example: if (session.isNew()) { response.sendRedirect (response.encodeRedirectUrl(welcomeURL)); The WebLogic Server will use URL rewriting when a session is new, even if the browser does accept cookies, since the server cannot tell if a browser does accept cookies or not in the first visit of a session. Your servlet may determine if a given session was determined from a cookie by checking the boolean returned from the HttpServletRequest.isRequestedSessionIdFromCookie() method. Your application may wish to respond appropriately, or simply rely on URL rewriting by the WebLogic Server. Making sessions persistentThe WebLogic Server can be set up to record session data in a persistent store. If using session persistence, you can expect the following characteristics:
How not to use sessions...Session persistence is not used for storing long term data between sessions. That is, you should not rely on a session still being active when a client returns to a site at some later date. Instead, your application should record long-term or important information in a database. Sessions are not a convenience wrapper around cookies. You should not
attempt to store long term or limited term client-data in a session. Instead,
your application should create and set its own cookies on the browser.
Examples of this might include an auto-login feature where the cookie might
live for a long period, or an auto-logout feature where the cookie might
expire after a short period of time. Here, you should not attempt to use HTTP
sessions, but instead write your own application specific logic.
When you use persistent sessions, all 'value' objects that you add to the session must implement java.io.Serializable. For more details on writing serializable classes, refer to the online java tutorial about serializable objects. If you add your own serializable classes to a persistent session, be careful that each instance variable of your class is also serializable. Otherwise, you can declare it as transient, and WebLogic will not attempt to save that variable to persistent storage. One common example of an instance variable that must be made transient is the HttpSession object. Configuring session persistenceFor details on setting up persistent sessions, see the Administrators Guide Setting up WebLogic as an HTTP server: Configuring session persistence. What is a cookie?A cookie a piece of information that the server asks the client browser to save locally on the user's disk. Each time the browser visits the same server, it sends all cookies relevant to that server with the HTTP request. Cookies are useful for identifying clients as they return to the server.
Each cookie has a name and a value. A browser that supports cookies
generally allows each server domain to store up to 20 cookies at up to
4k per cookie.
To set a cookie on a browser, you must create the cookie, give it a value, and add it to the HttpServletResponse that is the second parameter in your servlet's 'service' method. The following code illustrates this: Cookie myCookie = new Cookie("ChocolateChip", "100"); myCookie.setMaxAge(Integer.MAX_VALUE); response.addCookie(myCookie);
This adds a cookie called "ChocolateChip" with a value of "100" to the
browser client when the response is sent. The expiration of the cookie
is set to the biggest possible value, which effectively makes the
cookie last forever. Since cookies only accept string-type values, you
should cast to and from the desired type that you wish to store in the
cookie. A common practice is to use the handle ID of an EJB instance
for the cookie value and store the user's details in the EJB.
You can retrieve a cookie object from the HttpServletRequest that is passed to your servlet as an argument to the service() method. The cookie itself is presented as a javax.servlet.http.Cookie object. In your servlet code, you can retrieve all the cookies sent from the browser by calling: Cookie[] cookies = request.getCookies(); This method returns an array of all cookies sent from the browser, or null if no cookies were sent by the browser. Your servlet will need to process the array in order to find the correct named cookie. You can get the name of a cookie using the Cookie.getName() method. Note that it is possible to have more that one cookie with the same name, but different 'path attributes'. If your servlets set multiple cookies with the same names, but different 'path attributes' you will also need to compare this using the Cookie.getPath() method. The following code illustrates how to access the details of a cookie sent from the browser. It assumes that all cookies sent to this server will have unique names, and that we are looking for a cookie called "ChocolateChip" that we may have previously set in a browser client: Cookie[] cookies = request.getCookies(); boolean cookieFound = false; for(int i=0; i < cookies.length; i++) { thisCookie = cookies[i]; if (thisCookie.getName().equals("ChocolateChip")) { cookieFound = true; break; } } if (cookieFound) { // We found the cookie! Now get its value int cookieOrder = String.parseInt(thisCookie.getValue()); } For more details on cookies, see The JavaSoft Cookie API and The Java Tutorial: Using Cookies.
weblogic.httpd.session.cookie.domain=myserver.com This property will instruct the browser to include the proper cookie(s) for all requests to hosts in the domain specified in place of "myserver.com". For more information on this property or configuring session cookies, see Setting up WebLogic as an HTTP Server.
Using WebLogic services from an HTTP servlet
If you write a browser client, your client has access to many of the rich features of WebLogic in spite of the fact that your client isn't a Java client application (for more on writing Java client applications, see Writing a T3Client application). When you write server-side Java, you can access the WebLogic services such as factory methods -- like JNDI, RMI, EJB, JDBC connections, etc. -- as a WebLogic server-side process, rather than a Java client application. You can do this with a static method from the weblogic.common.T3Services class, as shown here: T3ServicesDef t3s = T3Services.getT3Services(); Once you have a T3ServicesDef object, you can call any of the factory methods from that interface to get access to WebLogic services. For example, here is how you might submit an event registration from a servlet (where request is the HttpServletRequest object): ParamSet eventParameters = new ParamSet(); String name; Enumeration names = request.getHeaderNames(); while (names.hasMoreElements()) { name = (String)names.nextElement(); try { eventParameters.setParam(name, request.getHeader(name)); } catch (Exception e) {;} } EventMessageDef ev = T3Services.getT3Services().events() .getEventMessage("HTTPWATCH", eventParameters); ev.submit(); Here is another example of how you might use WebLogic services from a servlet, through the log() and config() services: T3ServicesDef t3s = T3Services.getT3Services(); String consoleEnabled = t3s.config().getProperty("weblogic.system.enableConsole"); String logmsg = "Console enabled was set to " + consoleEnabled + " at " + new java.util.Date(); LogServicesDef logger = t3s.log(); logger.log(logmsg);
Using connection pools with server-side JavaWebLogic supports the use of JDBC connection pools from server-side Java classes, including servlets. We provide two server-side JDBC drivers: one for routine use for most database operations, and another for use exclusively with EJB, for transactional operations. Because WebLogic's servlet persistence is EJB-based, you will also use a connection pool as part of your configuration setup for persistence. A connection pool is a named group of JDBC connections to a database that are created when the WebLogic Server starts. Your servlets "borrow" a connection from the pool, use it, then return it to the pool by closing it. This is far more efficient than creating a new connection for each client each time they need to access the database. Another advantage is that you do not need to hard-code details about the database your application uses. WebLogic supplies special JDBC "pool" drivers that give server-side Java access to connection pools that are registered on the same WebLogic Server. WebLogic's JDBC pool drivers include:
Setting up the registration for a connection poolTo configure a connection pool, you add a registration for it to the weblogic.properties file. The connection pool is created each time you start the WebLogic Server and exists until the server is shut down. There are more details on setting properties for JDBC connection pools in the Administrators Guide, Setting WebLogic properties. You configure most aspects of the connection pool from the properties file, such as:
It is easy to use a connection from the pool in your servlet code. Your servlet code is abstracted from administration details of the pool. You can configure the pool, or even point the named connection pool at a completely different database, all without changing or recompiling any code. Here is an example of a registration from a weblogic.properties file for a connection pool named sales and its ACL (access control list). This pool uses jdbcKona/Oracle to connect to an Oracle database; the jdbcKona/Oracle driver requires a set of OCI client libraries on the WebLogic Server host. weblogic.jdbc.connectionPool.sales=\ url=jdbc:weblogic:oracle,\ driver=weblogic.jdbc.oci.Driver,\ initialCapacity=2,\ maxCapacity=10,\ capacityIncrement=2,\ props=user=scott;password=tiger;server=goldengate weblogic.allow.reserve.weblogic.jdbc.connectionPool.sales=\ joeuser,maryuser If you do not set an ACL for a connection pool, it defaults to "everyone" -- that means any user can grab a connection. If you want to restrict access to the pool to certain users, you must set up an access control list, as shown above. Then you set up a username and password for each application user with a java.util.Properties object in your code. Note that this username and password is the valid username and password that matches a user registered in the weblogic.properties file, and not a database username and password. At runtime, the username and password supplied by the application is checked against the list of T3Users established in the access control list for the connection pool. Each of the users in the access control list must be registered and have been assigned a password in the weblogic.properties file, as shown here: weblogic.password.joeuser=dP3m*spQc! Using a connection pool in your servletHere is a simple servlet that selects all of the records from a database table using dbKona, and displays them using htmlKona. First we load the pool driver. The full pathname of the driver is weblogic.jdbc.pool.Driver. Class.forName("weblogic.jdbc.pool.Driver").newInstance(); Then, we create the connection with the URL for the driver, plus (optionally) the name of the registered connection pool. The URL of the pool driver is jdbc:weblogic:pool. You can identify the pool in one of two ways:
Here is an illustration that obtains a connection from a pool, using a URL that incorporates the name of the connection pool. The second argument to this method is a java.util.Properties object, which we pass here as null. If you do not set the username and password for a T3User in a Properties object, the username defaults to "guest". If you are using an ACL, it must contain the user "guest", for this default connection to be successful. Connection conn = DriverManager.getConnection( "jdbc:weblogic:pool:sales", null); This code snippet illustrates how to obtain a connection using a Properties object to set the name of the connection pool to "myConnectionPool" : Properties props = new Properties(); props.put("connectionPoolID", "myConnectionPool"); Connection conn = DriverManager.getConnection("jdbc:weblogic:pool", props); Note that the Connection returned by DriverManager.getConnection() is an instance of weblogic.jdbc.pool.Connection. You must use the close() method on the Connection object, when you have finished with your JDBC work, so that the connection is properly returned to the pool. Here is the entire servlet. This servlet displays the contents of the "emp" database table in an HTML table on a web page. package examples.jdbc.pool; import java.io.*; import java.sql.*; import java.util.Properties import javax.servlet.*; import javax.servlet.http.*; import weblogic.db.jdbc.*; import weblogic.html.*; public class simpleselect extends HttpServlet { public synchronized void service(HttpServletRequest req, HttpServletResponse res) throws IOException { try { Properties props = Properties(); props.set("user", "joeuser"); props.set("password", "dP3m*spQc!"); Class.forName( "weblogic.jdbc.pool.Driver").newInstance(); Connection conn = DriverManager.getConnection( "jdbc:weblogic:pool:sales",props); res.setStatus(HttpServletResponse.SC_OK); res.setContentType("text/html"); TableDataSet ds = new TableDataSet(conn, "emp"); TableElement tbl = new TableElement(ds); ServletPage hp = new ServletPage("Simple select"); hp.getBody() .addElement(MarkupElement.HorizontalLine) .addElement(tbl); ds.close(); conn.close(); hp.output(res.getOutputStream()); } catch (Exception e) { ServletPage hp = new ServletPage("An Exception occurred"); ByteArrayOutputStream ostr = new ByteArrayOutputStream(); e.printStackTrace(new PrintStream(ostr)); hp.getBody() .addElement(new HeadingElement("An Exception occurred:", 2)) .addElement(new LiteralElement(ostr.toString())); hp.output(res.getOutputStream()); } } } Note that the htmlKona class TableElement automatically generates a formatted html table from a TableDataSet. This example may be compiled and run from the distribution directory examples/jdbc/pool. Threading issues in HTTP servletsWhen designing a servlet, you must consider how the servlet is invoked by the WebLogic Server under high load. It is inevitable that more than one client will hit your servlet simultaneously. You must write your servlet code to guard against sharing violations on shared resources or instance variables. The following tips will help you to design around this issue. As of the WebLogic 4.5 release, the SingleThreadModel is supported as specified in the JSDK2.1. An instance of a class that implements the SingleThreadModel is guaranteed not to be invoked by multiple threads simultaneously. Multiple instances of a SingleThreadModel servlet are used to service simultaneous requests, each running in a single thread. When designing your servlet, you should take care over shared resources outside of the servlet class such as file and database access. The multiple servlet instances used are identical, and may use exactly the same resources, so there are still synchronization and sharing issues that must be resolved, even if you do implement the SingleThreadModel. For instance, the SurveyServlet example (distributed with the JSDK) writes to a file - the SingleThreadModel will not protect against multiple servlet instances writing to the same file. WebLogic recommends that shared resource issues are handled by the developer on an individual servlet basis. The following guidelines may be helpful:
Getting a handle to a servletYou can get a handle to a servlet using the following code anywhere inside a servlet. Servlet x = getServletConfig() .getServletContext() .getServlet(String name); This will return a properly loaded and initialized servlet which can then have methods called against it (service(), etc). Using server-side includesWebLogic supports server-side includes (SHTML files) using an internal WebLogic servlet called the ServerSideIncludeServlet. Server-side includes allow you to include templates in your HTML pages. You define the templates in other files, and may include them in many other web pages to make maintenance easier. For example, you might define a header and a footer for all of your web pages. When you wish to change the headers, you can make the change in the single template file to take effect on all other pages that include the template file.You may also invoke a servlet using the servlet tag to generate dynamic content within your web page, although for new projects we recommend you consider using JSP. HTML files containing server-side includes traditionally have an .shtml extension. The ServerSideIncludeServlet is registered in the weblogic.properties file to handle all requests for files with this extension. Like the FileServlet, the ServerSideIncludeServlet searches for files below the document root. For details on setting up the ServerSideIncludeServlet, see Using server-side includes in the Administrators Guide, "Setting up WebLogic as an HTTP server". WebLogic supports two SSI directives:
Clustering servletsWebLogic supports clustering servlet services across a WebLogic Cluster. Clustering provides failover and load balancing to increase the performance and reliability of your website. Provided that you use HTTP sessions as they were intended, there are no servlet implementation differences that you must consider. For details on setting up a WebLogic Cluster, including using JDBC session persistence and in-memory state replication with a proxy server, see the Administrator Guide Setting up a WebLogic Cluster: Setting up HTTP servlets. Setting up ACLs for servlets in the WebLogic realmweblogic.servlet weblogic.servlet.virtualName WebLogic controls access to internal resources like HTTP servlets through Access Control Lists (ACLs) set up in the WebLogic Realm. Entries for ACLs in the WebLogic Realm are listed as properties in the weblogic.properties file. (For more info on the properties file, see the WebLogic Administrators Guide, Setting WebLogic properties. You can set the execute permission for an HTTP servlet by adding a property to the properties file. The ACL named weblogic.servlet controls access to all registered servlets. Setting the execute permission for the weblogic.servlet ACL to everyone allows anyone to execute any servlet without entering a password, except those servlets with more specific ACLs. To limit access to an individual servlet, you must set its execute permission to a list of one or more users. For example, setting the weblogic.servlet.T3AdminProperties ACL to the user system would allow general access (without a password) to all registered servlets except T3AdminProperties; only the system user would be able to execute that servlet. (The user "system" always has access to all servlets, but in this case setting the permission for this servlet effectively denies permission to everyone else.) Here is an example: weblogic.allow.execute.weblogic.servlet=everyone weblogic.allow.execute.weblogic.servlet.T3AdminProperties=system Setting ACLs for groups of servletsYou can organize servlets into groups using a delimited virtual name, then set a single ACL for those virtual names. In this example, we register all administration servlets against the virtual name pattern T3Admin.xxxx. We set one ACL to allow access to all servlets, and another ACL that limits access to all servlets beginning with the virtual name pattern T3Admin. The second ACL is more specific than the first, so it effectively limits administration abilities to the system user. weblogic.httpd.register.T3Admin.events=admin.T3AdminEvents weblogic.httpd.register.T3Admin.clients=admin.T3AdminClients weblogic.httpd.register.T3Admin.connections=\ admin.T3AdminConnections weblogic.httpd.register.T3Admin.jdbc=admin.T3AdminJDBC weblogic.httpd.register.T3Admin.license=admin.T3AdminLicense weblogic.httpd.register.T3Admin.main=admin.T3AdminMain weblogic.httpd.register.T3Admin.props=admin.T3AdminProps weblogic.httpd.register.T3Admin.threads=admin.T3AdminThreads weblogic.httpd.register.T3Admin.version=admin.T3AdminVersion # Allow anyone to execute registered servlets weblogic.allow.execute.weblogic.servlet=everyone # Allow only 'system' to execute any 'T3Admin' servlets weblogic.allow.execute.weblogic.servlet.T3Admin=system
Note: weblogic.httpd.requireAuthentication=falseIts equivalent property is: weblogic.allow.execute.weblogic.servlet=everyone It is recommended that you upgrade your properties file immediately, since we cannot guarantee how long deprecated properties will be supported. Change history
|
|
Copyright © 2000 BEA Systems, Inc. All rights reserved.
|