Developing the Bank Checking MTS Server Component
Gopalan Suresh Raj

Note
To work with any of these samples, you will need the following:
.........................................Microsoft Visual J++ ver 6.0
.........................................Windows NT 4.0 Options Pack

Once the IDL has been created, we now have to create the MTS server component.

The Steps involved in developing the MTS Server component are

1. Set the properties for your project
2. Implement the CheckingPK component
3. Implement the Checking Server component
3. Build and register the MTS server components
2. Add MTS aware code to the project's class
3. Mark the class as COM/MTS-enabled
4. Build the project
5. Deploy the DLL into The Microsoft Transaction Server

A Three Tier Architecture for a typical Bank Account

Figure shows what we are trying to ultimately accomplish in these pages

1. Create a new COM DLL project
An MTS component should always be packaged as a DLL. Select New Project and from the File menu, choose the COM DLL project template in Visual J++. Name the project BankServer.

2. Set the properties for your project

4. Set the properties for your project

1. ....From the Project Explorer | BankServer | BankServer Properties | ClassPath, uncheck the "Merge all Project-specific ........ClassPaths in solution" check box.
2. ....From the Project Explorer | BankServer | BankServer Properties | COM Classes check the "Use existing Type Library" ........radio button.
3..... Click the "Select" button.
4..... Click the "Browse" button.
5..... Browse to the newly created
Bank.tlb file in the project directory.
6..... Select and open the
Bank.tlb file.
7..... Click the "OK" button to confirm the list of COM Components.
8..... Click "OK" to confirm
Bank Properties form changes.
9..... Notice that the
Bank folder is added to the BankServer project.
10... Notice that 14 java source files have been created:
......
Checking.java, IChecking.java, and ICheckingDefault.java
...... ICheckingHome.java, and ICheckingHomeDefault.java
...... Savings.java, ISavings.java, and ISavingsDefault.java
...... ISavingsHome.java, and ISavingsHomeDefault.java
...... IAccountKey.java and IAccountKeyDefault.java
...... CheckingPK.java and SavingsPK.java
11... Rename the generated implementation class, Checking.java to CheckingImpl.java,
......
CheckingPK.java to CheckingPKImpl.java,
......
Savings.java to SavingsImpl.java and
......
SavingsPK.java to SavingsPKImpl.java.
12... A number of COM wrapper will be automatically generated during the compile phase.

3. Mark the class as COM/MTS-enabled
To deploy the class in MTS, you need to make it a COM/MTS class. You can easily make it one by right-clicking the mouse on the BankServer class from the Class Outline tab and Selecting Class Properties. Mark the MTS Support as Enabled and say OK.


Figure : Mark the Class as COM/MTS enabled

You will immediately notice that some code similar to this is added to the CheckingImpl class

/** @com.register(clsid=07D690F5-FB95-11D2-97E3-006097A7D34F,
* typelib=07D690F0-FB95-11D2-97E3-006097A7D34F, version="1.0")
* @com.transaction (required)
*/
 
The final code for the CheckingPKImpl and CheckingPK looks like this:

CheckingPKImpl.java
package bank;

import com.ms.com.*;
import com.ms.com.IUnknown;
import com.ms.com.Variant;

/** @com.register(clsid=07D690F4-FB95-11D2-97E3-006097A7D34F,
 * typelib=07D690F0-FB95-11D2-97E3-006097A7D34F, version="1.0")
 */

public class CheckingPKImpl
 implements IUnknown, com.ms.com.NoAutoScripting, bank.IAccountKeyDefault {
 
 public static final int CHECKING_BASE = 11;
 public static final int CHECKING_HIGH = 10000;
 
 int m_accountNumber;

 public void setKey(int key) {
 
  if ( (key < CHECKING_BASE) ||
       (key > CHECKING_HIGH) ) {
   throw new com.ms.com.ComFailException (1, "Invalid Checking Primary Key");
  }

  m_accountNumber = key;
 }
}

