HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

Introduction
With wider acceptance of component development and distributed object technologies, applications can be 'assembled' as a set of collaborating components. For non-visual business components, where delivery time, integration costs and maintainability are the determining factors of success, Java is increasingly the implementation language of choice. When writing components in Java, we must be able to access a set of services commonly provided to business objects in enterprise computing, most notably resource management, object pooling and transaction processing.

In this article, we will explore how Java components can access transaction services. We will describe the common framework for transaction processing: Distributed Transaction Processing (DTP) Model. We will also take a closer look at two common applications of DTP-like transaction models. In Part I, we will cover the concepts of the Microsoft Transaction Server (MTS), and OLE Transactions and build a sample MTS-based order validation application in Java. In Part II, we will explore the CORBA Object Transaction Service (OTS) and its commercial implementation. In the end, you will have a good understanding of transaction models, their underlying principles and how Java applications can participate in transaction processing. Before we start, I want to emphasize that the purpose of this article is to focus on understanding transaction processing concepts. We will not attempt to 'rate' various commercial implementations of TP monitors or component standards. You should also have a basic understanding of COM and CORBA.

Distributed Transaction Processing - X/Open DTP Model
Conceptually, a large number of business problems are transaction-based. Inventory management, order processing and job scheduling are only a few of the common manufacturing tasks that can be viewed as transactional. The concept of transaction is the centerpiece of all banking systems. Banks most certainly do not want to credit an account without debiting another and vice versa. In general, we describe transactions as:

  • Atomic: A transaction is a single logical unit of work - all changes are always either successfully committed or rolled back in case of failure. A transaction will not be partially committed or partially aborted.
  • Consistent: A transaction is a unit of work which takes a system from one consistent state to another.
  • Isolated: While a transaction is executing, its partial results are hidden from other entities accessing the system, and
  • Durable: The results of a transaction are persistent.
These four properties are also known as ACID properties and form the foundation of transactional systems. In truth, it is not that difficult to achieve ACID properties in highly integrated systems. However, maintaining ACID properties becomes increasingly complex in systems spanning multiple machines, platforms, databases or database systems.

To address transaction processing in the distributed and heterogeneous environment, X/Open group defined the Distributed Transaction Processing (DTP) Model. The basic X/Open DTP model consists of three main entities and two interfaces. Transaction Manager manages the scope (context) of transaction, provides a unique transaction identifier and determines the outcome of transaction. Resource Manager enlists transaction resources in transactions ('ax_reg', 'xa_start'), most importantly databases. Application communicates with Transaction Manager via TX interface. Transaction Manager 'talks' to Resource Manager via XA interface. Figure 1 shows how Application starts transaction ('tx_begin'). Transaction Manager informs Resource Manager about the transaction; Application then makes a series of calls to Resource Manager using the native API. The application signals the end of transaction by calling Transaction Manager ('tx_commit'). At this point, Transaction Manager starts the two-phase commit process using XA interface. In a simplified view of two-phase commit, Transaction Manager instructs all participating Resource Managers to prepare the commit ('xa_prepare'). Resource Managers communicate with their resources to prepare commit and send an acknowledge massage ('commit ready', or 'commit aborted') to the Transaction Manager. The Transaction Manager awaits the responses. If all resource managers responded with 'commit ready', the final commit command ('xa_commit') is issued by the Transaction Manager and all changes are committed. The information about successful commit is communicated back to the client. If one or more resource managers could not prepare to commit, the transaction manager issues the rollback message and all resource managers ensure that the initial state is restored. Finally, the transaction manager informs the client that the changes failed and the initial state was restored.

Figure 1
Figure 1:

