Home Contact

  Developing Applications with Java & ASP

 

News
Papers & Publications
Download Area
Resume

Developing Applications with Java, IIS, and ASP

by Robert Zembowicz (http://www.robertz.com)
March 1998

This paper is reproduced with permission of Information Communications Group. Copyright 1998 Informant Communications Group. For more information, please visit http://www.informant.com or http://www.javaconference.com.

Abstract

This paper introduces Java developers to building complex, distributed, multi-tier systems using Visual J++, Active Server Pages, and IIS. It starts from explaining how a simple ASP component can be written in Java and ends with presenting architecture for supporting complex, distributed, multi-tier Web systems. The presented architecture allows for both ultra-thin clients (HTML, D-HTML, and Java applets running in a browser) as well as more traditional, full-function clients (like stand-alone WFC or AFC applications developed with Visual J++).

This presentation also discusses the issues of how to maximize the re-use of code common to different kinds of clients and servers. This can be achieved by introducing the layer of service objects that can be used by GUI components of the full-function client and thus execute on the server, as well as by non-GUI Java components instantiated on the Web server by ASP.

Table of Contents:

1. Introduction
    1.1 Briefly about ASP and ASP Components

2. Your First Java ASP Component
    2.1 Writing ASP Components in Java
    2.2 Registering Java Classes as ASP Components
    2.3 Calling Java from ASP Script

3. More Advanced ASP Components
    3.1 Going Beyond OnStartPage
    3.2 Storing Reference to the Context Object
    3.3 Retrieving Parameters Passed to the Page
    3.4 Working with the Response Objects
    3.5 Initialization of Static Fields
    3.6 OnEndPage: Cleanup of Resources
    3.7 Debugging ASP Scripts and Components

4. Architecture for Complex Distributed Systems
    4.1 The Need for Architectural Solution
    4.2 Overview of the Architecture
    4.3 Traditional Client Support
    4.4 Web Client Support
    4.5 Background Job Support
    4.6 Business Objects and Services Layer
    4.7 Error Handling

5. Evaluation and Summary
    5.1 ASP Java Component Framework
    5.2 Using MTS
    5.3 Another Use of ASP
    5.4 Why not Java Applets Instead of ASP?
    5.5 Pros and Cons of Java on Web Server

Appendix A: Checklist for Developing Java ASP Components

Appendix B: Checklist for Developing ASP Pages

1. Introduction

Active Server Pages (ASP) is a relatively new technology that significantly simplifies developing Web applications that require executing scripts or programs on the Web server side. Recently, with the introduction of IIS 4.0, Active Server Pages was integrated with the Microsoft Transaction Server (MTS).

1.1 Briefly About ASP and ASP Components

For normal HTML pages, when a Web browser requests a page, the Web server’s responsibility is to retrieve the corresponding file and hand it over to the browser. Then the browser interprets HTML tags to render the page and eventually executes scripts, if any. In this traditional approach, scripts are executed on the client’s machine that runs the Web browser.

Active Server Pages are processed differently. First, scripts marked in a special way are executed on the Web server before the page is handed over to the browser. Second, scripts can invoke ActiveX objects called ASP components. Both scripts and components have access to parameters that were passed to the page, cookies, etc. Finally, bodies of server-side scripts in the original file are replaced with the output they produce and the resulting page is sent to the browser.

ASP files are very easy to write because they are basically HTML files that allow for placing scripts that execute on the server. This means that once you know how to create regular HTML pages, you should have no troubles learning how to create ASP pages. ASP extends HTML by adding new delimiters for designating where server-side scripts begin and end; these delimiters are <% and %>. The script you place in between these delimiters can be written in either VB Script or JScript, whichever you prefer (there is a number of add-ons for other scripting languages, too). Since the script is replaced by the output created by the script and/or ASP components it invoked, you need to remember to format the output as HTML.

The ActiveX object that is used as an ASP component could designed in several ways. One possibility is to develop a simple COM server that knows nothing about ASP. In such cases, it would be the script’s responsibility to get the data from the COM server, format it as HTML, and write it to the special ASP "response" object. You can use this approach when the output that the ASP component returns is small and simple.

Second possibility is to write an ASP-aware COM server that would connect to the ASP response object and then send the output directly to it (again, it needs to be in HTML format). As a Java developer, you will probably prefer this way, as it gives you more flexibility in producing the output.

Since ASP components are simply COM/ActiveX components, the developer automatically has access to all COM-based goodies, including DCOM and Microsoft Transaction Server. After proper registration with DCOM, the ASP component instantiated by an ASP page can actually execute on another machine. Additionally, the Microsoft Transaction Server (MTS) could manage ASP components to ensure that all involved components succeed or all of them fail. In IIS 4.0, MTS can also manage the ASP scripts directly: the script as well as all started components and all accessed databases can execute within a single transaction.

2. Your First Java ASP Component

2.1 Writing ASP Components in Java

ActiveX components that can be invoked from ASP scripts can be implemented in any programming language that supports developing COM servers. However, it is especially easy when you use Visual J++ and Microsoft’s Java VM. What makes it so easy is the Microsoft’s VM for Java that can expose any public Java class as a COM or even DCOM server. The only thing you have to do is to write the class and properly register it. The latter one could not be simpler: you just use the javareg utility provided in the SDK for Java.

As an example, let’s write the Java ASP version of the classical "Hello, World" program. Here it is:

package vjdc;

import com.ms.asp.*;
import com.ms.com.Variant;

public class HelloWorld {
  public void OnStartPage(IScriptingContext aspContext) {
    aspContext.getResponse().Write(new Variant("Hello, World!"));
  }
}  

When an ASP script instantiates our HelloWorld server, the OnStartMethod will be automatically called by the ASP system. This method is very important because it gives us a way to connect to built-in ASP objects, especially the response object that is used to prepare the output that the client will see. OnStartPage is given the context object as its parameter and you can use this object to access other ASP objects. In the example above, this context is used to retrieve the reference to the response object that is given our "Hello, World!" string to write. Please note that the string is actually passed as a COM Variant object, which should not be a big surprise: we are in the COM world here…

IIS 4.0 comes with ASP Java Component Framework, which contains a number of classes that simplify developing ASP components in Java. The Java Component Framework classes are very similar to ASP native classes and interfaces presented here, but encapsulate the use of COM by providing methods that use pure Java types. See the Summary section for more information on the Java Component Framework.

2.2 Registering Java Classes as ASP Components

Before our object could be created as an ASP component, we need to register it properly on the Web server. Once you compile the Java class shown above, you need to run the javareg utility provided in the SDK for Java 2.x. Here is how you do it:

javareg /register /class:vjdc.HelloWorld /progid:vjdc.HelloWorld  

Let’s look at the arguments in the above command line one by one. The /register option tells the javareg program to register the given Java class; you can use /unregister option to clean the registry once you are done with the HelloWorld class. The /class option let’s us specify what Java class is to be registered; you need to provide the fully qualified class name here, including the package path. Finally, the /progid option gives us the possibility to assign name to our server that can be used later to invoke it.

The last thing we need to do is to place the compiled Java class in the location where the Virtual Machine would be able to find it. Why can’t you just modify your CLASSPATH? You need to remember that your class would be executed by the VM which, in turn, is started by the ASP system. The ASP system is a part of IIS that is started by the NT system with the special, dedicated userid. Setting the environment variables for this dedicated user is not easy. Fortunately, there is a very easy solution: Microsoft’s VM will always search the TrustLib directory (in winnt\java) for classes. Therefore you can just copy HelloWorld.class into winnt\java\TrustLib\vjdc directory and you are done!

2.3 Calling Java from ASP Script

Once you have your Java ASP component properly registered and placed in TrustLib, you can invoke it from an ASP script. Here is an example that would instantiate the HelloWorld class presented above:

<% Set MyComponent = Server.CreateObject("vjdc.HelloWorld") %>  

This is all what you need to activate our HelloWorld object. When our component is instantiated by invoking the Server.CreateObject method, the ASP system will call OnStartPage method passing the ASP context object to it, which in turn will result in writing the "Hello, World!" string into the response object. Finally, when done with the script, IIS will replace everything in between <% and %> delimiters, including the delimiters, with the output collected by the response object.

3. More Advanced ASP Components

The example presented in the previous section demonstrated elementary steps required to write a very simple ASP component. In the real world, however, you will need to know a little bit more to be able to use all the power provided by Active Server Pages.

3.1 Going Beyond OnStartPage

Putting all the component’s functionality inside the OnStartMethod, as in the case of our HelloWorld example, is not the best solution in the real world. A natural question to ask is how one can invoke other Java methods from a script. Fortunately, Microsoft’s Java VM automatically provides the IDispatch interface support for all public methods and fields, which means that they will be accessible from an ASP script.

To invoke a method defined in your Java class, the method must be declared public. Additionally, the type of the method’s parameters and returned value must be one of the following:

bulletJava built-in type
bulletVariant type (specifically, com.ms.com.Variant)
bulletA public class that was also properly registered using javareg.

For details on how types are mapped between Java and COM, consult Visual J++ documentation.

For fields to be accessible from an ASP scripts, they also need to be public and of one of the types listed above.

Another nice feature of the Microsoft’s Java VM is its ability to expose derived properties that do not have the corresponding public fields. The VM uses the Java’s reflection mechanism to examine the class. If it finds the get and set methods that follow the JavaBeans naming convention, it exposes them as attributes (after removing "get" and "set"). Let’s look at the following example.

package vjdc;

public class Cube {
  protected int m_edgeLength = 0;

  public int getEdgeLength() {
    return m_edgeLength;
  }

  public void setEdgeLength(int length) {
    if (length >= 0)
      m_edgeLength = length;
  }

  public int getVolume() {
    return m_edgeLength * m_edgeLength * m_edgeLength;
  }
}  

When this class is properly registered, the VM will find and expose two properties: edgeLength and volume. In the script, one can access these two properties directly:

<% Set cube = Server.CreateObject("vjdc.Cube")
cube.edgeLength = 13
Response.Write cube.Volume %>  

The access to the m_edgeLength is shielded through the get and set methods; in particular, the set method doesn’t allow for setting the edge length to a negative value. Please also note that the volume is a read-only, computed property.

3.2 Storing the Reference to the Context Object

If your ASP component is to produce a lot of output or needs to access built-in ASP objects, you should store in a local field the reference to the ASP scripting context object when ASP system calls your class’s OnStartPage. The following class shows a typical implementation of the OnStartPage method.

package vjdc;

import com.ms.asp.*;

public class AspComponent {

  private IScriptingContext m_Context;

  public void OnStartPage(IScriptingContext aspContext) {
    setAspContext(aspContext);
  }

  protected void setAspContext(IScriptingContext aspContext) {
    m_Context = aspContext;
  }

  protected IScriptingContext getAspContext{
    return m_Context;
  }
}  

3.3 Retrieving Parameters Passed to the Page

One of the largest benefits of using ASP is the ease of accessing data received from the user. Data can come to ASP page from several different sources:

bulletfrom an HTML form passed with the form’s post method
bulletfrom an HTML form passed with the form’s get method
bulletfrom cookies passed from the user’s browser
bulletfrom client’s certificates
bulletfrom the server variables
bulletfrom the session object that can hold the data related to current user
bulletfrom the application object that can hold the data common for all users

Have you ever developed CGI scripts or programs? If you have, you will really appreciate the way in which all of the above data is accessed in ASP.

ASP has a number of so-called built-in objects that you can talk to. In Java, they are accessible through the scripting context object. The following is a quick summary of what data can be retrieved from the ASP built-in objects.

bulletThe Request object: used to get the information from the user, including data from the form (submitted with either get or post), cookies, certificates, and server variables. Examples:
bullet
getAspContext().getResponse().getForm().getItem(...)       
bullet
getAspContext().getResponse().getCookies()       
bulletThe Session object: used to store and get the information per user session; one script or component can put some data that another component can retrieve later. Each piece of data stored in the session object is accessed through a key (string of characters). Example:
bullet
getAspContext().getSession().putValue(...,...)       
bulletThe Application object: used to store and retrieve information common for all users; data stored by one script for a particular user can be later recalled by another script executed for another user. Again, each piece of data stored in the application object is accessed through a key. Example:
bullet
getAspContext().getApplication().getValue(...)       

There are two levels at which you can access the above data. First is at the script level: before invoking methods in an ASP component, in the script you can get the data and pass them as parameters to your component. When the component is done with processing, the script can get retrieve some results and store them in the session or the application object, if needed. The second solution is to access the data directly from the component: you can get access to the built-in objects through the given scripting context object.

Which approach should be used? If you want to use the same component in several different places, it might be better to get the data in the script and pass them to the component as parameters. This way your ASP component will not depend on the source of the data – once the system is in production, it is much easier to modify scripts then the components. But this is not always the best solution. If you have a large form being processed by an ASP component, the script would have to be very long. When the form is to be changed, you would have to make the changes in three places: the form, the script, and the ASP component. In such cases, simply access all the data directly from the component.

3.4 Working with the Response Object

The ASP response object collects all the output you write to it and gives it to IIS as the replacement for the script’s body. In the default situation, the response object takes whatever is passed as a parameter to the Write method and immediately forwards it to IIS to be sent to the requesting Web browser. It means that, if your components need a lot of time to execute on the server, the user’s browser will get the output in increments as soon as ASP scripts and components produce them. This might be want you want in many cases, because the user will at least see some output when waiting for the rest.

You can change this behavior by telling the response object that it should collect all the output in a buffer and send it to IIS (and client’s browser) only upon completion or when explicitly requested. In this approach, the user will see nothing until all scripts complete, or until your script or one of the components calls the Flush method.

Why would you like to do it and let the user wait? There are two important cases here. First, the buffer can be cleared without sending its contents to the user’s browser. This means that when, for example, your component detects a special situation after some output was already sent to the response object, it can clear the buffer:

  getAspContext().getResponse().Clear();  

and replace it with a special message.

Second, if no output was sent to the user’s browser, the script or component can re-direct the browser to another location:

  getAspContext().getResponse().Redirect("LoginError.htm");  

This is particularly useful when an error or another abnormal case was detected and another page needs to be displayed in place of the requested one. Imagine, for example, that you need to provide users with secure login to your pages. One, regular HTML page can have a form with username and password fields. The values entered are then sent to ASP page, whose component checks the validity of the user’s ID and password. When the validation fails, the user’s browser can be directed back to the login page, or to another page that informs the user of the problem.

3.5 Initialization of Static Fields

Some static fields need to be initialized only once. If this initialization can be handled in the static initialization block, or if the initialization can be safely done several times, then you don’t have to worry about it. However, if your code needs to call a static method to perform the initialization only once, you need to be very careful. The reason is that your ASP component is instantiated, some of the classes could be already loaded into VM and initialized during one of previous instantiations of this or another component. This can be easily resolved by performing lazy initialization, as in the following example.

  protected static boolean m_Initialized = false;

  public static void initializeClass() {
    synchronized (m_Initialized) {
      if (! m_Initialized) {
        // place initialization code that
        // can be executed only once

        // mark that the initialization was done
        m_Initialized = true;
      }
    }
  }  

Please note that since we might have many clients accessing the same .asp file, the body of the method is synchronized for the static variable to ensure that the initialization happens really only once.

3.6 OnEndPage: Cleanup of Resources

What if your Java ASP component uses some resources that need to be released after the component is no longer needed? Fortunately, there is an easy solution here. When the component is instantiated by calling Server.CreateObject method, the component's OnStartPage is called. Similarly, when the component is no longer needed, ASP system calls the OnEndPage method. OnEndPage method is a perfect place to release all the resources used by the component.

3.7 Debugging ASP Scripts and Components

ASP gives you nice environment for developing complex Web systems. However, the number of bugs grows with the complexity of the system. How can you debug your ASP scripts and components? This is not easy so easy with IIS 3.0, especially considering the fact that the Java VM that executes your ASP components is started by IIS under a dedicated user ID. It means that you can’t easily attach to VM and debug your classes – you can’t even send debug stuff to System.out because there is no console window to display the output.

IIS 4.0 can also be started as a normal, stand-alone Windows application, which greatly helps with debugging but still doesn't answer all the debugging needs. Currently, IIS 4.0 can help with debugging Java applets running on the client, but the support for debugging Java ASP components is still limited.

The new, enhanced debugger in Visual J++ 6.0 is capable of attaching to VM running on this or even other machines, which will greatly help in debugging.

Is there a way out here? Yes, if your scripts are written in VB Script.

Ladies and Gentlemen, Start Your VBA Engines…

As a Java developer, most likely you would prefer to write all your scripts in JScript rather than VB Script, but you may change your mind when you try to debug your system. VB Script is a subset of VBA, the Visual Basic for Applications. VBA is included, for example, in Microsoft Excel, which also comes with a simple VBA debugger. Your ASP components are just COM objects, so they can be instantiated from VBA, too. Now you can see that all of the sudden debugging becomes easy, provided that your ASP scripts are written in VB Script. When you have a problem with your script or components, copy the script to a VBA window in Excel and start the debugger.

The beauty of COM and Java VM comes into light once your component is created by the script and stored in a local script variable. Using the debugger, you can now see all public properties of your component, including those inferred from the get and set methods! You can even change the properties, which will result in changing the corresponding public field in your Java class or invoking the corresponding set method.

Capturing Output Sent to the Response Object

When you run your script from Excel, your components will fail when accessing the built-in ASP objects. However, resolving this issue is really simple because components access the built-in objects through Java interfaces rather than the actual classes. This means that you can just define your own classes that implement the corresponding interfaces.

Since these classes will be used only for debugging, you might not need to implement all methods for all interfaces, just the ones that are used by the component that requires debugging. On the other hand, once you implement the classes, make sure you keep them for future debugging sessions.

You will need to start from defining two classes, one implementing the IScriptingContext interface and one implementing the IResponse interface because these will be the most frequently used. Then you can add other classes when you need them.

Here is the example of the simplest class that implements IScriptingContext and answers the response object:

package vjdc;

import com.ms.asp.*;

public class AspDebugContext implements IScriptingContext {

  protected AspDebugResponse m_Response = new AspDebugResponse();

  public IRequest getRequest()               { return null; }
  public IResponse getResponse()             { return m_Response; }
  public IApplicationObject getApplication() { return null; }
  public IServer getServer()                 { return null; }
  public IsessionObject getSession()         { return null; }
}  

Similarly, you will need to implement the IRespone interface. Start with implementing the Write method that would capture the given piece of output so you could examine it. You can write given value to a text file, append it to a String field, or do whatever is convenient for you and easy to check. Here is an example:

package vjdc;

import com.ms.asp.*;
import com.ms.com.Variant;

public class AspDebugResponse implements IResponse {

  public String buffer = new String();

  public void Write(Variant v) { buffer += v.toString(); }
  public void Clear()          { buffer  = new String(); }

  // other methods from IResponse come here...
}  

Note that the buffer field is public, so you could easily examine it in the debugger (after you register AspDebugContext and AspDebugResponse classes with javareg, of course).

Finally, since there is no ASP system that could call the OnStartPage method passing the context object, you will have to call OnStartPage method by hand passing the instance of AspDebugContext. One possible way is to add a new field holding the context and a new public method to your Java ASP class and call it from the script, for example:

package vjdc;

import com.ms.asp.*;

public class MyAspComponent extends AspComponent {
  ...
  public debugContext;
  public void initDebug() {
    debugContext = new AspDebugContext();
    OnStartPage(debugContext);
  }
  ...
}  

In the script, you will need to add a call to the initDebug method just after the instance is created. Since the debugContext field is public, you will be able to see its contents in the debugger. Similarly, our implementation of the context class has the buffer field that also can be seen in the debugger.

Clearing Virtual Machine Cash

One more thing you need to know regarding debugging is how update Java classes on the Web server. The problem is that the Java VM cashes classes (this "problem" in testing mode is a huge benefit in the production mode) – if you simply copy new class files over older versions, the VM might still use the older version. When you work with IIS 3.0, the most reliable way of clearing the cash that I found is quite brutal: stop IIS for a moment, get a cup of tea or coffee, and restart IIS. In case of IIS 4.0, you can run IIS as a stand-alone application and simply stop and run it again.

Using Script Debugger in IIS 4.0

Debugging with the latest IIS 4.0 is simpler than with IIS 3.0, because IIS 4.0 comes with the Microsoft Script Debugger, which allows for debugging scripts running on the server. Scripts running on the client can also be debugged with the same debugger, because it works with IE 4.0. Therefore, if your scripts are not very complex, you shouldn’t have to run Visual Basic.

On the other side, the debugging approach presented above is still very useful, because it allows developers to test components locally before they are installed on the Web server as ASP components.

Another reason for emulating ASP classes as described in this section is that this approach allows for automated testing. You can create a database that will contain the data needed for a number of test cases. Then you can loop through all the records in the database, initialize the request object from the values read from the record, execute the script and components, and compare the produced response against the expected output.

You can now see that debugging ASP components is not that hard as it seemed to when we first looked at it. Basically, you need to prepare the debug environment that would emulate ASP by implementing your own versions of the needed ASP built-in objects and calling the OnStartPage and OnStopPage methods by hand. The rest is easy thanks to (i) Java VM, which can expose any public class as a COM object, (ii) Java language, which introduced interfaces, and (iii) VBA, which is usually easily available.

4. Architecture for Complex Distributed Systems

In the previous sections, you have learned how to develop simple, stand-alone ASP components. This section focuses on developing complex, multi-tier systems consisting of several components running on different machines.

4.1 The Need for Architectural Solution

If you work for a large, established company, like a financial institution or a utility company, most likely the application you are developing has to connect to the existing infrastructure. For example, you may have to extract data from several different sources, from modern databases to mainframe systems. It is also very likely that the same data would be used by different application. For example, there might be a "traditional", stand-alone client application used in a customer service as well as a Web application accessed by the company’s clients through Internet. Additionally, it is not uncommon to have a number of GUI-less jobs executed periodically in an automated way (like customer billing or verification of daily financial transactions).

A typical question that developers face in such environments is how to maximize the re-use of code, both on the client as well as pieces running on the server(s). Re-using the code on the client is not a simple issue because there are several diverse kinds of clients: an ultra-thin one in Web browser, traditional stand-alone fat client, and background, periodic jobs.

The architecture discussed in this section attempts to address all of the issues mentioned above, plus more:

bulletdifferent kinds of clients;
bulletre-use of code for different clients;
bulletdistributed, multi-tier environment;
bulletre-using the existing server transactions;
bulletclean separation of data access layer from client code;
bulletuniform, transparent error handling mechanism.

Figure 1 below shows a typical run-time configuration for a heterogeneous, distributed system that supports a number of different types of clients.

Figure 1. Physical view of the architecture: this UML deployment diagram presents a possible run-time architecture of a multi-tier, distributed system.

The example presented on the figure above identifies three kinds of clients:

  1. Traditional client: a stand-alone application ("fat" client).
  2. Web-based client: a set of HTML pages rendered by the client’s Web browser and ASP pages and ASP Components executed on the Web server.
  3. Non-GUI, background jobs running on an application server.

Let’s assume that all of these clients will be implemented in Java. In this example, each of the clients communicates with the transaction server through DCOM. The transaction server manages the retrieval and storage of data from/to multiple sources: modern relational databases as well as DB2 and COBOL jobs running on a mainframe.

4.2 Overview of the Architecture

Figure 2 presents the overview of the logical architecture that supports the above three kinds of clients.

Figure 2. Logical view of the architecture: major packages and dependencies between them.

The top layer consists of the specialized classes that are specific to each type of client. The middle layer provides the common services reused for all applications within this domain, including business services and business objects. Finally, the bottom layer provides general-purpose classes that are not specific to the business domain, like transactioning support, data access, GUI library, etc.

The reuse comes from the separation of the code specific to individual kinds of clients from all business logic code that was encapsulated into business services and business objects. Note that on the above diagram the middle layer classes are reused by all client types.

4.3 Traditional Client Support

Classes that support traditional, stand-alone clients are mostly GUI screens built on the top of your favorite Java GUI library. The GUI components receive data as encapsulated into business objects that shield the client code from the actual source of data. Most actions requested by the user are forwarded to the business service classes.

For the traditional client, a significant portion of the code resides on the client machine (whence the name "fat client"). Part of the data access layer (business objects or services) may also reside on the client machine and is responsible for retrieving the data either from a transactioning server or directly from the corresponding databases. Alternatively, some of those services may be executed on a remote machine through DCOM or MTS.

The front-end of the traditional client can utilize the Application Foundation Classes (AFC) or the latest Windows Foundation Classes (WFC) to create an advanced, modern-looking GUI.

4.4 Web Client Support

In the presented architecture, Web clients are supported through ASP components implemented in Java. In this approach, a client’s request is processed by an ASP page that uses a number of ASP components. ASP components use common business services and objects. Remember that ASP system runs on the Web server – the client gets only the output (that’s why it is called an ultra-thin client).

If the output is limited and can be easily tabulated, it can be sent to the user’s Web browser as an HTML page. For more complex cases, one can have a small Java applet running inside the client’s Web browser that receives the output from an ASP page and renders it, for example, in a graphical form.

To simplify developing ASP components in Java, introduce a base class that implements OnStartPage and OnStopPage methods and provides place holders for instance initialization and cleanup. The following code presents one of possibilities.

package vjdc;

import com.ms.asp.*;

public class AspComponent {

  private IScriptingContext m_Context;

  public void OnStartPage(IScriptingContext aspContext) {
    setAspContext(aspContext);
    initialize();
  }

  public void OnEndPage() {
    cleanup();
  }

  protected void initialize() {
    // empty implementation - may be redefined in subclasses
  }

  protected void cleanup() {
    // empty implementation - may be redefined in subclasses
  }

  protected void setAspContext(IScriptingContext context) {
    m_Context = context;
  }

  protected IScriptingContext getAspContext{
    return m_Context;
  }
}  

The OnStartPage method stores the reference to the ASP context and calls the initialize method. Similarly, OnEndPage calls the cleanup method.

Additionally, this base class will be very handy if you decide to switch to using the latest ASP Java Component Framework classes.

4.5 Background Job Support

In the discussed architecture, background jobs are implemented as Java classes executed periodically or per request. Again, those classes use the same common business layer as the traditional and Web clients.

4.6 Business Objects and Services Layer

Business objects and services is the key to reuse. Business objects encapsulate data stored in databases and retrieved through the data access layer. They represent the "logical" view of the data rather than physical: to extract data for a particular business object, sometimes several queries need to be ran against different persistent storage systems. By introducing business objects and services we can shield the client code from details like where the data is actually stored. This is particularly important when there is several very different kinds of clients that can present or work with the same data.

Business objects can be implemented as non-visible JavaBeans to simplify building GUI screens and connecting individual fields in the business object with the corresponding GUI controls that display them.

Similarly, all business logic can be encapsulated into business service objects. Those service objects are responsible for implementing all actions required by the business processes used by the company. Some of these services require data extraction, processing, and updating databases with new data. Other services may simply forward the action requests to other systems, like COBOL jobs running on a mainframe.

Frequently, a service is given business objects as parameters and/or returns a number of business objects as the output. In other words, it isolates the client code from knowledge how business objects are mapped to databases and what low-level actions are required to implement business functions.

In some cases, like in the example presented on the Figure 1, part of (or all) the code from this layer may be executed under a supervision of a transaction server, like MTS or Tuxedo, to ensure the consistency of the business data. In such cases, this layer would also hide from the client code all communications to/from the transaction server, which could be implemented through DCOM (for MTS) or other means.

4.7 Error Handling

The needs for uniform error handling are always obvious. However, when the same Java object can be executed as a part of a traditional client as well as inside an ASP component on a Web server, there is one more dimension to error handling. In a stand-alone application, an error box can be open to notify the user about the problem. In the case of ASP, error report may have to be written to the output HTML page or the user should be re-directed to another page. Background jobs should log all the problems in an external file or database. This means the actual error handling mechanism in use has to be transparent to all Java code.

This can be handled by introducing the ErrorManager class that holds onto the actual ErrorHandler object to be used. The UML diagram in Figure 3 illustrates this possible solution.

Figure 3. Class diagram for error handling classes.

The ErrorManager class has a static reportError() method and a static collection (vector) of error handlers. The abstract ErrorHandler class defines the abstract reportError() method, which each subclass needs to implement. When the top-level Java object that represents an ASP component is instantiated, it needs to initialize the error manager by specifying what error handler should be used. This could be done in the OnStartPageMethod, as in the following example:

  public void OnStartPage(IScriptingContext aspContext) {
    setAspContext(aspContext);
    setErrorHandler(new AspErrorHandler());
  }  

On the other hand, the application-level object for the traditional client should at the very beginning setup the error manager to use another error handler:

  public void init() {
    setErrorHandler(new AfcErrorHandler());
    // other application initialization code
  }  

Finally, in this example a background job would only use the LogErrorHandler:

  public void init() {
    setErrorHandler(new LogErrorHandler());
    // other application initialization code
  }  

The reportError() method of ErrorManager simply passes down the error message to the error reporter. In this scenario, errors are reported by calling ErrorManager.reportError(String message) without worrying what actual error handlers are in use.

5. Evaluation and Summary

5.1 ASP Java Component Framework

IIS 4.0 comes with ASP Java Component Framework, which is a small set of classes that isolate Java developers from working directly with COM interfaces (or, more precisely, Java wrappers for COM interfaces).

When you use the ASP Java Component Framework, you do not have to worry about OnStartPage, OnEndPage, and storing the reference to the ASP IScriptingContext. All this is done behind the scenes by the framework. When you need to use one of the ASP built-in objects, use the corresponding static method from the AspContext class:

public class AspContext {
  public static Request getRequest();
  public static Response getResponse();
  public static Server getServer();
  public static Session getSession();
  public static Application getApplication();
  public static IObjectContext getObjectContext();
}  

Each of the five first methods returns another framework class. The last method, getObjectContext(), enables you to work with Microsoft Transaction Server (MTS).

Debugging with Java Component Framework

Java Component Framework classes are easier to use because they work with native Java classes rather than COM interfaces. However, currently debugging is not easy because debugging Java components on the server is not supported yet - you need to wait for Visual J++ 6.0. Since AspContext methods return objects of specific classes rather than interfaces, the debugging approach presented in the section 3.7 is harder to implement.

If you really want to use the new framework but also want to have a way to debug your classes, here is a short summary of how to support debugging.

First, define your own interfaces for the built-in objects that have method signatures exactly as those provided by the corresponding framework methods.

Second, for each framework class that encapsulated a built in object, create a subclass that implements the interface, for example:

public class AspResponse extends Response implements IAspResponse {
  // all IAspResponse methods are already implemented in Response
}  

Note that the base class already implements the methods defined in the interface, therefore the actual class definition is empty.

Third, enhance the AspComponent class introduced in section 4.4 by providing methods that return the interfaces to built in objects and use them instead of direct calls to static AspContext methods.

Finally, when you need to debug you components, change the AspComponent class to return the debug versions of the ASP built-in objects. Of course, for each interface you introduced, you will have to define a debug class that implements it, for example:

public class AspDebugResponse implements IAspResponse {
  // implement all IAspResponse methods!
  ...
}  

This time you will have to implement each method defined in the corresponding interface, as it was discussed in section 3.7.

5.2 Using MTS

IIS 4.0 has been integrated with Microsoft Transaction Server. MTS can manage the execution of the whole ASP script: the script and components created with Server.CreateObject method can be executed within the same transaction.

New Java Component Framework classes also support MTS. For example, you have access to the MTS's object context.

For more information, please see the online documentation for IIS 4.0.

5.3 Another Use of ASP

This article introduced "conventional" use of ASP, where ASP application consists of .asp files containing scripts that activate ASP components, and the output produced by the scripts and components is presented by a Web browser. However, there is another possibility.

ASP pages are processed by IIS when a Web client requests them. This request could come from a Web browser that wants to download and display the page, or from a Java applet (or from any other application that attempts to open the ASP file). The former method was the base for this presentation. The latter one is a new approach. In this case, the Java applet (or any other program written in a language that supports access to files on the Internet, like VB, VC++, etc.) opens the page using HTTP protocol (possibly passing some parameters to it). At the point, the Web server processes the ASP page by executing all scripts and replacing them by the generated response text. Finally, the Java applet reads the output and presents it to the user. Most likely, you response text should come with no HTML formatting, as it will not be read and rendered by a Web browser. Instead, the output should be formatted in the form that is most convenient for the Java applet. Everything that was presented in this paper still applies, the only difference is who presents the data on the user’s machine.

One of the benefits of this approach is that the user is not send to another page, but rather sees the same page where the Java applet shows the data retrieved in "background".

5.4 Why not Java Applets instead of ASP?

One of the questions some developers ask is why not include the functionality of ASP components into an applet that would execute on the client’s machine. At first, this might sound like a reasonable solution, and in some cases this may really be a good approach. However, before you follow this path, please look at the potential problems enumerated below.

bulletSecurity: de-compiling Java code loaded by the Web browser reveals the source of and access method to data; this is especially danger when data is kept in Access or other simple files; it is less danger but still insecure when data is stored in a SQL Server or another RDBMS.
bulletSlow download time of large applet code: from a thin client approach we go back to traditional fat client where most of the functionality is performed on the client machine, which result in a large amount of code that needs to be downloaded from the Web server.
bulletProblems with direct access to COM/DCOM (like DAO):
bulletrequires secure applets
bulletlimits possible client platforms
bulletexposes usage of COM/DCOM object and thus again creates a security problem

If you need to present data to the user in a format that goes beyond capabilities of HTML, then one of the possibilities is to use a mixed approach:

bulletdata is retrieved by ASP scripts or components, which ensures security and minimizes download,
bulletretrieved data is presented by a Java applet that can do it in a nice graphical way.

5.5 Pros and Cons of Java on the Web Server

Another question to ask is whether ASP components should be actually written in Java rather than other languages, especially C++ or Visual Basic. Here are some points for consideration.

Pros:

bulletfaster development than with C++
bulletmuch more powerful than Visual Basic
bulleteasier access/interface to COM/DCOM components than in C++

Cons:

bulletmuch slower than C++ (let’s keep asking for a real Java compiler)
bulletoverhead of Java VM

Possible approach to address the performance:

bulletfirst develop ASP components in Java
bulletdeliver the system (better time-to-market)
bulletwatch/analyze performance and replace critical components with C++ versions, if needed

Appendix A: Checklist for Developing Java ASP Components

Here is a quick checklist that summarizes the steps necessary to develop an ASP component using Visual J++:

  1. When working with IIS 3.0, use jactivex utility to generate Java class files for ASP built-in objects from the ASP type library provided by IIS.
  2. The Java class must be a public class.
  3. Always define public OnStartPage method that would store the reference to the given ASP context object.
  4. Methods and fields available to ASP scripts must be declared public and use either built-in elementary Java types, Variants, or other Java classes registered as COM objects.
  5. Use javareg utility to register your Java classes as COM/DCOM servers.
  6. Copy the compiled .class files into the TrustLib subdirectories on the Web server that correspond to your Java packages.
  7. When you update classes in TrustLib, clear the VM’s cash by stopping and then restarting IIS.

Appendix B: Checklist for Developing ASP Pages

Here is a quick checklist for writing and installing ASP pages:

  1. Create ASP components using Server.CreateObject method and passing the ProgID string identical to the one specified when the class was registered with javareg. This will ensure that your Java component is found and its OnStartPage method is executed.
  2. If you use scripting language other than VB Script, remember to change the default language.
  3. Place your ASP files in the directory that has the "executable" flag set in the IIS directory manager.
  4. Remember that ASP scripts are executed before the resulting page is handed over to the requesting Web browser.
  5. Use Java applets only to improve data presentation or make the page more dynamic.
 

For more information, send email to: or fill in the online contact form.
Last update: September 17, 2005
Home ] Contact ]