This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


This article assumes you're familiar with Java, Visual InterDev, COM and ADO
Download the code (323KB)

Using MTS Components on Your Web Server with Java
Christian J. Thilmany

Using Microsoft Transaction Server, Active Server Pages, and Java, you can create a Web server application that will scale from a ten-person intranet to thousands of users over the Internet.
Transaction support is a long-overdue addition to Microsoft® Windows® and BackOffice®. Before the advent of Internet and Web development, writing a client-server application meant targeting a certain number of users. Scaling an application for a typical network environment of 1 to 50 users meant leveraging the abilities of a particular database. Most business logic was kept at the database implementation tier in the form of SQL triggers and stored procedures. The focus of other development efforts was on creating robust front-ends and an intelligent set of user services code. Database implementers controlled the server code, while Windows-based development remained at the workstation level, creating intelligent front-ends. This "smart client" approach can work well for controlled network environments whose mission is to create an intelligent client-server system centered on a corporate datastore. Unfortunately, fattening the business logic at the database tier also stretches the capabilities of the SQL language. Although programming in SQL can produce scalable applications, SQL was never meant to be a true general-purpose programming language.
      Fortunately for developers, this client-rich architecture allowed the programmer to concentrate on business logic and application functionality, and not the intricacies of scalable code. Unfortunately for these same developers, the arrival of the Internet and distributed application architectures brought new scaling issues and a new development model. Development is now focused on the server, where business logic has ended up. This is a shift from the traditional database coding setup that client-server programmers are familiar with. With distributed technology, applications on the Internet are now becoming component-driven. This can mean distributing the logic between servers and thinning the clients in the emerging n-tier architectures you are now seeing.
      In the n-tier world, the development of parts of an enterprise application can now be divided among those with the appropriate skills and functional knowledge. Programmers familiar with GUI development work on the client, while those with data access development skills can focus on the business components. Of course, database implementers and administrators still remain at the data tier. This environment also simplifies code distribution, since most of the business logic has been moved from the client to the server. With clients becoming thinner and installations becoming smaller, administrators can focus more on server configuration and less on deployment. Microsoft's new Zero Administration Initiative follows this premise.
      Along with server-based development comes the challenge presented by the increase in user access. Business services running on the server can now be accessed from thousands of clients. The programmer must now be concerned with concurrency, user context, connections, synchronization, pooling, security, and transactional behavior. For instance, building transactional behavior into a server application can be a tremendous challenge. Atomic behavior among these transactions is a must, and it's up to the developer to ensure this. Using banking transactions as an example, if a customer transfers money from one account to another, the two transactions must both either fail or succeed. If not, that customer may walk away with more or less funds in their accounts than intended. Transactional integrity is an important business issue and must be addressed at the development level. As the number of users increase, these issues become more and more onerous, sidetracking the developer from the real task at hand, which is delivering application features.

What is Microsoft Transaction Server?
      Microsoft Transaction Server (MTS) is part of the Microsoft Active Platform strategy for building distributed applications. MTS provides the ability to develop high-performance, scalable, distributed applications using components. Built on distributed COM (DCOM), MTS puts the focus on the application business rules, not on scaling issues. MTS developers can use languages such as Java, C++, Visual Basic®, or anything else that allows you to build in-process COM objects. The same code that runs a small workgroup can serve thousands of users over the Internet. MTS brings mainframe-style transactional reliability to the PC world following a "write once, run many" strategy: "write once" in the sense of component development, and "run many" in the sense of application scalability. For system designers, the debate over thin versus smart client is minimized since either architecture can be implemented.
      MTS represents the middle tier of a distributed application. It provides both design-time and runtime services to the components used in an application. A developer can access these services through the simple MTS development interface. Developers create a single-user component and make it stateless. They then deploy the component into the MTS environment with a few mouse clicks. This registers the component onto the server and provides client access to its business services. In MTS terminology, these clients are typically referred to as base clients.
      MTS provides low-level system resource management, including thread pooling, process management, and process isolation. Developers can move components from one set of application services to another without recompilation by simply dragging the component to the appropriate spot within the MTS Explorer. MTS also provides resource pooling for high-performance access to data resources such as Microsoft SQL Server™. Because MTS uses DCOM, it gains built-in component security from the Windows NT® security framework for controlled access.
      Most importantly, MTS provides automatic transaction support, providing two-phase commit behavior with full rollback and recovery. Developers configure their components within the MTS Explorer or, with MTS 2.0, use the new Microsoft Management Console (MMC) to set transactional properties (see Figure 1). Once deployed, a ball-shaped icon represents each component. These business objects can be viewed at design time and, more crucially, at runtime. When the balls start spinning, you know they are running!