Microsoft Transaction Server (MTS)
In this section, we will explore how COM and DCOM-based components create and participate in transactions. According to MTS 2.0 documentation: "MTS is a component-based transaction processing system for building, deploying, and administering robust Internet and Intranet server applications." More importantly, MTS provides a common framework of services for developing components that encapsulate business logic. The MTS runtime is a middle-tier platform for running these COM-based components. Arguably, the key benefits of MTS are the programming model, resource management, object pooling and ease of administration. MTS provides transactional services through leveraging existing OLE Transactions technology. MTS runtime then simply interacts with OLE Transactions participants on behalf of the business components.

Understanding MTS and OLE Transactions
When developing MTS application components, we declare component's transaction attribute, which determines whether associated resources should participate in the transaction. This attribute can also be changed via MTS administrative tool - MTS Explorer. The transaction information is contained in Context Object. Context Object is created automatically for each MTS component. Among other properties, it also contains Transaction ID. Context Object is loaded with MTS component as a part of MTS Executive (mtxex.dll). The components and MTS executive then execute either in client's process or, more typically, in separate host process provided by MTS (mtx.exe).

MTS Executive has an 'intimate' knowledge of the application component and interacts with MTS runtime on its behalf. Figure 2 illustrates the core components of MTS runtime that participate in transaction processing. If a component is declared as transactional, MTS runtime contacts Microsoft Distributed Transaction Coordinator (MS DTC) and automatically starts a new transaction, or joins the existing one, when the component is instantiated.

Figure 2
Figure 2:

As illustrated in Figure 2, MTS Executive requests resources from Dispenser Manager. Dispenser Manager maintains resource pools with the help of Inventory Statistics Manager and Holder. The Holder component lists the resource inventory for each Resource Dispenser. Resource Dispenser has an 'intimate' knowledge of the underlying resource. It knows how to allocate and reclaim the resource. On start-up, Resource Dispenser registers with Dispenser Manager and enlists its resource with Resource Manager and Holder. The dispenser usually provides public API or COM interfaces that are used by client applications to access the resource. Resource Manager is a component that is part of the OLE Transactions model. The resource manager communicates with MS DTC and participates in a two-phase commit process.

Dispenser Manager periodically (every 10 seconds in MTS 2.0) interrogates each Holder to allow them to readjust their inventory. Each Holder, in turn, calls Inventory Statistics Manager to suggest the appropriate inventory levels. As a result, Holder instructs Resource Dispenser to either create or destroy some resources. After the resource is allocated, Dispenser Manager asks MTS Executive whether the application component is running within a transaction. If so, Dispenser Manager asks Resource Dispenser to enlist the resource in the transaction. Resource Dispenser, in turn, contacts Resource Manager to enlist the resource with MS DTC.

OLE Transactions
As we mentioned earlier, MTS relies on OLE Transactions to provide full support for ACID properties. The OLE Transactions model is based loosely on the DTP model. It also defines three entities in the transaction processing: the client application, the resource manager and the transaction manager. OLE Transactions protocol differs from the DTP model mainly because it is object-based and provides support for COM interfaces. As a proprietary standard, OLE Transactions take advantage of Windows-specific features and can be extended to support transactions across resources that were traditionally thought of as non-transactional (e.g., voice, video, directory services). Microsoft provides an implementation of the transaction manager - MS DTC. OLE Transactions also define a set of COM interfaces that MS DTC and each resource manager support. The protocol details how the client, MS DTC, and the resource managers carry out the two-phase commit process. The commit process is fundamentally very similar to the one described in the DTP model.

MTS Programming in Java
One of the major advantages of the MTS programming model is its simplicity. Virtually all of the detail about how the transactions are carried out is hidden from the client. Figure 3 depicts the complete set of Java interfaces and classes exposed by MTS in com.ms.mtx package.

Figure 3
Figure 3:

