Comments
Richard Davies wrote: The UK has a good crop of technology pioneers in cloud computing - for example ElasticHosts, FlexiScale, Flexiant, OnApp - and also some strong government initiatives such as G-Cloud. We will have to see whether this kind of technical leadership converts into swift mass-market adoption or not.
Cloud Expo on Google News

SYS-CON.TV
Cloud Expo & Virtualization 2009 East
PLATINUM SPONSORS:
IBM
Smarter Business Solutions Through Dynamic Infrastructure
IBM
Smarter Insights: How the CIO Becomes a Hero Again
Microsoft
Windows Azure
GOLD SPONSORS:
Appsense
Why VDI?
CA
Maximizing the Business Value of Virtualization in Enterprise and Cloud Computing Environments
ExactTarget
Messaging in the Cloud - Email, SMS and Voice
Freedom OSS
Stairway to the Cloud
Sun
Sun's Incubation Platform: Helping Startups Serve the Enterprise
POWER PANELS:
Cloud Computing & Enterprise IT: Cost & Operational Benefits
How and Why is a Flexible IT Infrastructure the Key To the Future?
Click For 2008 West
Event Webcasts
A Practical Solution for the Deployment of JavaServer Pages
A Practical Solution for the Deployment of JavaServer Pages

Sometimes it's worthwhile to go back and visit your former projects. It certainly was for me - using presentation as a commodity to be deployed according to network configuration is the concept that resulted from my visit.

The original assignment was to reduce the operating costs of a large banking agency network. How could this be achieved with a network of 23,000 personal computers scattered over 2,000 sites connected by a frame relay with a guaranteed bandwidth of 32Kb? We selected an intranet solution that radically reduced PC client/server applications to a single local program, the browser. To reduce bandwidth needs we deployed one Web server per site to perform only three tasks - handle presentation, maintain reference data, and invoke central system applications. This intranet design saved money by reducing the number of machines to operate from 23,000 to 2,000 by allowing them to be operated with a browser.

We can implement this concept to reduce the load of central farms with Java and J2EE because a fast local loop isn't always available. My goal, however, is to show specifically how we can do it better. The aforementioned approach didn't support a Web server's update on the fly and we had to contend with the central system's synchronization. The solution I present here addresses these issues by allowing Web servers to download their presentations the way browsers download applets. Figure 1 illustrates a possible organization. Let's summarize what we would need:

  1. Inexpensive Java servers able to host JSPs and servlets
  2. An API allowing them to invoke central system applications
  3. A simple way to download a presumably large number of Java servers from any number of central repositories