Figure 1: ODBC Components
Building Transaction Server Components
      So how do you build MTS components? Exactly the same way you build standard COM objects, with the optional addition of a few lines of code. These additional lines are required to take advantage of the MTS transactional behavior by providing user context control. However, they are not required to use the MTS deployment or debugging environment (a fact that can come in handy while developing distributed applications across physical boundaries).
      For component development, a developer may choose any language, including Java. Writing MTS components in Java has its advantages and disadvantages. I will mention some of these issues in the following sections, but thanks to the language-neutral nature of COM, the choice is yours. For Web applications, this proves to be a big advantage if the front-end is already in Java; the same Java developers responsible for the client can also develop the middle tiers.
      Developing transaction server components requires little work beyond actually creating the component. MTS provides a straightforward interface for developers looking to take advantage of its transactional features. Once built, deployed, and instantiated from a base client, MTS creates an ObjectContext associated with every newly instantiated component. One ObjectContext object is created for each calling user and is completely managed by MTS.
Figure 2: ObjectContexts
Figure 2: ObjectContexts

      If an application client is anything other than an Active Server Page (ASP), and if multiple components make up the transaction, the first instantiated component must in turn instantiate other components, using the newly created ObjectContext to perform its own CreateInstance on the second component (see Figure 2). In essence, the first component becomes a client of the second. Clients developed in languages such as Visual Basic, Java, or Visual C++® must perform object instantiation in this manner in order to control transactional context.
      During execution, the client component runs normally, and on successful completion calls SetComplete. This completes the work on the transaction and tells MTS to recycle any resources it may be holding, thus finishing the atomic operation. If errors occur at any time in the transaction, SetAbort is called and all changes are immediately rolled back. The beauty of the model is that any component may have already called its save routines to a data store such as SQL Server. If SetAbort is called at any time, data will not persist, leaving the atomic operation intact. This model frees the developer from having to perform any manual two-phase operations or cache data. MTS and the Microsoft Distributed Transaction Coordinator (DTC) manage this automatically.
      If the application client happens to be an ASP, as in my example, then the second component does not have to be instantiated from the first. Instead, transaction control is kept at the ASP level since the ASP acts as a transaction client to components created within that page. This feature is built into Internet Information Server (IIS) 4.0 using ASP 2.0. Using ASPs greatly simplifies the code required in an MTS component by eliminating any ObjectContext.CreateInstance calls. This simplifies a component developer's task of making business components truly stateless and reusable.

Building MTS Components Using Java
      To show how to build a fully scalable Web application using MTS, I created a sample Web-based conference registration system using Microsoft Visual InterDev, MTS, and Java. To use my application, a user would simply browse to my starting page, fill out the appropriate registration and contact information, then select the Submit button. Behind the scenes in MTS, the appropriate component will be loaded and run. With the components running on the server and using ASP to deliver pure HTML to the client, you can create a true cross-platform transactional Web application.
      I named my workspace SemResWeb, which stands for Seminar Reservation Web application. It contains three project types: a Visual J++™ project (Attend.dsp), a Visual InterDev project (SemResWeb.dsp), and a database project (SemResDB.dsp). This workspace demonstrates the benefits of Microsoft's integrated Visual Studio™ in that each of these projects are all part of one workspace. Switching between them during development is a matter of highlighting the appropriate project. The SemResWeb application also demonstrates the ease and power of the MTS environment by showing how a developer can create flexible business components. SemResWeb components can be used individually or together as part of a cohesive transaction.
      To build this application I used Visual J++ 1.1, Visual InterDev 1.0, SQL Server 6.5, MTS 2.0, and IIS 4.0 with Microsoft Internet Explorer 4.0 (see Figure 3). At the time of this writing, both MTS 2.0 and IIS 4.0 were in late beta.