Because MTS is COM-based, the process of building an MTS application is basically the same as building COM components in Java. However, when attempting to create scalable systems we must consider issues such as an objects' state, persistence, granularity, object pooling and resource management. There are key differences between building the scalable applications in MTS and plain COM. For example, resource management and object pooling make acquiring and destroying resources in MTS relatively 'cheap'. Therefore, the traditional model of acquiring resources once and then holding onto them as long as they are needed is no longer valid in MTS. The 'typical' MTS component would create and destroy resources as needed and commit/rollback changes as soon as possible. The component sends commit/rollback messages by calling SetComplete/SetAbort methods on IObjectContext interface. In addition to committing changes, the SetComplete/SetAbort calls cause the object instance to be 'recycled' using the object pool. MTS version 2.0 supports the most basic object pooling - instances are created and destroyed on demand, no object pool is maintained. As a result, clients cannot rely on MTS objects to maintain their state after MTS objects issue SetComplete/SetAbort commands. This behavior constitutes the single most important paradigm change in the COM programming model.

MTS also introduces a new security model on top of NT domain security. The centerpiece of MTS security model is the concept of roles. A role usually refers to a group or type of users for a set of components; e.g., Manager, Sales Representative or Customer.

To demonstrate these concepts we will build a sample order validation system. First a little background. Our company - M.C. Manufacturing (MCM) - is adopting a new business model. It allows its customers to order any sample and experimental products. After a few successful sample orders, the customers would presumably place a large order and the product could be eventually added to the standard product line. MCM's IT department must now build an order validation system that could pre-process the large volume of custom-made products. Pre-processing orders will help to minimize the lead times. We will attempt to build the system in the following steps:

  1. Design conceptual-level interfaces that describe desired systemís behavior.
  2. Design physical, MTS COM interfaces and classes using Interface Definition Language (IDL).
  3. Map IDL interfaces and classes into Java interfaces. Create Java implementation classes.
  4. Create and deploy the system.
Designing conceptual-level interfaces
MCM's new system must accomplish a single logical step -- an activity, in MTS speak: process an order. As it turns out, to validate an order the system must: validate order attributes (size, quantity, etc.), make sure that the item satisfies general rules (production specifications, etc.), notify demand planning system and contact work scheduling system to pre-schedule plant capacity. For simplicity, we assume that there is only one item per order. We also omit security, which usually would be part of the system. Given these facts, Listing 1 shows a simplified set of Java interfaces describing the new system. IItem interface represents an item on an order. Before submitting an order, each item must be validated by calling IItem.ValidateAttributes() and IItem.ValidateRules(). Each order, represented by IOrder interface, contains one item. Using IOrder interface, we can add an item (IOrder.AddItem()), and submit the order (IOrder.Submit()). When submitting an order, the new system uses IDispacher interface to interact with scheduling system (IDispatcher. Schedule()), and demand planning system (IDispatcher. InformDemandPlanning()).

Designing physical, MTS COM interfaces using COM IDL
COM IDL provides a language-neutral way of defining interfaces in COM. These definitions are 'compiled' by an MIDL compiler that produces necessary marshaling code, header files and 'type library' - a binary representation of IDL code. The type library is then used to generate language mappings for interfaces and implementation classes described in IDL. Before we create an IDL file, however, we must re-design the conceptual-level interfaces with respect to MTS and COM.

Traditionally, inside of Order class we would also create an instance of Item and Dispatcher classes and use them when validating and submitting order. These classes would, therefore, remain in memory for the lifetime of order instance. Clearly, this is not the best use of system resources. Consider the following scenario. When entering an order, we create an instance of Order component. When an item is added, we will obtain and keep a reference to it for the lifetime of instance of Order class. We will use an object manager to create an instance of Item class as needed. The object manager will 'know' how to create an instance of a class. It also 'knows' how to restore object's state based on the reference. What we are describing here is a process of adding persistence. COM has a concept of monikers that are used for implementing persistence. However, monikers are not supported in Java and, therefore, we must implement persistence ourselves. Our implementation is simple. Every class will implement an IPersistObject interface that defines how to load state, save state, return a persistent object reference to itself and notify about changes in state. Clients then use a static BindToObject() method of PersistManager class to recreate state of persistent objects. Listing 2 shows the IDL definition of IPersistObject interface.