The first two requirements can be fulfilled with off-the-shelf products, and the local Java server has to address only the following three requirements: Generate presentation Invoke central applications Maintain reference data At least two Open Source products meet these needs: Tomcat                                                                                                   . ( http://jakarta.apache.org/downloads/binindex.html) and Resin (www.caucho.com/download/index.xtp).

EJBs, Remote Method Invocation (RMI), or Java Message Service (JMS) can be used as the API to connect to central systems.

The last point, presentation downloading, implies development. This requires more explanation and thought and is the core of the article. Presentation downloading relies on a Java class loader and leverages on JSPs and servlets specifications, which I'll present first.

Standard
The Java Servlet Specification v2.2 defines a Web application as a collection of HTML pages, servlets, and classes that exists as a structured hierarchy of directories. The root of this hierarchy is the document root that serves files such as images or HTML. If your Java server waits for HTTP requests on www.iamakishirofan.com and you defined your Web application as gunnm, your users will be able to invoke zalem.html, stored at the root with the URL www.iamakishirofan.com/gunnm/zalem.html.

A WEB-INF directory contains a web.xml file that describes, among miscellaneous things, servlet and JSP definitions, initialization parameters, mapping to URL, and security constraints. It can also contain a classes subdirectory in which classes, servlets, taglibs, JSP invoked beans, compiled JSP, and more are stored. A Web application should be packaged in a .war file - the JAR archive of the hierarchy.

This packaging is convenient as it gathers all related components in a single delivery. It has another important property: all servlets and JSPs of a .war are served the same ServletContext, which is different from the ServletContext of other packages. Servlets and JSPs can use this ServletContext to access .war data, such as resources and initialization parameters, or to store and retrieve application-wide attributes.

The servlet container loads and instantiates servlets. It initializes them before their first use by calling their init() method with an object that implements the ServletConfig interface. This provides access to servlet-specific data. When it decides to unload a servlet, the container invokes the servlet destroy() method and unreferences it. Each time the container has to route a request to a servlet, it invokes the servlet's service() method.

A compiled JSP is a servlet, even if it doesn't extend HttpServlet or GenericServlet as a normal servlet but as another class that's application server dependent. In the case of Resin, it's com.caucho.jsp.JavaPage and with Tomcat, org.apache.jasper.runtime.HttpJspBase. As you can see, compiled JSPs are no longer portable even if there are only minor differences. The specification requires a JSP to implement a standard HttpJspPage interface. A JSP indirectly handles container requests as depicted in Figure 2.

A compiled JSP implements a _jspService() method and, optionally, a jspInit() and a jspDestroy() method. The specification implies that, for instance, when the container invokes Servlet.init(), jspInit() is invoked somewhere in the implementation of the JSP base class. I've provided the Tomcat implementation in Listing 1. All Java servers I tested have similar code.

Choices
Back to our requirement - the solution I want to implement involves four participant types:

  • Browsers: Submit HTTP requests
  • Java servers: Process presentation and download the JSPs and servlets from a repository
  • Repositories: Must be accessed with a URL. A suitable repositories list includes HTTP servers as depicted in Figure 3 and FTP servers
  • Java application servers: Process EJB requests
I need to implement a piece of code in the Java server that's able to seamlessly retrieve JSPs and servlets from a central point, cache them, and support remote update. The solution depicted in Figure 3 is just common sense: I define a special servlet, JSPservlet, and package it in a .war file to handle all requests targeting its Web application. This servlet is responsible for loading target JSPs and servlets and forwarding them requests. To minimize data transfers, I handle archives (.jar) files only and cache downloaded archives, not only in memory but also on disk to survive a scheduled shutdown or a crash.

To simplify the development I don't handle JSP compilation. It doesn't mean the solution doesn't support JSPs, only that they have to be precompiled, not a real drawback. Compiling JSPs is the only safe way to ensure a JSP can compile, and I prefer to avoid downloading failing code. I also don't support single thread servlets that guarantee only one thread at a time will execute through a given servlet instance's service() method. The support of this feature would require instantiating a new target servlet when already created target servlets are processing a request. It would add complexity to the logic and have an adverse impact on scalability.

Listing 2 shows the deployment descriptor (web.xml) of the JSPservlet application and how to define that a JSPservlet must handle all requests targeting the application. You specify in <servlet-mapping> <url-pattern>/</url-pattern>, not <url-pattern>*</url-pattern> as you'd expect. Note that I use <init-param> to set every machine-dependent parameter. Deployers can then modify them to accommodate different installation and operating system requirements. cachePath is the directory in which downloaded JARs are locally stored, and remoteLocations indicates a property file in which remote locations are defined. For instance, if a JAR file named myjar must be downloaded from an HTTP server www.mysite.com, remoteLocations will contain an entry myjar=HTTP://www.iamakishirofan.com.

Implementation
Let's look at the class diagram in Figure 4. You see the aforementioned JSPservlet that relies on a JSPhandlers HashMap of JSPhandler. There's a JSPhandler instance per application that reads parameters and maintains ClassEntry objects, one per archive. ClassEntry maintains a target servlets cache and a JSPloader instance.

JSPloader is the class loader itself and maintains a class cache. It's also responsible for saving locally downloaded archives.

We can now see how the solution works. The Java server calls JSPservlet service(). To know which servlet is requested, JSPservlet.service() uses the request object. It first finds the appropriate JSPhandler with getHandler(), passing the application name it retrieves using the request getContextPath(). Then it gets a reference on the target with JSPhandler.get(), passing the path to the target returned by the request getPathInfo(). Eventually it uses this reference to invoke the target object service() method. As you can see in Listing 3 that's all for JSPservlet.

Listing 4 shows the implementation of JSPhandler. Its constructor retrieves parameter values from web.xml using ServletConfig. getInitParameter() and restores remote location properties from their persisted state. I chose to use the first part of the path as the archive name and the remaining part as the class name. Given the URL www.iamakishirofan.com/gunnm/ gally/nano/machine, if the application server is configured with the JSPservlet application on gunnm, ContextPath will be gunnm, the archive will be gally, and the servlet path in the archive, nano/ machine.class. This may seem a bit rough compared to the Web application flexible mapping but it's simpler to administer and implement. So JSPhandler.get() parses the pathInfo string and uses the archive part to find the corresponding ClassEntry in classEntries HashMap. It creates a ClassEntry if the search fails and invokes its get() method.

Now we can look at the ClassEntry implementation in Listing 5. Its constructor creates a JSPloader. Its get() method first tries to get the target servlet from its instance cache, servletObjects. No matter how many times a servlet is invoked, a single object is used and reused. If the object doesn't exist yet, it uses JSPloader to retrieve its class, invokes Class.newInstance() to instantiate it, and Servlet.init() to initialize it. It's extremely close to the Java server's implementations.

Class Loader
Before diving into the last and most complicated piece of code, JSPloader in Listing 6, let's recap what a class loader is and what our class loader is supposed to do. A class loader is an object responsible for loading classes. Given the class name, it can generate or load its binary code. It inherits from ClassLoader, which provides methods you can override (loadClass is the most flexible method). ClassLoader also implements a service method, defineClass, that converts the binary code in the Java class and resolveClass that links it. JSPloader must load classes from JAR files located either in the cachePath or at a URL.

Back to our example: it retrieves the archive from the local cache in cachePath/gally.jar or downloads it from a URL, which is the value of a gally property persisted in remoteLocations. In addition, when JSPloader downloads an archive, it must save this archive in its local cache, cachePath/gally.jar.

I prefer loading classes in a JSPloader constructor to minimize disk and network access duration and numbers. Another advantage is that forced loading can be performed outside peak hours by an administration JSP. JSPloader will then deliver a better response time as classes are already in memory. I found the memory use - same order of magnitude as the size of a downloaded archive - wasn't a showstopper. Note that I link a class only when requested, and ClassEntry instantiates objects only once, when they're first requested.

The JSPloader constructor tries downloading the archive from the local cache with loadClassDataFS() and then from its remote location with loadClassDataURL(). Both methods build a JarInputStream from an input stream that loadClassDataFS() gets from a FileInputStream and loadClassDataURL gets from a URL.openStream(). Since the JarInputStream handling is the same, I implemented it in a parseStream method.

parseStream loops around JarInputStream.getNextJarEntry(), which reads the next JAR file entry and positions the stream at the beginning of the data. Once parseStream has a JAR entry, it gets its name with JarEntry.getName() and uses a BufferedInputStream to read it. Then it converts it to a class with ClassLoader.defineClass and stores it in a classes memory cache. When it has to locally store a remotely downloaded archive, it uses a JarOutputStream; each time it's read an entry it rewrites it using JarOutputStream. putNextEntry() and JarOutputStream.write().

loadClass is invoked with two arguments, the name of the class and a boolean, resolve, that indicates if the class must be linked. Here I use the passive mode on purpose. Who invokes loadClass()? It depends. When ClassEntry invokes loadClass with the class name only, no magic happens. ClassLoader implements a loadClass(name) method that invokes loadClass(name, false). But the loaded class is associated with a JSPloader instance, which becomes the current class loader. If the loaded class uses another class, the Java Virtual Machine (JVM) will invoke JSPloader.loadClass to load it. This is why JSPloader.loadClass delegates class loading for the classes it doesn't find in its classes cache to the system class loader and its parent through the loadForward method.

The JSPloader.loadClass also delegates in two other interesting cases. If the class name starts with "java.", ClassLoader refuses to create it for security reasons. So I don't even try. The other case is "javax.servlet.Servlet". ClassEntry casts the target object it creates in a servlet. As I said, every class is associated with a class loader instance. In fact the JVM maintains the uniqueness of class_name, class_loader_object and not of class_name alone. So a cast of an object of class A loaded by class_loader_object1 to the same class loaded by class_loader_object2 fails. Therefore I check javax.servlet.Servlet and don't risk loading it from the archive.

Considerations
The order of the search has an obvious security impact. I prefer trying the class's memory cache first for speed and flexibility: I really depend on the Java server JDK for Java. I can download anything else, including the EJB, JMS, or RMI library code, but it has a security impact. If you don't trust your remote location, it's safer searching locally first.

My code is reasonably close to JDK 1.1 code: just replace HashMap with Hashtable and JarInputStream with ZipInputStream to run it with JDK 1.1. If local caching and JDK 1.1 have no value for you, consider URLClassLoader as an alternative to JSPloader. However, it's not really optimized for server-side use and you'd probably prefer the compatible NetworkClassLoader of Harish Prabandham provided in Tomcat. Its design is similar to JSPloader but instead of caching defined classes, it caches class data.

In Part 2 I'll describe how to handle images, support Web applications without restriction, and require updates from a browser. In Part 3 I'll demonstrate how to host downloaded classes in a sandbox, such as applets.

Conclusion
Through the class loader comprehensive mechanism it's easy to write a tool that's able to download servlets and JSPs from a remote location. It's even relatively easy to make it portable, though Java servers are probably the most hostile environment since they use class loaders intensively.

The idea probably has value for corporate intranets and B2Bs. Assume company B wants to provide access to its Web application to company A, which maintains a Java server. It simply configures its server to automatically download the code from B to enjoy reduced communication bills and better response time. It's a win-win situation since B doesn't have to process presentation. Now suppose A has many partners. As each downloaded archive is processed by a different class loader instance, it can use the same class names without collision. If A uses a different Web application for each partner, the partners won't share the same context. And A partners don't even have to know about A's Java server host and operating system. However, its real potential may be elsewhere.

If we could define a standard describing how to require a download and from where - for instance with XML over HTTP - even ISPs could host pages. Presentation would become a commodity like routing or a name service.

About Alexis Grandemange
Alexis Grandemange is an architect and system designer. A Java programmer since 1996 with a background in C++ and COM, his main interest is J2EE with a focus on design, optimization, and performance issues.

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Latest Cloud Developer Stories
Rackspace Hosting, the service leader in cloud computing, on Thursday announced its acquisition of SharePoint911, an industry leader in SharePoint consulting, training, and "JumpStart" services within SharePoint. The unification of both companies provides capabilities to deliver ...
With Cloud Expo 2012 New York (10th Cloud Expo) now under four months away, what better time to start introducing you in greater detail to the distinguished individuals in our incredible Speaker Faculty for the technical and strategy sessions at the conference... We have techn...
Nimble, the social CRM platform has announced the launch of Nimble 2.0, billed as the “most social” CRM platform on the market today. Nimble was designed entirely with social CRM in mind and is the first social business platform that empowers companies with the ability to get clo...
2011 was a year of rapid adoption for public and private cloud services. Instant and on-demand server provisioning was the driving force behind the massive growth. On top, cloud server templates and script automation simplified application installation for simple and pre-defined ...
"Having been in the IT field for many years, I believe the cloud computing chapter in the industry is an exciting one and I am proud to be a part of it," said National Reconaissance Office (NRO) Chief Information Officer Jill T. Singer Tuesday, as it was announced that she was on...
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON Featured Whitepapers
ADS BY GOOGLE