Figure 3: Seminar Reservation Web App
Figure 3: Seminar Reservation Web App

      For developers creating large-scale applications, transactions have many advantages. When MTS 1.0 first shipped, it was the only product to provide such transaction support for Java. Developing transactions without it would have been a major endeavor. Let's explore how to create an MTS component using Java and then drive it from a fully functional ASP, thus completing my transactional Web app.
       Step 1 As part of the Attend project, I first provided definitions for my classes and the interfaces that I would later implement by creating an Interface Description Language (IDL) file. This IDL file will be used to create my type library and is the necessary first step toward building my components. In Attend.idl, I created two components, or coclasses. The first class, CContact, I will use to add contact information to my database. The second class, CAttend, will be used to register the attendees to the conference (see Figure 4). Each component can be used individually or grouped into a transaction. In the CContact class I created a method called Add, which will be called from the client to add a contact to the database (in this case SQL Server 6.5). In the CAttend class I also created a function called Post, which will register an attendee to the conference so I can later get an accurate headcount.
      When building an IDL file for a Java-based COM component, you should only use COM-compatible data types that can be mapped to Java types. I also recommend using OLE automation-compatible types and making the interfaces dual. A dual interface allows a component to be called from both early-binding (vtable) and late-binding (automation) clients. Using a dual interface will also allow VBScript clients like mine to use Java-based COM components. It is important to note that all out parameters must use Variant types if they are to be called from VBScript, as in my example.
      For a complete table of the mapping between COM types and Java types, see the Microsoft Visual J++ documentation topic "Type Mappings between Java and COM."
       Step 2 Make sure that each class, interface, and library in the newly created IDL file has a globally unique identifier (GUID). Choose Create GUID from the Tools menu in Microsoft Developer Studio or run guidgen.exe directly from the command line. Once the IDL file is complete, the next step is to create the type library. Since multiple custom attributes will be used in the IDL, I needed version 3.01.59 or later of the MIDL compiler, which ships with all versions of MTS. I chose to place the MIDL compiler in the project settings of my Visual J++ project, as part of my custom build settings. In Visual J++, select Project | Settings, highlight the IDL file in the left pane, and select the Custom Build tab to add the following:

 midl Attend.idl 