Listing 2 describes the IDL definitions of all interfaces and COM implementation classes. Note that the IDL file contains TRANSACTION REQUIRED and JAVACLASS attributes. First attribute marks the component as transactional and causes MTS to start a new transaction or include it in the existing one. The JAVACLASS attribute provides a class name of concrete Java implementation class. For example, Java MCMValidateImpl.Order class will implement COM class COrder.

Mapping IDL files and creating implementation classes
We use a Jactivex tool to generate Java code from the type library. The Jactivex tool is included in Microsoft's Java SDK. Jactivex by default generates .java files for all interfaces and coclasses (COM classes) in the type library. In Listing 3 we describe the batch file that automates all necessary commands to create MTS components. Listing 4 shows the implementation classes for Order, Item and Dispatcher components. All business implementation logic is omitted for clarity. Note that all business classes implement IPersistObject to provide persistence support. All business classes also implement the IObjectControl interface. By implementing this MTS interface, objects can declare their support for object pooling. If an object supports pooling, the Activate() method is called when a new instance is assigned from the object pool. Therefore, rather than using constructor, you should always put any initialization code into Activate() method.

Implementation of Order and Dispatcher components illustrates the importance of state awareness in MTS. Since we want to keep order's state until it is submitted, AddItem() method does not call SetComplete(). On the other hand, Submit() method uses SetComplete()/SetAbort() to commit changes and to recycle the object instance. Dispatcher component is an example of a so-called 'stateless' component. It does not have any private state, all information is passed in via parameters and each method calls SetComplete()/SetAbort() upon completion. This design pattern minimizes use of system resources and also allows clients to use Dispatcher component without having to restore the component's state between method calls. In implementing large systems, it is clearly critical for clients to fully understand the MTS components' state behavior and use them accordingly.

Creating, and deploying MTS components.
We can now compile all Java classes and create an in-process, MTS-compatible dynamically linked library using the exegen tool shipped with MTS (see Listing 4). After creating MCMValidate.dll, we are ready to deploy components in MTS. First we create a new package and then import the newly created DLL by using 'Install new component(s)' option in MTS Explorer. Finally, MCMValidate.Order.1, MCMValidate.Item.1, and MCMValidate.Dispatcher.1 components will appear in MTS Explorer (see Figure 4). You can verify the install by examining component properties in MTS Explorer.

Figure 4
Figure 4:

Conclusion
Transaction processing is one of the critical tasks in enterprise computing. To write effective Java business components, we must be able to access transaction services. Transactions are usually defined by four properties: atomicity, consistency, isolation and durability. One of the most common frameworks for providing transaction support is the Distributed Transaction Processing Model by X/Open. The DTP model defines the set of standard interfaces, entities and behaviors for implementing transactions with ACID properties.

Microsoft Transaction Server (MTS) has emerged as one of the most important frameworks for component development. MTS provides COM components with common services such as resource management, object pooling and transactions. MTS components access transaction services by using OLE Transactions technology. MTS runtime participates in OLE Transactions on behalf of MTS components. In addition to transaction processing, MTS introduces the new COM programming model. To build effective MTS components, we must consider additional design issues such as state management, resource management and object pooling.

In Part II we will explore the CORBA OTS specification. We will review and explain OTS-defined interfaces, entities and behaviors. We will also examine a commercial implementation of OTS, and demonstrate how Java clients can interact with OTS entities.

