Chapter 15. Advanced Application Design

CONTENTS

IN THIS CHAPTER

  •  Dynamic JSP
  •  SOAP Server Security Concerns
  •  Quick Takes
  •  Summary

This final chapter will cover two main topics.

The first topic to consider is expanding the traditional boundaries of JSP. The chapter examines Dynamic JSP. In JSP 1.2, XML syntax is introduced to make JSP a 100% XML document. Because JSP is an interpreted language, this means that it's possible to write self-modifying code with the various XML techniques discussed in this book. This section builds an example page that will be dynamically modified depending on changing conditions.

The second application topic is the one of security. This is an extremely important topic at a time when anyone can access and probe our Web applications. As JSP developers, this is something that is a basic part of the construction of a Web application. However, we also need to think about security for our Web services because our Web services are usually hosted on exposed Web servers. For this reason, it makes sense to discuss some basic security techniques. Although these techniques will not be the final word in implementing security, they will form a starting point to begin understanding some security techniques.

Dynamic JSP

Dynamic JSP is a new term. It's so new that there really isn't a generic term for this type of process. The term that best describes this process is "automatic code generation." Personally, I coined the term Dynamic JSP in my previous writings because it's easier to write and makes more sense. Dynamic JSP refers to the ability to change the JSP page programmatically. Because JSP can be interpreted at runtime, any changes made will be compiled and a revised JSP page can then run automatically.

Although it was always possible to create Dynamic JSP pages, in the past it wasn't very practical because the string parsing would be difficult. In practice, this meant only complicated code engines would dynamically modify JSP pages. However, JSP XML syntax changes everything. Using the techniques described earlier in this book makes it easy to work with and change a JSP page programmatically.

Dynamic JSP is not a solution that should be done without thought. Recompiling a JSP page at runtime has a significant overhead in both time and processing requirements. Dynamic JSP has several important areas in which it can be very helpful:

  • Building JSP pages, which are only updated occasionally against an XML file or a Web service

  • IDE-based automatic code generators for JSP

  • Building a site that can literally change itself depending on external conditions

This chapter only covers the first possible use of Dynamic JSP. The other two topics take Dynamic JSP too far away from the book's XML and Web service theme. However, Dynamic JSP does offer us some dramatic improvements for our XML and Web service handling.

In building a JSP page, constantly accessing an XML file or Web service can be very costly in terms of performance. This is especially true when the XML file or the Web service results don't change very often. A better solution is to build an automatic process that accesses your data (XML file or Web service) on a need-to-know basis. This automatic process will rebuild the JSP page to reflect the changed data. Using a solution such as this is incredible. It removes the need of a slow file or Web service access, and the recompilation of the JSP page only happens occasionally.

Now let's run through a simple example. It's possible to build a JSP page to detect when an XML file is placed into a directory. Once this file is detected, the JSP page can read the data from the file and incorporate the data straight into the JSP page. After the JSP page is rebuilt, the XML file is deleted because it's no longer needed by the process. The advantage of this system is the file is only read once. In addition, whereas the page does need recompilation, the recompilation only happens once per XML file reading. This is just one example of how to approach Dynamic JSP: Many other methods exist.

The last example brings up the topic of a trigger. We don't want a JSP page to rebuild itself every time it's called by a user. Instead, we need a trigger something that will cause the Dynamic JSP process to only happen occasionally.

It's possible to build many different kinds of triggers to cause a JSP page to be rewritten. The five most common triggers that will be programmed are

  • A scheduled system based on a time increment.

  • A file-based system. The trigger is the actual creation of a file.

  • An external process. A JSP page or servlet is called manually or automatically, which triggers the actual rebuild process.

  • When the application starts, it rebuilds the various JSP pages to be current.

  • A data field. Usually this field can be stored within a database, the application data space, or even the JSP page itself.

All these systems are valid as triggers, and the ones to use depend on your project needs. It's possible to combine several triggers together. For example, within this chapter's example, we will combine the first, third, and fifth trigger options.

It should be noted that using application and session starting events is not recommended for Dynamic JSP triggers. Application start events would generally be too infrequent. The goal is to avoid having to restart an application often. When building a trigger on application start, it would be a good idea at the very least to build an external process to supplement the application start event. Using a session start as a trigger tends to be a bit heavy because it means that quite a bit of recompilation will happen far more than is required in most cases causing unnecessary extra server load.

When Not to Use Dynamic JSP

Although Dynamic JSP is very powerful, it should be used sparingly for conditions that cannot be solved with traditional approaches. The two conditions in which Dynamic JSP should be avoided by a programmer are

  • When every call would cause the JSP page to be recreated. This solution will result in very slow Web sites. In addition, other design options are usually better choices in this case.

  • When building personalized pages or user-specific pages. Personal pages should be driven by using a database, other external data sources, or simply multiple pages.