The Code for CheckingImpl.java is shown below:

CheckingImpl.java
package bank;

import com.ms.com.*;
import com.ms.com.IUnknown;
import com.ms.com.Variant;
import com.ms.mtx.*;
import com.ms.wfc.data.*;

/** @com.register(clsid=07D690F5-FB95-11D2-97E3-006097A7D34F,
 * typelib=07D690F0-FB95-11D2-97E3-006097A7D34F, version="1.0")
 * @com.transaction (required)
 */

public class CheckingImpl implements IUnknown,com.ms.com.NoAutoScripting,
 bank.ICheckingHomeDefault,bank.ICheckingDefault {
 
 static final int ALL_FIELDS   = 0;
 static final int NAME_FIELD   = 1;
 static final int BALANCE_FIELD= 2;
 
 //odbc type connection string
 static final String m_strOpenConn = "FILEDSN=Bank";
 
 ////////////////////////////////////////////////////////////////////
 //          Home Interface methods
 ////////////////////////////////////////////////////////////////////

 ////////////////////////////////////////////////////////////////////
 public void create(bank.IAccountKey key, String name, double startingBalance) {
 ////////////////////////////////////////////////////////////////////
  if (startingBalance < 0)
   return;
 
  boolean bSuccess = false;
  System.out.println("Invoking Checkings::create");
 
  IObjectContext context = null;
 
  try {
   // Get the Object Context
   context = (IObjectContext)MTx.GetObjectContext ();
   truePut (CheckingImpl.ALL_FIELDS, (CheckingPKImpl)key,
            (new Double (startingBalance)).toString (), name);

   bSuccess = true;
  }
  catch (Exception e) {
   bSuccess = false;
   e.printStackTrace ();
  }
  // Upon exit, always call SetComplete () if happy,
  // or
SetAbort () if unhappy
  // We do this since we never save state across method calls.
  finally {
   if (context!=null) {
    if (bSuccess == true)
     context.SetComplete ();
    else
     context.SetAbort ();
   }
  }
 }

 ////////////////////////////////////////////////////////////////////
 //          Remote Interface methods
 ////////////////////////////////////////////////////////////////////

 ////////////////////////////////////////////////////////////////////
 public void credit(double amount, bank.IAccountKey key) {
 ////////////////////////////////////////////////////////////////////
 
  double balance = 0.0;
  boolean bSuccess = false;
  System.out.println("Invoking Checkings::credit");
 
  try {
   balance = getBalance (key);
  }
  catch (Exception e) {
   e.printStackTrace ();
  }
 
  System.out.println("changing Checkings::balance from " + balance);

   // Get the Object Context
  IObjectContext context = (IObjectContext)MTx.GetObjectContext ();
 
  try {
   if( amount > 0 ) {
    balance += amount;
    truePut (CheckingImpl.BALANCE_FIELD, (CheckingPKImpl)key,
             (new Double(balance)).toString (), "");
    bSuccess = true;
   }
  }
  catch (Exception e) {
   bSuccess = false;
   e.printStackTrace ();
  }
  // Upon exit, always call SetComplete () if happy,
  // or
SetAbort () if unhappy
  // We do this since we never save state across method calls.
  finally {
   if (context!=null) {
    if (bSuccess == true)
     context.SetComplete ();
    else
     context.SetAbort ();
   }
  }
  System.out.println(" to " + balance);
 }

 ////////////////////////////////////////////////////////////////////
 public void debit(double amount, bank.IAccountKey key) {
 ////////////////////////////////////////////////////////////////////
  double balance = 0.0;
  boolean bSuccess = false;
  System.out.println("Invoking Checkings::debit");
 
  try {
   balance = getBalance (key);
  }
  catch (Exception e) {
   e.printStackTrace ();
  }
 
  System.out.println("changing Checkings::balance from " + balance);

   // Get the Object Context
  IObjectContext context = (IObjectContext)MTx.GetObjectContext ();
 
  try {
   if ( (amount > 0) && (balance >= amount) ) {
    balance -= amount;
    truePut (CheckingImpl.BALANCE_FIELD, (CheckingPKImpl)key,
             (new Double (balance)).toString (), "");
    bSuccess = true;
   }
  }
  catch (Exception e) {
   bSuccess = false;
   e.printStackTrace ();
  }
  // Upon exit, always call SetComplete () if happy,
  // or
SetAbort () if unhappy
  // We do this since we never save state across method calls.
  finally {
   if (context!=null) {
    if (bSuccess == true)
     context.SetComplete ();
    else
     context.SetAbort ();
   }
  }
  System.out.println(" to " + balance);
 }

 ////////////////////////////////////////////////////////////////////
 public double getBalance(bank.IAccountKey key) {
 ////////////////////////////////////////////////////////////////////
 
  double  balance = 0.0;
  boolean bSuccess= false;
  System.out.println ("Invoking Checkings::getBalance");
  IObjectContext context = null;
 
  try {
   // Get the Object Context
   context = (IObjectContext)MTx.GetObjectContext ();
 
   String result = trueGet (CheckingImpl.BALANCE_FIELD, (CheckingPKImpl)key);
   balance = (new Double (result)).doubleValue();
   bSuccess = true;
  }
  catch (Exception e) {
   bSuccess = false;
   e.printStackTrace ();
  }
  // Upon exit, always call SetComplete () if happy,
  // or
SetAbort () if unhappy
  // We do this since we never save state across method calls.
  finally {
   if (context!=null) {
    if (bSuccess == true)
     context.SetComplete ();
    else
     context.SetAbort ();
   }
  }
 
  System.out.println("Checkings::balance is " + balance);
  return balance;
 }

 ////////////////////////////////////////////////////////////////////
 public String getCustomerName(bank.IAccountKey key) {
 ////////////////////////////////////////////////////////////////////
 
  String  name = null;
  boolean bSuccess= false;
  System.out.println ("Invoking Checkings::getCustomerName");
 
  IObjectContext context = null;
 
  try {
   // Get the Object Context
   context = (IObjectContext)MTx.GetObjectContext ();
   name = trueGet (CheckingImpl.NAME_FIELD, (CheckingPKImpl)key);
   bSuccess = true;
  }
  catch (Exception e) {
   bSuccess = false;
   e.printStackTrace ();
  }
  // Upon exit, always call SetComplete () if happy,
  // or
SetAbort () if unhappy
  // We do this since we never save state across method calls.
  finally {
   if (context!=null) {
    if (bSuccess == true)
     context.SetComplete ();
    else
     context.SetAbort ();
   }
  }
 
  System.out.println ("Checkings::customer_name is " + name);
  return name;
 }
 
 ////////////////////////////////////////////////////////////////////
 //          Other Internal methods
 ////////////////////////////////////////////////////////////////////

 ////////////////////////////////////////////////////////////////////
 String trueGet (int type, CheckingPKImpl key) {
 ////////////////////////////////////////////////////////////////////
  Connection connection = null;
  Recordset  rset = null;
  Variant    rowCount = new Variant ();
  String     result = null;
  String     query = null;
  String     fieldName = null;
 
  switch (type) {
   case CheckingImpl.NAME_FIELD:
    query = "SELECT CUSTOMER_NAME FROM Checkings WHERE ACCOUNT_NUMBER=";
    fieldName = "CUSTOMER_NAME";
    break;

   case CheckingImpl.BALANCE_FIELD:
    query = "SELECT BALANCE FROM Checkings WHERE ACCOUNT_NUMBER=";
    fieldName = "BALANCE";
    break;
  }
  query += key.m_accountNumber;
 
  try {
   //STEP1 : open the connection
   connection = new Connection ();
   connection.open (CheckingImpl.m_strOpenConn);
 
   //STEP 2: Obtain the desired recordset with a query
   rset = connection.execute (query);
 
   //STEP 3:Get the appropriate fields
   if (!rset.getEOF()) {
    result = rset.getField (fieldName).getString ();
   }
  }
  catch (Exception e) {
   e.printStackTrace ();
  }
  finally {
   // Cleanup that needs to occur whether we leave via a return or exception
   if (rset != null) {
    if (rset.getState () == AdoEnums.ObjectState.OPEN)
     rset.close ();
    ComLib.release (rset);
    rset = null;
   }
 
   if (connection != null) {
    if (connection.getState () == AdoEnums.ObjectState.OPEN)
     connection.close ();
    ComLib.release (connection);
    connection = null;
   }
  }
  return result;
 }

 ////////////////////////////////////////////////////////////////////
 String truePut (int type, CheckingPKImpl key, String balance,
                 String name)
{
 ////////////////////////////////////////////////////////////////////
  Connection connection = null;
  Recordset  rset = null;
  Variant    rowCount = new Variant ();
  String     result = null;
  String     query = null;
 
  switch (type) {
   case CheckingImpl.NAME_FIELD:
    query = "INSERT INTO Checkings VALUES ( '"+ key.m_accountNumber
            +"','"+ name +"','"+balance+"')";
    break;

   case CheckingImpl.BALANCE_FIELD:
    query = "UPDATE Checkings SET BALANCE=" + balance +
            " WHERE ACCOUNT_NUMBER="+ key.m_accountNumber;
    break;

   case CheckingImpl.ALL_FIELDS:
   default:
    query = "INSERT INTO Checkings VALUES ( '"+ key.m_accountNumber
            +"','"+ name +"','"+balance+"')";
    break;
  }
 
  try {
   //STEP1 : open the connection
   connection = new Connection ();
   connection.open (CheckingImpl.m_strOpenConn);
 
   //STEP 2: Obtain the desired recordset with a query
   connection.execute (query);
 
  }
  catch (Exception e) {
   e.printStackTrace ();
  }
  finally {
   // Cleanup that needs to occur whether we leave via a return or exception
   if (rset != null) {
    if (rset.getState () == AdoEnums.ObjectState.OPEN)
     rset.close ();
    ComLib.release (rset);
    rset = null;
   }
 
   if (connection != null) {
    if (connection.getState () == AdoEnums.ObjectState.OPEN)
     connection.close ();
    ComLib.release (connection);
    connection = null;
   }
  }
  return result;
 }

 ////////////////////////////////////////////////////////////////////
 public CheckingImpl () {
 ////////////////////////////////////////////////////////////////////
  System.out.println ("Invoking CheckingImpl::CheckingImpl");
 }
}

4. Build the project
Select the Build menu and Build the project. This creates an MTS component DLL called BankServer.dll. This contains the Class files and all the appropriate stub code so that the DLL can be registered and deployed in MTS.

5. Deploy the DLL into The Microsoft Transaction Server
Start up the MTS Explorer. Go to the computer you want to install your component on and select "Packages Installed". Right click and create a New empty Package called BankServer. Select the newly created BankServer package and create a New Component. Select the Component through the Browse button into MTS. (Make sure you Install New Component rather than Import Components...) The Checking MTS Server component is now deployed on MTS and is ready for client invocations.

click here to go to the
Developing a Bank Account MTS Client Page...
click here to go to
My MTS HomePage...

Go to the Component Engineering Cornucopia page

This site was developed and is maintained by Gopalan Suresh Raj

This page has been visited times since April 26,1999.

Last Updated : Apr 26, '99

If you have any questions, comments, or problems regarding this site, please write to me I would love to hear from you.


Copyright (c) 1997-99, Gopalan Suresh Raj - All rights reserved. Terms of use.

All products and companies mentioned at this site,are trademarks of their respective owners.