References and Resources
Arnold, K., and Gosling, J., "The Java Programming Language", Addison-Wesley, Reading, MA, 1996 Box, D., "Essential COM," Addison-Wesley, Reading, MA, 1998 Chappell, D., "How Microsoft Transaction Server Changes the COM Programming Model," Microsoft Systems Journal, January, 1998, pp. 19-28. Sessions, R., "COM & DCOM: Microsoft's Vision for Distributed Objects", John Wiley & Sons, New York, NY, 1998 "Distributed TP: XA Specification, X /Open Document C193.", X/Open Company Ltd., Reading, UK, 1992 Microsoft Transaction Server 2.0 online Help. Microsoft Transaction Server SDK (ftp.microsoft.com/bussys/viper/SDK). Microsoft Developer Network, "Microsoft Transaction Server", January 1998 (www.microsoft.com/msdn)

Maros Cunderlik is a consultant for Connect Computer Co., a regional consulting and system integration firm based in Minneapolis, MN. He focuses on OO design and distributed object architecture. He can be reached at [email protected]

	

Listing 1: MCM Order Validation System: Conceptual-level Set of Java Interfaces.
 
public interface IItem 
{ 
  public boolean ValidateAttributes(); 
  public boolean ValidateRules(); 
} 

public interface IOrder 
{ 
  public boolean AddItem(IItem Item); 
  public boolean Submit(IItem Item); 
} 

public interface IDispatcher 
{ 
  public boolean Schedule(); 
  public boolean InformDemandPlanning(); 
} 

Listing 2: MCM Order Validation System: IDL Definitions.
 
FILE: MCMUtils.idl 
//MCMUtils.idl 

import "oaidl.idl"; 

//typedefs 
#ifndef _PERSISTID 
#define _PERSISTID 
  typedef BSTR PERSISTID; 
#endif _PERSISTID 

//interfaces 
[ 
  object, 
  uuid(AA573A21-90D2-11d1-B744-00609770DE26), //interface ID 
  dual, 
  helpstring("IPersistObject Interface"), //string desc. 
  pointer_default(unique) 
] 
interface IPersistObject : IDispatch 
{ 
  HRESULT GetPersistRef([out, retval] PERSISTID* pRef); 
  HRESULT Load( [in] const BSTR Storage); 
  HRESULT Save(void); 
  HRESULT IsDirty([out, retval]BSTR* pDirty); 
} 

MCMValidate.idl 

//MCMValidate.idl 

//Custom Properties for Java and MTS 
#include <MtxAttr.h> 
#include <JavaAttr.h> 

import "oaidl.idl"; //std. defs 
import "MCMUtils.idl"; // contains IPersistObject def. 

//interfaces 
[ 
  object, 
  uuid(F6E42BE2-8DE9-11d1-8813-0080C72ABA92), //Iterface ID 
  dual, 
  helpstring("IItem Interface"), 
  pointer_default(unique) 
] 
interface IItem : IDispatch 
{ 
  //Validate method, POST: item attributes and rules were validated,  
  calls SetComplte()/SetAbort() 
  HRESULT Validate(); 
} 

[ 
  object, 
  uuid(16E009A1-8DEA-11d1-8813-0080C72ABA92), //Iterface ID 
  dual, 
  helpstring("IOrder Interface"), 
  pointer_default(unique) 
] 
interface IOrder : IDispatch 
{ 
  //AddItem method, POST: item is added to order   
  HRESULT AddItem([in] PERSISTID ItemID); 

  //Submit method, POST: order was submitted, calls SetComplte()/SetAbort() 
  HRESULT Submit(void); 
} 

[ 
  object, 
  uuid(41E5D4E1-8DEA-11d1-8813-0080C72ABA92), //Iterface ID 
  dual, 
  helpstring("IDispatcher Interface"), 
  pointer_default(unique) 
] 
interface IDispatcher : IDispatch 
{ 
  //Schedule method, POST: item attributes and rules were validated, calls SetComplte()/SetAbort() 
  HRESULT Schedule([in] PERSISTID ItemID); 

  //InformDemandPlanning method, POST: order was sent to demand planning, calls SetComplte()/SetAbort() 
  HRESULT InformDemandPlanning([in] PERSISTID ItemID); 
} 