This lets you avoid going to the command line to run the MIDL compiler. In fact, all of the many command-line tools can be run in this fashion (see Figure 5). It is assumed that these tools are all in the current path. At the end of each step, I chose to build the Attend project. This compiled my IDL into a corresponding type library, attend.tlb.
Figure 5: Project Settings
Figure 5: Project Settings

      Step 3 The next step is to create the first actual Java code for the project. These classes will act as wrappers for the classes that I will implement later. The Javatlb.exe tool, part of Visual J++, creates one .class file for each coclass and interface in the type library I created. The names of the files generated from Javatlb will correspond to the names of the coclasses and interfaces. When Javatlb is run, each generated .class file will be placed in the appropriate package subdirectory. Using Javatlb, I created the CAttend.class, IAttend.class, CContact.class, and IContact.class files. Later, I created two additional Java files to implement the components: Attend.AttendObj and Attend.ContactObj. At runtime, the Java VM will use these wrapper classes to map incoming calls from COM clients to method calls in Attend.AttendObj and Attend.ContactObj.
      To generate my Java wrappers I used the /p option to specify Attend as the Java package for my new classes, and /d to tell Javatlb in which directory to place the wrapper classes. I added the following just after the MIDL command:

 JAVATLB /d . /p Attend  /p:b- Attend.tlb
      As an optional step, calling Javatlb with the /U:T switch will create a declarations file called summary.txt. This will contain all of the required Java signatures contained in the type library. Summary.txt can be handy when later implementing the COM classes in Java.
      Step 4 The last step before implementing and compiling your Java code is to run an MTS-specific tool called Javaguid.exe on the newly created wrapper classes. This tool is used to ensure that the proper GUID class (com.ms.com._ Guid) is passed to all MTS-specific APIs. Those APIs requiring a GUID type will be changed appropriately. The wrapper classes created in Step 3 must be in the current directory when you run Javaguid. Again, I added this tool to the custom build in Project | Settings right after the Javatlb line like this:

 cd Attend 
 JAVAGUID CAttend.class IAttend.class CContact.class IContact.class 
      Step 5 Finally, I implemented my Java classes. In my case, I created AttendObj.java and ContactObj.java to implement the CAttend and CContact classes. Each class name must exactly match what's been specified in the JAVACLASS custom IDL attribute. I then implemented all of the methods with-in those interfaces as defined in Attend.idl. In my case, I needed to implement the Post (IAttend) and Add (IContact) methods of my components. Later, I will call each of these functions from my ASP base client (see AttendObj.java, available online).
      Step 6 For both the Add and Post methods, any database transport interface may be selected (I chose ADO). I recommend that the chosen transport be ODBC-based in order to utilize one of MTS's key features, the ODBC resource dispenser, for optimized database connectivity. The services use ODBC running on the server, so the cross-platform architecture will remain intact. Also, to take advantage of the MTS transactional environment, the database must be XA-compliant and must support MTS. Currently, SQL Server 6.5 is one of those databases (Sybase and Informix are soon to follow). This is not to say that I couldn't have developed my MTS components without an XA-compliant database, but I wouldn't have had access to MTS's transactional services.
      Step 7 After I implemented all of the business logic, I built my project. The build compiled attend.idl, ran all of the custom build command-line tools, and compiled the Java source with jvc.exe.
      Step 8 Before I deployed my new components into MTS, I had to build an in-process DLL from the generated class files. Only DLLs can be used within MTS. For my example, both components are contained in one DLL called vjattend.dll. To accomplish this, I used yet another tool called the Java Executable Generator (EXEGEN). The version that ships with MTS supports a new /d switch for creating DLLs. As before, I added this to my Project | Settings, this time to my Post-Build Step tab:

 EXEGEN /d /r /out:VJAttend.dll Attend.TLB *.class 
The /d switch tells EXEGEN to build a DLL, and /out specifies the file name of the component DLL. The /r switch recurses into the project subdirectory, where all of my class files will be found. As an option, I chose to copy the final binary to a deployment directory, called packages, as shown in Figure 6.
Figure 6: Post-build Commands
Figure 6: Post-build Commands

Deploying Your Components into MTS
      It's time to deploy the components into MTS. Using the MTS Explorer or MMC, create an empty package to house the components. I called mine Conference. To create a package, open the MTS Explorer and highlight the hierarchy Packages Installed. Right-click this hierarchy, and select New. Choose Create an empty package and give it a name.
      Next, I added my components. I defined the component's programmatic IDs (ProgIds) as Reservation.Contact and Reservation.Seminar. I will use these ProgIds to create my components from VBScript. Once deployed, the ProgIds are displayed in the MTS Explorer. I expanded the hierarchy under the new package and highlighted components, right-clicked, and selected New. I chose to install the new component vjattend.dll. MTS loaded the file and listed all of the components in a corresponding dialog. I then selected finish and vjattend was deployed!
      I used all of the default MTS property settings for this example. These settings include "Requires a Transaction," which flags MTS to create an accessible object context, and "Enable authorization checking," which enforces DCOM security on the component. All transactional settings initially came from my IDL custom attributes like TRANSACTION_REQUIRED (see Figure 4). At this point I could instantiate my components from an ASP. At runtime, the ASPs I build will use the Java VM as the COM server for each implemented Java class. The COM server is associated with the Java VM through the component's registry settings.