Building a Dynamic JSP Example

This example shows you how to build a scheduled system. The goal is to build a page that on a timed basis goes out and calls a Web service to get some data. In this example, we will use the JSP Buzz newsletter service developed in Chapter 14, "Building a Web Service." The example will be a simple application. The page will just display the list results of the JSPBuzz news service, which is nothing special in itself. However, the JSPBuzz only changes once in awhile. It doesn't make sense to call the Web service every time a user requests the page. Instead, we will call the Web service once a day and rebuild our JSP page to contain the data directly. The advantage of this is that we only need to make one Web service call in the morning. In addition, we will set it up so that the page will call automatically.

Our example will use a combination of a scheduled system and an external process for maximum flexibility. This way, the system will automatically refresh itself on a timed basis, but as an administrator, we can run also run another JSP page to manually update the Dynamic JSP page.

The first step is to build our JSP display page. This JSP page must use the new JSP 1.2 XML syntax. This file, shown in Listing 15.1, should be saved as webapps/xmlbook/chapter15/JSPBuzz.jsp.

Listing 15.1 JSPBuzz.jsp
<?xml version="1.0" encoding="UTF-8"?> <jsp:root xmlns:jsp="http://java.sun.com/jsp_1_2" xmlns=""> <jsp:directive.page import="java.util.Calendar" /> <html> <head><title>Current JSPBuzz</title> <PageStats LastUpdate="" NextUpdate="" UpdateCycle="1">     <jsp:scriptlet>Long date = new Long("0");</jsp:scriptlet> </PageStats> <jsp:scriptlet>   <![CDATA[       long startProcess    = date.longValue();       Calendar currentDate = Calendar.getInstance();       long time_accessed = currentDate.getTime().getTime();       if (startProcess < time_accessed)       { out.clear();         RequestDispatcher rd = null;         rd = application.getRequestDispatcher("/chapter15/RegenerateBuzz.jsp");         rd.forward(request,response);       }   ]] > </jsp:scriptlet> </head> <body>     <div></div> </body> </html> </jsp:root>

Let's review the code. The first thing to point out is the fact we do have an XML document, which means that the JSP page in XML syntax must follow the same rules as an XML document. For programmers used to the original JSP syntax, this isn't as easy as it sounds. The original JSP syntax is not well formed, so it takes awhile to get used to the new format.

If you are new to JSP XML syntax, a handy reference is the JSP 1.2 Syntax Card, which can be downloaded at http://java.sun.com/products/jsp/pdf/card12.pdf.

The second point to note is that the code listing uses new elements:

<PageStats LastUpdate="" NextUpdate="" UpdateCycle="1">     <jsp:scriptlet>Long date = new Long("0");</jsp:scriptlet> </PageStats>

The PageStats element is an arbitrary element, which was created purely for this example. This element serves several important functions within this example.

This first function is that data can be stored within an element. The stored data can be used to communicate back to the Dynamic JSP process or to us as comments. The LastUpdate and NextUpdate attributes were created to permit the Dynamic JSP process to leave some data starting at when the last update happened and when the next update is scheduled to occur. These two attributes serve no logical coding purpose; they are comments to let the administrator know when the process ran and will run. The other attribute, UpdateCycle, will be used to tell the Dynamic JSP process when to set the next update to occur. The logic will be to run the next update x number of days after the current run time. This means that in this example the code is set up to run the process once a day.

The other purpose of the PageStats element is to act as a bookmark. Our Dynamic JSP process will rebuild the scriptlet within the PageStats element. The purpose will be to store a Long value indicating when the next update needs to be executed. Now the problem is that several jsp:scriptlet blocks are on this page. We need a way to tell our Dynamic JSP process which scriptlet block we want to process. The PageStats element serves as a useful reference point for our XML parsing code to find our scriptlet.

The ability to create elements to store data within and to mark code is extremely powerful. In fact, this is one of the reasons Dynamic JSP is very practical and easy to code.

Now let's examine the next scriptlet block:

<jsp:scriptlet>   <![CDATA[

Notice that we have the scriptlet code embedded within a <![CDATA[ block. This is required because our scriptlet code has the < sign. We have to embed the code within the CDATA block so Tomcat can successfully parse this JSP XML file. Without the CDATA block, the parser would try to interpret the < time_accessed) statement as an element.

The overall scriptlet code is simple for our page:

long startProcess    = date.longValue();       Calendar currentDate = Calendar.getInstance();       long time_accessed = currentDate.getTime().getTime();

The code first gets the next update time stored in the previous scriptlet block, and then gets the current time the JSP page is running:

if (startProcess < time_accessed)       { out.clear();         RequestDispatcher rd = null;         rd = application.getRequestDispatcher("/chapter15/RegenerateBuzz.jsp");         rd.forward(request,response);       }

A check is done to see whether it's past the update time. If so, the code clears the buffer and forwards the user to the RegenerateBuzz.jsp page.

When the RegenerateBuzz.jsp page runs, it will store the data of the Web service request between the <div> block:

<body>     <div></div> </body>

On a more complicated page, we would assign an id attribute to the <div> blocks so the Dynamic JSP process could insert the data at the proper place with this page.

The basic logic flow of this page is simple: Check the update time, verify whether it's time to update, and, if so, call the update process.

The next step is to build a separate JSP page that will modify the JSPBuzz.jsp page. This file, shown in Listing 15.2, should be saved as webapps/xmlbook/chapter15/RegenerateBuzz.jsp.

Listing 15.2 RegenerateBuzz.jsp
<%@ page import="java.util.Calendar,                  xmlbook.chapter14.*,                  java.io.*,                  java.text.DateFormat,                  java.util.*,                  org.jdom.Document,                  org.jdom.Element,                  org.jdom.input.SAXBuilder,                  org.jdom.Namespace,                  org.jdom.output.XMLOutputter" %> <%  /* Initialize our information */     Calendar currentDate = Calendar.getInstance();     String jsppath       = application.getRealPath("chapter15/JSPBuzz.jsp");     SAXBuilder builder = new SAXBuilder();     Document   doc     = builder.build(new File(jsppath));     Element    root    = doc.getRootElement();     Namespace  ns_jsp  = root.getNamespace();     /* update statistics*/     Element pagestats  = root.getChild("html")                              .getChild("head")                              .getChild("PageStats");     String date = DateFormat.getDateInstance().format(currentDate.getTime());     pagestats.getAttribute("LastUpdate").setValue(date);     /* Determine and save next update time*/     String updateCycle = pagestats.getAttribute("UpdateCycle").getValue();     if (updateCycle == null) updateCycle = "1";     int adddays = Integer.parseInt(updateCycle);     currentDate.add(Calendar.DATE, adddays);     date = DateFormat.getDateInstance().format(currentDate.getTime());     pagestats.getAttribute("NextUpdate").setValue(date);     Element timescript = root.getChild("html")                              .getChild("head")                              .getChild("PageStats")                              .getChild("scriptlet",ns_jsp);     long nexttime = currentDate.getTime().getTime();     timescript.setText("Long date = new Long(\"" + nexttime + "\");");     /* Get the current JSPBuzz data and build listing section*/     String ls_wsdl = "http://localhost:8080/xmlbook/chapter14/JspBuzz.wsdl";     BuzzServiceCall bsc = new BuzzServiceCall(ls_wsdl);     Element div = root.getChild("html")                       .getChild("body")                       .getChild("div");     /* remove all old data within the element */     String      buzz = "<div>" + bsc.getBuzz() + "</div>";     Document buzzdoc = builder.build(new StringReader(buzz));     Element buzzroot = buzzdoc.getRootElement();     div.setText(null);     List  divcontents = div.getChildren();     divcontents.addAll(buzzroot.getChildren()) ;     /* Re write out the JSPBuzz.jsp page*/     FileOutputStream writejsp = new FileOutputStream(jsppath);     XMLOutputter    formatxml = new XMLOutputter();     formatxml.output(doc, writejsp);     /* reforward the page to display the JSPBuzz.jsp results. */     out.clear();     RequestDispatcher rd = null;     rd = application.getRequestDispatcher("/chapter15/JSPBuzz.jsp");     rd.forward(request,response); %>

Although this page will be called automatically, it can also be called manually. The example will use JDOM as the XML Java API.

The first step is to initialize our data:

Calendar currentDate = Calendar.getInstance(); String jsppath       = application.getRealPath("chapter15/JSPBuzz.jsp"); SAXBuilder builder = new SAXBuilder(); Document   doc     = builder.build(new File(jsppath)); Element    root    = doc.getRootElement(); Namespace  ns_jsp  = root.getNamespace();

We get the current time and then find our JSP page and read it in as a JDOM Document object. Because this JSP page will be using the JSP namespace, we also need to get a handle to the JSP namespace.

The next step is to update our user statistics:

Element pagestats  = root.getChild("html")                          .getChild("head")                          .getChild("PageStats");     String date = DateFormat.getDateInstance().format(currentDate.getTime());     pagestats.getAttribute("LastUpdate").setValue(date);

We get a handle to our PageStats element and then stash the date of the update within the LastUpdate attribute.

The next step determines when the next update is to occur and saves the results back to the NextUpdate attribute and the JSP scriptlet:

String updateCycle = pagestats.getAttribute("UpdateCycle").getValue(); if (updateCycle == null) updateCycle = "1"; int adddays = Integer.parseInt(updateCycle); currentDate.add(Calendar.DATE, adddays); date = DateFormat.getDateInstance().format(currentDate.getTime()); pagestats.getAttribute("NextUpdate").setValue(date); Element timescript = root.getChild("html")                          .getChild("head")                          .getChild("PageStats")                          .getChild("scriptlet",ns_jsp); long nexttime = currentDate.getTime().getTime(); timescript.setText("Long date = new Long(\"" + nexttime + "\");");

Notice that we are changing the JSP code within the JSPBuzz.jsp page. This opens up all sorts of powerful techniques. In this case, we are easily storing the next update time as a Long. After this value is stored in the scriptlet, we can have another scriptlet logically check the time and react accordingly. In the JSPBuzz.jsp pages case, it calls this process.

The next step is to call our actual Web service:

/* Get the current JSPBuzz data and build listing section*/ String ls_wsdl = "http://localhost:8080/xmlbook/chapter14/JspBuzz.wsdl"; BuzzServiceCall bsc = new BuzzServiceCall(ls_wsdl);

The code then gets a handle to the <div> block:

Element div = root.getChild("html")                   .getChild("body")                   .getChild("div");

Then the code takes the Web service results and translates the data into another JDOM Document object:

String      buzz = "<div>" + bsc.getBuzz() + "</div>"; Document buzzdoc = builder.build(new StringReader(buzz)); Element buzzroot = buzzdoc.getRootElement();

In creating the Document object, we perform a little prep work. In this case, the code properly enclosed the Web service call results within a <div> block. This was done because the Web service call returned an HTML rather than an XML statement. By adding the <div> blocks, we created a root element for the data so that it was a true XML fragment.

The code then empties out the current JSPBuzz.jsp <div> element with a setText call:

div.setText(null);

By using setText(null), the entire contents of the <div> block are wiped and emptied of data.

Then we take the data from the Web service call and append it to the JSPBuzz Document object:

List  divcontents = div.getChildren(); divcontents.addAll(buzzroot.getChildren()) ;

This is accomplished by using the List functions that JDOM exposes.

The last step is to write the data back out. More specifically, the code overwrites the old JSPBuzz.jsp file with the modified one we created in the JSPBuzz Document object:

FileOutputStream writejsp = new FileOutputStream(jsppath); XMLOutputter    formatxml = new XMLOutputter(); formatxml.output(doc, writejsp); /* reforward the page to display the JSPBuzz.jsp results. */ out.clear(); RequestDispatcher rd = null; rd = application.getRequestDispatcher("/chapter15/JSPBuzz.jsp"); rd.forward(request,response);

When finished, we forward the request to the JSPBuzz.jsp page. This request will cause the page to be accessed, and the JSP container will recompile the page and show the user the new results.

Using JDOM setText

Now what would happen if the code tried to place the result of the JSPBuzz feed directly into the JDOM document using setText? The code would look like this:

div.setText(bsc.getBuzz());

This seems simple enough. If we were to run the page, the result in the JSPBuzz.jsp page would appear as follows:

<div>&lt;div&gt; &lt;p class="12ptBold" align="center"&gt; JSP Buzz - October 9th, 2001 - Misc Tidbits&lt;/p&gt; &lt;div class="10ptBold"&gt;News&lt;/div&gt; &lt;ol&gt; &lt;li&gt; etc etc more string data

JDOM will treat the string as text data, not as XML elements. This means that all the data is properly encoded to be a text result. This includes converting < to &lt; and > to &gt;, not a result we desire. When dealing with XML data, we need to be careful. In Java APIs such as JDOM and dom4j, XML fragments are text. We need to convert all XML fragments to Document objects and then merge the results.

Running the Example

When this runs, you will see the results shown in Figure 15.1.

Figure 15.1. Running JSPBuzz.jsp.

graphics/15fig01.jpg

Of more interest is how the actual JSP page has changed after the process. Don't forget; we rebuilt the JSP page dynamically. When viewed on the server, the page appears as shown in Listing 15.3.

Listing 15.3 JSPBuzz.jsp After Being Rebuilt by RegenerateBuzz.jsp
<?xml version="1.0" encoding="UTF-8"?> <jsp:root xmlns:jsp="http://java.sun.com/jsp_1_2" xmlns=""> <jsp:directive.page import="java.util.Calendar" /> <html> <head><title>Current JSPBuzz</title> <PageStats LastUpdate="Dec 18, 2001" NextUpdate="Dec 19, 2001" UpdateCycle="1">     <jsp:scriptlet>Long date = new Long("1008812169641");</jsp:scriptlet> </PageStats> <jsp:scriptlet>   <![CDATA[       long startProcess    = date.longValue();       Calendar currentDate = Calendar.getInstance();       long time_accessed = currentDate.getTime().getTime();       if (startProcess < time_accessed)       { out.clear();         RequestDispatcher rd = null;         rd = application.getRequestDispatcher("/chapter15/RegenerateBuzz.jsp");         rd.forward(request,response);       }   ]] > </jsp:scriptlet> </head> <body> <div> <div><p class="12ptBold" align="center"> JSP Buzz - October 9th, 2001 - Misc Tidbits</p> <div class="10ptBold">News</div> <ol> <li><a href="http://www.jspinsider.com/jspbuzz/2001/buzz_10_09_2001.jsp#news1"> Microsoft Plans Java Counterpunch for .NET</a></li></ol> <div class="10ptBold">Rambles</div> <ol><li> <a href="http://www.jspinsider.com/jspbuzz/2001/buzz_10_09_2001.jsp#ramble1"> More on Web Services</a></li></ol> ... more of the same ... </div> </div></body></html> </jsp:root>

The sections of code that have changed are marked in bold.

Notice the PageStats element. The element shows that the page was last updated on December 18 and will be updated next on December 19.

<PageStats LastUpdate="Dec 18, 2001" NextUpdate="Dec 19, 2001" UpdateCycle="1">     <jsp:scriptlet>Long date = new Long("1008812169641");</jsp:scriptlet> </PageStats>

Also notice that the exact next time the page will be updated is 1008812169641. This Long value represents the number of milliseconds after Jan 1, 1970 00:00:00 GMT. Although a bit strange, it's the easiest way to store the time value for checking purposes.

Also notice that the JSPBuzz listing is now part of the JSP page. This is very efficient. Instead of calling a Web service to rebuild this page every time, we now have an optimized JSP page, which just performs one small time check to determine when to create a new page.

This technique can be used in many fashions. For instance, if you had a huge XML file to run, it's now possible to create a JSP batch process to read the data into the JSP page at a low load time. Later in the day, users could see the compiled version during high load times. Or, instead of performing expensive and complicated XML/XSL transforms every single time, we could again run the process once and then show the optimized results. The limits are only based on our imagination in how we can apply this technique to improve a JSP site.

SOAP Server Security Concerns

Setting up a SOAP server also includes setting up security. The SOAP server setup in this book is running as a Web application under Tomcat. As a Web application, our SOAP server will inherit all the potential security risks of a Web site. Unfortunately, the typical default installation of a SOAP server will not be secure, so several levels of security should be added to protect the SOAP server to prevent outside programmers from adding or changing the services on our machine. In these examples, the localhost is being used, which means that security isn't a high risk. However, as a topic, security is glossed over too often. Instead, we will take the time to set up some examples to show how you can add security to the basic SOAP setup. This chapter will set up two forms of security. The first will be to use the security realms. Using realms will permit Tomcat to validate security access relative to a user. The second level of security will be to use servlet filtering to only allow certain IP addresses to access the Apache SOAP administration pages. The other consideration is that the techniques shown here are generic; although being applied to Apache SOAP, they will be easily transferable to Apache Axis, other Java-based SOAP servers, or even a normal JSP site.

Before we go any further, remember that there is no such thing as perfect security. The steps shown here are only the most basic steps to take in securing a SOAP server.

Also remember that this example will be working against the SOAP Web application, not the xmlbook Web application.

Let's start with the easiest security step to take. Because the SOAP server is running through Tomcat in this example, we can use Tomcat to set up a security realm.

Using Tomcat Security Zones

The first step is to update the Tomcat user XML file.

This file, shown in Listing 15.4, should be saved in the Tomcat directory as conf/tomcat-users.xml.

Listing 15.4 Updating the tomcat-users.xml File
<tomcat-users>   <user name="soapadministrator" password="mypassword" roles="SoapAdmin" /> </tomcat-users>

This step defines the users who exist, the expected password for each user, and the roles each user will be assigned to within the security realm. Keep in mind that usernames and passwords will be case sensitive when trying to log on to the administrative screens.

The next step is to create the actual security zones. These settings are set up in each individual Web application. This is just a matter of modifying the web.xml file stored in webapps/soap/WEB-INF/web.xml, as shown in Listing 15.5. (Add the following code after the servlet-mapping.)

Listing 15.5 Updating the web.xml File
<security-constraint>     <web-resource-collection>         <web-resource-name>SoapAdmin</web-resource-name>         <url-pattern>/admin/*</url-pattern>     </web-resource-collection>     <auth-constraint>         <role-name>SoapAdmin</role-name>     </auth-constraint> </security-constraint> <login-config>     <auth-method>BASIC</auth-method>     <realm-name> SoapAdmin </realm-name> </login-config>

Restart your server, and some basic security will now be in place.

If we were to access a page in the administrative directory, we would be stopped and prompted for a username and password, as shown in Figure 15.2.

Figure 15.2. Basic login.

graphics/15fig02.jpg

Servlet Filtering

The chances are that your Web service server will only be administered from a few IP addresses. This fact will permit us to block out any unwanted machine from accessing the SOAP administration tools. This is a perfect use for a servlet filter.

Filters were introduced with the Servlet 2.3 specifications. A filter permits the servlet container to intercept a request for a file or a directory. Here's a brief overview of what is possible with a filter:

  • A filter can transform the content of HTTP requests and responses. Whereas a servlet is used to create a new HTTP response, a filter is designed to modify an existing request or response.

  • It's possible to create a chain of filters that perform separate steps of pre- or post-processing to a file within a servlet container.

  • Upon receiving a request, a filter can examine and modify any part of the request.

  • A filter is able to block a request to a file, call the originally requested resource, or throw an exception to indicate there was a problem.

As a brief note, a filter is not a servlet. If you are new to filters and desire to learn more, check out the following filter overview at http://java.sun.com/products/servlet/Filters.html.

This example will only build a very simple filter. The filter will intercept any request for files in the admin directory of the Apache SOAP application. When the request comes from an approved IP address, the filter will allow the original page to be served to the administrator. If the request comes from any other IP address, the filter will block the request and transfer control to a Page Not Found error.

Declaring a Filter

A filter is declared and defined within the web.xml file.

Refer to Table 15.1 for the subelements that can be used to fully define a filter.

Table 15.1. Servlet Definition
Element Description
icon Represents a filename used to represent the filter for use within GUI development tools. This element is not required for a filter.
filter-name This is the filter handle. Any references to the filter servlet within the web.xml file will be through this name.
display-name This is a short name intended for display by GUI tools.
description A short description of the servlet.
filter-class The class file representing the filter action.
init-param Contains an initialization parameter to the filter. This element uses subelements of param-name, param-value, and description to define the overall parameter. These parameters are retrieved by the filter with use of the FilterConfig interface.

In addition to a filter declaration, the system will need a filter-mapping element. This element is used to indicate what resources map to which filter:

<filter-mapping>     <filter-name>a filter</filter-name>     <url-pattern>a file or path</url-pattern> </filter-mapping>

The filter-mapping element only uses the filter-name element to match the mapping to a servlet. The url-pattern element defines the actual mapping request, which will invoke the given filter. This element represents a directory or a file being matched to the filter-name filter. The rules for the url-pattern attribute are the same as for servlet mappings. A complete explanation can be found in the "How Servlet Mappings Work" section in Chapter 10, "Using XSL/JSP in Web Site Design." One other element exists within the filter-mapping element. Instead of defining a url-pattern, it's permissible to use the servlet-name element to map the filter to a specific servlet.

Now it's time to create a registration for our filtering example. This is just a matter of modifying the web.xml file stored in webapps/soap/WEB-INF/web.xml, as shown in Listing 15.6. (Add the following code before any listener declarations.)

Listing 15.6 Updating web.xml
<filter>   <filter-name>IPFilter</filter-name>   <display-name>IPFilter</display-name>   <description>This Filter will only permit a single                IP address to maintain the Web services</description>   <filter-class>xmlbook.chapter15.FilterIP</filter-class>   <init-param>         <param-name>IP</param-name>         <param-value>192.168.1.30</param-value>   </init-param>   <init-param>         <param-name>IP2</param-name>         <param-value>127.0.0.1</param-value>   </init-param> </filter> <filter-mapping>     <filter-name>IPFilter</filter-name>     <url-pattern>/admin/*</url-pattern> </filter-mapping>

The first point to note is that the filter elements must be defined within Tomcat before the listener elements. Tomcat enforces the order of the elements to match the element order defined within the web-app_2_3.dtd specification. This brings up the second point. Apache SOAP was written under the Servlet 2.2 specification. We are coding to Servlets 2.3. Thus, you must make sure to update the web.xml file to use the Servlet 2.3 specification DTD as follows:

<!DOCTYPE web-app   PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"   "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">

You will also have to modify Listing 15.6 for your own use. The following entry needs to be modified:

<param-value>192.168.1.30</param-value>

You will need to change this entry to match the IP of the machine from which you want to administer the SOAP server.

Creating a Filter

The first programming fact to know about filters is that they must implement the javax.servlet.Filter interface.

Creating the filter is an interesting process. The actual filter is only a single step of a larger process. From a design viewpoint, a filter should only perform a single action. When multiple actions are required, build multiple filters. Our process is a single step of blocking unwanted IP addresses, so there will only be one filter. However, as a programmer you might see the need for additional security steps. If this is the case, expand the process by adding filters rather than extending the one filter presented here for the IP blocking.

The file in Listing 15.7 should be saved to webapps/soap/WEB-INF/classes/xmlbook/chapter15/FilterIP.java.

Listing 15.7 A Security Filter
package xmlbook.chapter15; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.http.HttpServletResponse; public class FilterIP implements Filter { private FilterConfig config  = null; public void init(FilterConfig fc) throws ServletException { config = fc;} public void doFilter(ServletRequest request, ServletResponse response,                      FilterChain chain)                      throws java.io.IOException, javax.servlet.ServletException {       Enumeration IPlist  = config.getInitParameterNames();         String incomingIP   = request.getRemoteAddr().trim();         boolean processpage = false;         while (IPlist.hasMoreElements())         { String IP = config.getInitParameter((String) IPlist.nextElement());           if (IP.equals(incomingIP))           { processpage = true;             break;           }         }         if (processpage)         {   chain.doFilter(request,response);}         else         {   ServletContext application = config.getServletContext();             application.log("Unauthorize access attempt from:" + incomingIP);             if (response instanceof HttpServletResponse)             { int notfound = HttpServletResponse.SC_NOT_FOUND;               ((HttpServletResponse)response).sendError(notfound);             }             else             {PrintWriter out = response.getWriter();              out.print("No Page To Access");             }         } } public void destroy() { config = null;} }

A review of the filter shows us some interesting features. The first is that all filters must implement the Filter interface. Then notice that the initialization parameters and the ServletContext are received from the FilterConfig object obtained in the init method. To make access easy, the data will be stored in a private FilterConfig object for access within the main doFilter method.

Now all the magic happens within the doFilter method. The first thing to notice is this method is not passed the more familiar HttpServletRequest and HttpServletResponse objects. This means that when we need to perform some special HTTP processing, some extra casting of the variables will be required by our code. For example, if we block a user in this filter, we want the server to return a Page Not Found error. This would entail using the sendError method of the HttpServletResponse object. However, to do so, the code needs to be written as follows:

if (response instanceof HttpServletResponse)             { int notfound = HttpServletResponse.SC_NOT_FOUND;               ((HttpServletResponse)response).sendError(notfound);             }

In case we can't perform the casting of the HttpServletResponse, we perform a more traditional error message:

else             {PrintWriter out = response.getWriter();              out.print("No Page To Access");             }

Why return a 404 error (Page Not Found)? The reason is simple. When dealing with unauthorized access, the error should give as little information as possible to the trespasser. If we were to return an unauthorized-access error, the error would be telling a trespasser that the page exists. However, if we return a 404 error, it helps to obscure the server setup to a larger degree. Security by obscurity isn't security in itself; however, obscurity when tied to actual security measures does strengthen the existing security measures.

The actual security check within the filter logic is simple:

boolean processpage = false; while (IPlist.hasMoreElements()) { String IP = config.getInitParameter((String) IPlist.nextElement());   if (IP.equals(incomingIP))   { processpage = true;     break;   } }

The code loops through all the IP addresses sent in as parameters to the filter from the web.xml file. If any of these parameters matches the requesting IP address, the page is permitted to run as normal:

if (processpage) {   chain.doFilter(request,response);}

The chain.doFilter() call merely tells the system to process all other filters and the requested resource. To not process the page, all we need to do is not call the doFilter() method.

Running this code isn't very exciting. When your IP address is allowed access, the pages will show up as normal. When an IP is blocked, the user will only see a 404 error.

Other Apache SOAP Specific Security Steps

In using Apache SOAP, you should take additional security measures. One easy measure is to remove or rebuild the index.html page at the root. This page isn't needed by the SOAP server, and it exposes too much information about your SOAP server.

The next step is to plug the remote deployment security hole discussed in Chapter 8, "Integrating JSP and Web Services." We don't want outside users to be able to deploy services remotely through the ServiceManagerClient class. To plug this security hole, a special SOAP server configuration file needs to be created in the system.

NOTE

This fix is not implemented in the May 30, 2001, release of version 2.2. This means that to implement this version of the security patch, you will have to upgrade to version 2.3 if it has been released by the time you read this. Otherwise, you will have to download and install one of the newer nightly builds of 2.2, which have been updated to solve this security problem.

The first step is to modify the web.xml file stored in webapps/soap/WEB-INF/web.xml as shown in Listing 15.8.

Listing 15.8 Updating web.xml to Turn Off Remote Service Deployment
<servlet>   <servlet-name>rpcrouter</servlet-name>   <display-name>Apache-SOAP RPC Router</display-name>   <description>no description</description>   <servlet-class>org.apache.soap.server.http.RPCRouterServlet</servlet-class>   <init-param>     <param-name>faultListener</param-name>     <param-value>org.apache.soap.server.DOMFaultListener</param-value>   </init-param>   <init-param>         <param-name>ConfigFile</param-name>         <param-value>soap.xml</param-value>   </init-param> </servlet>

This step adds a new <init-param> entry to the rpcrouter servlet declaration within the web.xml file. This entry will have a ConfigFile parameter. The parameter itself will point to the soap.xml file. This means that we need to create the soap.xml file. Place the soap.xml file shown in Listing 15.9 into the same directory as web.xml.

Listing 15.9 Creating the soap.xml Initialization File
<soapServer>         <serviceManager>           <option name="SOAPInterfaceEnabled" value="false" />         </serviceManager>         <configManager value="org.apache.soap.server.DefaultConfigManager" >         </configManager> </soapServer>

The entry of interest is the SOAPInterfaceEnabled entry:

<option name="SOAPInterfaceEnabled" value="false" />

The value attribute is a boolean to indicate whether remote deployment is on or off. For security reasons, we want it to be off, so we set it to false.

Once you've finished, stop and restart Tomcat.

Note that it's also possible to rebuild the DefaultConfigManager so that the code blocks all deploy or undeploy requests. The one advantage is we have a Java open source project in which it's possible to modify the code to our particular needs.

Quick Takes

Before concluding this book, two other topics need to be covered very briefly. We have reviewed and discussed many subjects within this book, but we have still only scratched the surface of the possibilities of using JSP and XML together. This section is geared to help point the reader to other topics of interest in using XML and Web services. This section lists a few resources that will aid you in exploring these new topics.

Web Services SSL and Data Encryption

The topic of implementing SSL and data encryption within a Web service is beyond the scope of this book. Each of these topics properly done would consist of several healthy-sized chapters.

However, several resources on the Internet exist to help users. For using SSL and Apache SOAP together, two resources that could be of help exist. The first one is a nice beginning article found on the Apache SOAP site at http://xml.apache.org/soap/docs/install/FAQ_Tomcat_SOAP_SSL.html. This article will walk a user through setting up Tomcat and Apache SOAP to work together with SSL. The second resource is the soap-user list. Many other programmers are using SSL and SOAP, and unfortunately the combination isn't always a smooth path. For solving problems with SOAP and SSL, visit the soap-user list archive at http://marc.theaimsgroup.com/?l=soap-user&w=2&r=1&s=SSL&q=b. In the archive, just type SSL as the search parameter. The resulting information will give you a good idea of the problems other users are encountering when setting up and using SSL.

In terms of encryption, the Microsoft MSDN site has an interesting article on the subject. The link can be found at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspnet/html/asp09272001.asp. This article is currently one of the few references to this particular subject. Although it is a good starting point, it has drawbacks. The first one is that the article isn't complete and is merely a starting point for the subject. The second drawback is that the example is written toward .NET and C#. However, it's still a good place to start reading on the subject.

Using Cocoon

The second topic is the concept of expanding JSP in yet another way, using Cocoon. Cocoon is a topic that deserves its own book. From this book's perspective, Cocoon offers a unique way to expand JSP. A Web application serves up data. This data can be in many formats. However, in addition to different destination formats, we have to consider the fact that different servers exist to generate the results. As an example, Cocoon is a Java publishing framework optimized for handling XML files for publication. It's possible for us to integrate Cocoon into our JSP applications.

NOTE

Cocoon can be found at http://xml.apache.org/cocoon/.

For questions about using Cocoon, the best place to go is the Cocoon user list. This list can be found at http://marc.theaimsgroup.com/?l=xml-cocoon-users&r=1&w=2.

Overall, Cocoon is a very robust project that will not go away. For programmers interested in using XML and XSL to aid in Web publishing, Cocoon is worth examining. Because Cocoon is a servlet-based application, it's possible to get Cocoon and JSP to work together. In setting up, you can get the two tools to work side by side or in conjunction with each other, depending on your needs.

The point is that Cocoon is built specifically for dealing with large sites of XML files. As a result, it has plenty of optimized XML handling for our Web applications to take advantage of. Cocoon ends up being another large tool set to expand our JSP applications into new territories.

Summary

This chapter serves as a source of some old and new ideas. Dynamic JSP introduces a method to automate handling XML and Web services. This automation can be used to great effectiveness in optimizing JSP pages to perform quickly when accessing data that doesn't change often. In some respects, this chapter applies the concept in a manner similar to old batch processes of the mainframe days. However, the idea is far more powerful. Using it as a batch process is only one of many ways that it can be applied effectively in a Web application. Dynamic JSP is a method to create code that can grow with changing conditions.

Next, the chapter covered a basic topic of security. You saw how to implement some security features to help protect a Web service server. Interestingly enough in the discussion, we also talked about servlet filters. Although servlet filters are used for security in this chapter, filters can have other uses with XML.

We hope that you have found this book both useful and informative. Writing a book such as this is an intense process. Many months of sweat, tears, and plain hard work went into this tome. We found for every topic written, there were two other topics we wanted to explore. However, only so much time can be allocated to write a book, so this is the final result. Thank you for reading our book. May your time using XML and Web services in your JSP projects be enjoyable.

CONTENTS


JSP and XML[c] Integrating XML and Web Services in Your JSP Application
JSP and XML[c] Integrating XML and Web Services in Your JSP Application
ISBN: 672323540
EAN: N/A
Year: 2005
Pages: 26

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net