[ 
  uuid(6A505140-8DE9-11d1-8813-0080C72ABA92), //LibID 
  version(1.0), //version number 
  helpstring("MCM Order Validation Library") //string desc. 
] 
library MCMValidateLib 
{ 
  importlib("stdole2.tlb"); //std. defs 
  importlib("stdole32.tlb"); //std. defs 
  [ 
    uuid(41E5D4E2-8DEA-11d1-8813-0080C72ABA92),  //COM class ID 
    helpstring("CItem class"), 
    JAVACLASS("MCMValidateImpl.Item"), //Java impl. class 
    PROGID("MCMValidate.Item.1"), //Prog ID 
    TRANSACTION_REQUIRED //MTS trans. indicator 
  ] 
  coclass CItem 
  { 
    [default] interface IItem; 
    interface IPersistObject; 
  } 

  [ 
    uuid(6A505141-8DE9-11d1-8813-0080C72ABA92), //COM class ID 
    helpstring("COrder class"), 
    JAVACLASS("MCMValidateImpl.Order"),  //Java impl. class 
    PROGID("MCMValidate.Order.1"), //Prog ID 
    TRANSACTION_REQUIRED //MTS trans. indicator 
  ] 
  coclass COrder 
  { 
    [default] interface IOrder; 
    interface IPersistObject; 
  } 

  [ 
    uuid(6A505145-8DE9-11d1-8813-0080C72ABA92), //COM class ID 
    helpstring("CDispatcher class"), 
    JAVACLASS("MCMValidateImpl.Dispatcher"), //Java impl. class 
    PROGID("MCMValidate.Dipatcher.1"), //Prog ID 
    TRANSACTION_REQUIRED //MTS trans. indicator 
  ] 
  coclass CDispatcher 
  { 
    [default] interface IDispatcher; 
  } 
} 

Listing 3: MCM Order Validation System: Batch Build File.
 
FILE: MCMBuild.bat 
REM MCMBuild.bat 

REM Compile IDL 
del MCMValidate.tlb 
midl MCMValidate.idl 

REM Generate Java mapping 
jactivex /javatlb /d . MCMValidate.tlb 

REM Compile all Java classes 
jvc mcmvalidate\*.java MCMValidateImpl\*.java MCMUtils\*.java 

REM generate MTS Dll 
exegen /d /r /out:MCMValidate.dll MCMValidate.tlb mcmvalidate\*.class MCMValidateImpl\*.class MCMUtils\*.class 

Listing 4: MCM Order Validation System: Java Implementation Classes.
 
FILE: MCMValidateImpl\PersistManager.java 
//PersistManager.java 

package MCMUtils; //MCMValidate Utilities package 

import MCMValidateImpl.*; //MCMValidate impl. classes 
import mcmvalidate.*; //MCMValidate Jactivex gnerated 

//COM Std. packages 
import com.ms.com.*; 
import com.ms.com.IUnknown; 
import com.ms.com.Variant; 

public class PersistManager 
{ 
  public static IPersistObject BindToObject(String PersistRef) 
  { 
    IPersistObject obj = null; 

    //add your favorite persistence algorithm here 
    //create a new instance, e.g. obj = (IPersistObject) new CItem(); 
    //load state, e.g. obj.Load( žstorageIDÓ); 

    return obj; 
  } 
} 

FILE: MCMValidateImpl \Dispatcher.java 
//Dispatcher.java 

package MCMValidateImpl; 

import MCMUtils.*; 
import mcmvalidate.*; 
import com.ms.mtx.*; //MTS package 

//std. COM packages 
import com.ms.com.*; 
import com.ms.com.IUnknown; 
import com.ms.com.Variant; 

public class Dispatcher implements IObjectControl, IDispatcher 
{ 
  private static final String CLSID = "6A505145-8DE9-11d1-8813-0080C72ABA92"; 
  private IObjectContext m_context; 