Building a Web Client with Active Server Pages
      To pull together a complete Web application, I used Visual InterDev to create three ASPs. Here I took full advantage of one of the new features of ASP 2.0, using the built-in transactional support. By adding the statement <% @TRANSACTION=REQUIRED %> to the ASP (see Figure 7), the entire transactional context of the components can now be controlled from within the page itself. Each of my pages will instantiate a new MTS component and utilize its services (Post and Add) to provide the simple conference registration front-end.
      My pages employ standard HTML forms and VBScript to create my components, call their methods, and clean up after themselves. By using ASPs, I was able to provide these MTS services to any browser (see Figure 7 and Figure 8). In this capacity my MTS components act as Active Server components, each callable from within my ASPs. As mentioned earlier, if a non-ASP client wants to use these services, it needs to instantiate any service that's been implemented as part of a transaction directly from that individual component. With ASP 2.0, each MTS component can be instantiated individually and be controlled completely from VBScript. With IIS 4.0, your ASP files have the option of running under the context control of MTS, providing industrial-strength reliability to your Web content.
      Let's look at some more code. After a brief introduction to the upcoming seminar, the user can advance to the first form of the application (see Figure 9). The user is then prompted for general registration information such as last name, number of attendees, and favorite subject. If the attendee asks to have a confirmation faxed to them and then chooses Submit, I then display the second form for them to give me their contact information. If the user chooses not to receive a confirmation, Reservation.Attend is immediately instantiated and the user will be registered for the conference. At this point it isn't necessary to provide transactional control at the ASP level since only one component is being instantiated. Now let's look at how to control the entire transaction using both components from one ASP.
      To drive a component from the ASP, simply use Server.CreateObject(ProgId) from within VBScript. The components are working when the magic X-balls start spinning in the MTS Explorer. Had the user chosen to receive a registration confirmation and filled out the appropriate contact information on the form, both components would have been instantiated from Contact.asp. At this point, both Reservation.Seminar and Reservation.Contact are created from one ASP. If one of these components fails to complete by calling SetAbort from within its business logic, the developer can now roll back both actions. Additionally, with ASP 2.0, you can respond to MTS-specific transaction events that get fired during each SetComplete or SetAbort. This gives you the flexibility of responding from within the ASP code as I have.
      If the base clients were not ASP files (perhaps created with Visual Basic), then my Reservation.Contact component would have to call Reservation.Attend from within its code and automatically register the guest (see Figure 10). When calling one object from another, you must use the current ObjectContext created from within MTS and call ::CreateInstance to instantiate the next component level. This ensures that each component will belong to the same transactional context. Reservation.Contact would then save the contact information to the database immediately after Reservation.Attend registered the new attendee. Once again, if any item failed during this operation all actions would automatically roll back, and database integrity would be preserved.
      Transactional control gives this application the ability to provide an accurate count of registered attendees and exemplifies the power of MTS. Each component can be used individually or as part of an entire transaction.
      The code within both the Add and Post methods contains the database logic required to save and transactionally control the conference registration. The database logic within these methods is almost identical, except for the SQL string passed to the database (see Figure 11). I decided to use ActiveX Data Objects (ADO) for my database transport for its simplicity and performance, although any number of database transports could have been used, including RDO, JDBC, or ODBCDirect.
      Upon the second iteration of this process, the MTS resource managers and pooling features begin to play their role. This will provide a significant increase in performance due to the fact that resources are now available from the first iteration and will not need to be reinstantiated. When a client requests a database connection, its handle can now be drawn from the current pool that MTS controls. Thus, return customers can avoid waiting for pages to be updated. To further improve performance within MTS, each client should be developed so that object references are maintained as long as possible. Also, instantiate components when the user may have something else to do, since object creation will be MTS's most significant bottleneck.

Debugging Your MTS Components
      There are definite advantages to writing a component in Java. Personally, I like the fast compilations. However, debugging an MTS component in Java is slightly less convenient than writing a component in Visual C++ or Visual Basic. Currently, in order to step through code (when running under MTS) you must get acquainted with the Microsoft Script Debugger (see Figure 12). Some debugging may even have to precede the deployment of the component through a standalone applet, using Jview. It also doesn't hurt to have Visual Basic installed since running MTS components from Visual Basic tends to be a little more informative than VBScript and ASP. If the components still do not run after all of this, make sure that the DTC service is running. If it isn't, use the MTS Explorer to restart it.

Figure 12: Microsoft Script Debugger
figure 12: Microsoft Script Debugger

      At runtime, MTS provides many views such as the Statistics Window to help the developer see what's going on. But MTS is more than a transaction monitor or object broker. Not only does it make the world of distributed components more manageable, MTS provides insurance to the developer. What once ran only on a single workstation can now scale across the Web.

From the February 1998 issue of Microsoft Interactive Developer.