  public boolean CanBePooled() //IObjectControl 
  { 
    //allow object pooling 
    return true; 
  } 
  public void Activate() //IObjectControl 
  { 
  } 
  public void Deactivate() //IObjectControl 
  { 
  } 
  public void Schedule( String ItemID ) //IDispatcher 
  { 
    boolean bSuccess = false; 
    try 
    { 
      m_context = MTx.GetObjectContext(); 

      //execute scheduling alogorithm 
      //add business code here 
      bSuccess = true; 
    } 
    finally 
    { 
      //commit changes and recycle instance 
      if ( bSuccess ) 
   m_context.SetComplete(); 
 else 
   m_context.SetAbort();   
    }; 
  } 
  public void InformDemandPlanning( String ItemID ) //IDispatcher 
  { 
    boolean bSuccess = false; 
    try 
    { 
      m_context = MTx.GetObjectContext(); 

      //submit item attributes to demand planning system 
      //add business code here 
      bSuccess = true; 
    } 
    finally 
    { 
      //commit changes and recycle instance 
      if ( bSuccess ) 
   m_context.SetComplete(); 
 else 
   m_context.SetAbort();   
    }; 
  } 
} 

FILE: MCMValidateImpl\Item.java 
//Item.java 

package MCMValidateImpl; 

import MCMUtils.*; 
import mcmvalidate.*; 
import com.ms.mtx.*; //MTS package 

//std. COM packages 
import com.ms.com.*; 
import com.ms.com.IUnknown; 
import com.ms.com.Variant; 

public class Item implements IObjectControl, IPersistObject, IItem 
{ 
  private static final String CLSID = "41E5D4E2-8DEA-11d1-8813-0080C72ABA92"; 
  private IObjectContext m_context; 
  private boolean m_OK; 

  //persistence attributes 
  private String m_strRef; 
  private String m_storageID; 
  private boolean m_i_am_dirty; 

  //item attributes 
  protected String m_name; 
  protected long m_productID;  
  protected long m_width; 
  protected long m_length; 

  //constructor 
  public Item() 
  { 
  } 
  public boolean CanBePooled() //IObjectControl 
  { 
    //allow object pooling 
    return true; 
  } 
  public void Activate() //IObjectControl 
  { 
    //reset on activation 
    m_i_am_dirty = true; 
    m_strRef = ""; 
    m_storageID = ""; 
  } 
  public void Deactivate() //IObjectControl 
  { 
  } 
  public String IsDirty() //IObjectControl 
  { 
    return ( new Boolean(m_i_am_dirty).toString() ); 
  } 
  public String GetPersistRef() //IpersistObject 
  { 
    //return reference that can be used to restore object's state 
    return m_strRef; 
  } 
  public void Save() //IpersistObject 
  { 
    //save the object state into persistent storage: StorageID 
    //add code here 
    return; 
  } 
  public void Load( String StorageID ) //IpersistObject 
  { 
    //load the object state from persistent storage 
    //add code here 
    return; 
  } 
  protected boolean ValidateAttributes() 
  { 
    boolean success = false; 

    //perform validation logic 
    //add code here 

    //signal change of state 
    m_i_am_dirty =  true; 

    return success; 
  } 
  protected boolean ValidateRules()  
  { 
    boolean success = false; 

    //perform validation logic 
    //add code here 

    //signal change of state 
    m_i_am_dirty =  true; 

    return success; 
  } 
  public void Validate() throws ComSuccessException //IItem 
  { 
    boolean success = false; 
    try 
    { 
      m_context = MTx.GetObjectContext(); 

      //perform validations 
      if ( ValidateAttributes() && ValidateRules() ) 
        success = true; 
      else 
        throw new ComSuccessException( "Invalid Item." ); 
    } 
    finally 
    { 
      //save state, if necessary 
      if ( m_i_am_dirty ) 
        Save(); 

      if ( success ) 
        m_context.SetComplete(); 
      else 
        m_context.SetComplete(); 
    }; 
  } 
} 

FILE: MCMValidateImpl\Order.java 
//Order.java 

package MCMValidateImpl; 

import MCMUtils.*; 
import mcmvalidate.*; 
import com.ms.mtx.*; //MTS package 

//std. COM packages 
import com.ms.com.*; 
import com.ms.com.IUnknown; 
import com.ms.com.Variant; 

public class Order implements IObjectControl, IPersistObject, IOrder 
{ 
  private static final String CLSID = "6A505141-8DE9-11d1-8813-0080C72ABA92"; 

  private IItem m_item; 
  private String m_itemID; 
  private IObjectContext m_context; 
  private IDispatcher m_dispatcher; 
  private boolean m_submit; 

  //persistence attributes 
  private String m_strRef; 
  private String m_storageID; 
  private boolean m_i_am_dirty; 

  //constructor 
  public Order() 
  { 
  } 

  public boolean CanBePooled() //IObjectControl 
  { 
    //allow object pooling 
    return true; 
  } 
  public void Activate() //IObjectControl 
  { 
    //reset instance variables 
    m_submit = false; 
    m_dispatcher = null; 
    m_item = null; 
    m_itemID = ""; 
    m_context = null; 
    m_i_am_dirty = false; 
    m_strRef = ""; 
    m_storageID = ""; 
    return; 
  } 
  public void Deactivate() //IObjectControl 
  { 
  } 
  public String IsDirty() //IPersistObject 
  { 
    return ( new Boolean(m_i_am_dirty).toString() ); 
  } 
  public String GetPersistRef() //IPersistObject 
  { 
    //return persistent reference 
    return m_strRef; 
  } 
  public void Save() //IPersistObject 
  { 
    //save state into persistent storage 
    //add code here 
    return; 
  } 
  public void Load( String StorageID ) //IPersistObject 
  { 
    //load state from persistent storage 
    //add code here 
    return; 
  } 
  public void AddItem( String ItemID ) throws ComSuccessException 
  { 
    if( ItemID.length() == 0 ) 
    { 
      throw new ComSuccessException ("Invalid ItemID."); 
    } 
    else 
    { 
 m_itemID = ItemID; 
 m_i_am_dirty = true; 
 return; 
    }; 
  } 
  public void Submit() throws ComSuccessException 
  { 
    boolean success = false; 
    try 
    { 
      m_context = MTx.GetObjectContext(); 
      if ( m_submit ) 
      { 
         //order has already been submitted 
    throw new ComSuccessException ("Order already submitted."); 
      }; 
      if( m_itemID.length() == 0 ) 
 { 
   //nothing to submit 
   throw new ComSuccessException ("No item on order."); 
 }; 
  
 //load an instance of Item 
 m_item = (IItem) PersistManager.BindToObject( m_itemID ); 

      m_item.Validate(); //m_item instance recycled 

      //create instance of Dispatcher within current context 
      m_dispatcher = (IDispatcher) m_context.CreateInstance(CDispatcher.clsid, IDispatcher.iid); 

      m_dispatcher.Schedule(m_itemID); //instance recycled 
      m_dispatcher.InformDemandPlanning(m_itemID); //instance recycled 

      m_i_am_dirty = true; //signal change of state 
      m_submit = true; 
 success = true; 
      return; 
    } 
    finally 
    { 
      //save state before calling SetComplete()/SetAbort() 
      if ( m_i_am_dirty ) 
        Save(); 

      //Without the following calls, the objects used here 
      //would not get released until after the next time 
      //the Java garbage collector runs.  
      //This calls could be omitted. 
      if (m_dispatcher != null)  
   ComLib.release( m_dispatcher ); 
      if (m_dispatcher != null)  
        ComLib.release( m_item ); 

      if ( success ) 
        m_context.SetComplete(); 
      else 
        m_context.SetAbort(); 
    }; 
  } 
}
 
      
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.