The Transfer Package

of the Transfer And Exchange Layer (txlayer)


Editor: T. Beiler (SRB)
@version [CVS] @(#) $Id: index.html,v 1.1 1997/07/28 16:34:52 semper Exp $


Configuration options


Introduction

The package txlayer.transfer contains classes for performing the SEMPER service of transferring goods from one SEMPER application to another.

A transfer is a protocol in which a sender inputs a good g, and in the end a receiver gets as output a good g'. The number of steps in such a protocol is arbitrary and depends on the good to be transferred, and also it is not necessary g = g'. For example, in a payment transfer a transferred coin may change some internal data during a transfer, but the value remains the same. Thus, a transfer is not just a copy operation.

The transfer service is performed by an object of class TransferTransaction. This class serves as a baseclass for the special transfer protocols. It provides the infrastructure to run a transfer protocol and does most of the neccessary administration automatically. Each specific transfer protocol itself is to be implemented by overloading the corresponding methods.

A SEMPER transfer has the notion of a transaction, having the properties of fault tolerance and operational atomicity (Note, that this is not meant cryptographically). The baseclass therefore has the name TransferTransaction.

If an object is to be transferred with the SEMPER transfer service, it has to be known which one form the set of transfer transaction is to be used. The transfer protocol is to be chosen by the object itself, because it knows this best. To indicate that an object knows to do this assignment to a suitable transfer method, it has to implement the interface 'Transferable'.

This package provides a (small) set of transfer protocols for standard cases like transfer of java.util.Vector and objects, for which it suffices to make a remote copy via serialization. These can also be used as subtransfers in composite transfer protocols.

There are two views onto the service of the transfer package. One is the application programmer's view. At this level, someone (mainly the commerce layer) has a group of items and wants to perform a transfer . The second view is for those who provide items or goods, and want to enable them to be transferred by means of a transfer transaction. This is the 'extension programmer's view'. Candidates for being extended are payment, statement, ...

Baseclass TransferTransaction

In theory of transactions, a transaction has to fulfill the ACID properties. This acronym stands for atomicity, consistency, isolation, durability. In this context, the transfer transaction concentrates on the atomicity property. This means, that either a transfer is performed in whole, or if not, the state after the process is the same as before. Note, that atomicity here is not meant in the cryptographical sense, here the correctness of the result depends on the honesty of both participients. For example, if one side decides to commit, there is no way to be sure that the other side really has committed, too. More it is meant in the programming theoretical sense, that all or nothing happens; that the state of the program doesn't get stuck inbetween with some strange intermediate results, but that the transaction is exactly one whole operation from the caller's point of view. The cryptographical atomicity is to be achieved by means of specializations of the transfer protocols, dealing with receipts and so on.

The Flow of a TransferTransaction

To get an understanding what happens inside a transfer transaction, the following figure shows the sequence of steps which is performed:

The sender's and receiver's role are not partitioned in two classes. The role is determined by the prepare-methods. (This is for reasons of overview.) Thus, the left half of the figure reflects a transaction which is configured as sender, and the right reflects a receiver.

The prepare-methods serve to load the object with the necessary data, depending on the role, a sender needs to know the recipient. From the begin()-call on the transaction process runs its own thread, that means it runs autonomously. The send()- and the receive()-method contains the special code for transferring the namely object. This then is the more pure transfer protocol, which distinguishes the different TransferTransactions.

A TransferTransaction object can be visualized as follows:

There are three groups of methods. The first group contains the methods to drive the transaction. These methods are begin(), ..., commit(), and the preparation methods. The second contains methods to do watching of the transaction, these are getStatus(), ..., registerObserver(). The third group is important for the extension programmers. It contains the internal services which are to be used in the implementation of the send method.

The Application Programmer's View

The scenario which an upper layer programmer might find is this: There is a number of goods which are to be transferred from one semper application (sender) to another (receiver).

For the sender this is an example of code:

Have some items to be transferred. These are objects of an example class ItemA.

//--- Create some example items:
1. ItemA itemA = new ItemA("Good #1"); 
2. ItemA itemA2 = new ItemA("Good #2"); 
3. ItemA itemA3 = new ItemA("Good #3"); 

The first two items are grouped by means of a container which is transferable (A so called TransferContainer). To show that this works also nestedly, the third item is put into a second container, which itself is put into the first container.

//--- Put them into _two_ containers, to make things a bit more complicated.
4. TransferContainer tc1 = new TransferContainer(itemA, itemA2); 
5. TransferContainer tc2 = new TransferContainer(itemA3);

//--- Nesting the containers; putting the second into the first:
6. tc1.append(tc2);

Now the container tc can be sent:

//--- Asking for the type of transfer the container desires:
7. TransferTransaction sender_tta = tc.getTransferTransaction();
//--- Preparing: Tell it the receiver's address and make it a sender.
8. sender_tta.prepareToSend(compointAddress_of_Receiver);
//--- Start the transfer process:
9. sender_tta.begin();

//--- For informing the receiver, what transaction he has to expect, 
//--- the getTID() method obtains the transaction's ID:
10. String tid = sender_tta.getTID();
//--- This is just a dummy name, to be filled by the application. 
11. inform_receiver_of_type_and_tid_of_the_transaction_to_expect();

And this is the example code for a receiver:

//--- The communication has to be setup somewhere before.
1. TransferTransaction.classInit();

//--- This again is a dummy name, to be filled by the application. 
2. obtain_type_and_tid_from_sender(); 

//--- A new transaction is being created ...
3. TransferTransaction receiver_tta = new ContainerTransfer();
//--- ... and prepared to be a receiver.
4. receiver_tta.prepareToReceive(expected_tid);
//--- Start the transfer process:
5. receiver_tta.begin();
//--- Wait until the transfer is finished:
6. receiver_tta.join();
//--- Retrieve the result:
7. if(receiver_tta.getStatus == TransferTransaction.COMITTED) {
     TransferContainer result = (TransferContainer)receiver_tta.getObject();
   }
   else complain_about_failure( ;- );

In the synchronous model of semper, the receiver has to be already awaiting a transaction. Therefore, he passed this knowledge in form of the transaction identifier (tid) to a class method of the class TransferTransaction. The result of the transfer is the then newly created transaction. When the transfer has successfully ended, the method getObject() retrieves the received object.

The Extension Programmer's View

Since the TransferTransaction is an abstract class, the objects performing the transfer will be subclasses. This subclasses normally will just to have to overload the send and the receive-method. They do not deal with administration stuff and recovery. Two examples are given to show how an extension might work:

  • A SerializingTransfer performs a transfer of any arbitrary serializable object by using serialization, that means it simply serializes the object and transmits it.
  • //--- This class code is self-commentating.
    class SerializingTransfer extends TransferTransaction {
      private Serializable _s;
    
      public SerializingTransfer() {}
      public SerializingTransfer(Serializable s) { _s = s; }
      
      protected void send() { write(_s); }
      protected void receive() { _s = (Serializable)read(); }
    }
  • An example of a transfer of a composite object is VectorTransfer:
  • public class VectorTransfer extends TransferTransaction {
      //--- The Vector to be transferred.
      Vector _v = null;
    
      public VectorTransfer() {}
      public VectorTransfer(Vector v) { _v = v; }
    
      //--- Overloading the sender's half.
      protected void send() { 
        //--- The vector containing the subtransfers.
        Vector w = new Vector();
    
        //--- Temporary vector containing the names of subtransfer types.
        Vector x = new Vector();
        //--- Temporary reference.
        TransferTransaction tta = null;
        
        //--- For all elements in vector _v: get transfer object; 
        //--- prepare it to send; put in vector w holding the subtransfers.
        //--- Furthermore, fill temporary vector x.
        for(int i=0; i < _v.size(); i++) {
          tta = ((Transferable)_v.elementAt(i)).getTransferTransaction();
          tta.prepareToSend(_cpa, _tid+"."+i);
          w.addElement(tta);
          x.addElement(tta.getClass());
        }
    
        //--- Write the type-vector, for receiver knows 
        //--- what kinds of subtransfers to expect.
        write(x);
    
        //--- Perform the subtransactions:
        for(int i=0; i < w.size(); i++) {
          ((TransferTransaction)w.elementAt(i)).begin();
        }
    
        //--- Waiting for the subtransactions to finish.
        //--- The semantic of Transaction::join() is the same
        //--- as Thread::join()
        for(int i=0; i < w.size(); i++) {
          ((TransferTransaction)w.elementAt(i)).join();
        }
    
        //--- Now check the outcome:
        for(int i=0; i < w.size(); i++) {
          if( ((TransferTransaction)w.elementAt(i)).getStatus() == 
              TransferTransaction.ABORTED) abort();
          // And don't forget to tell the other subtransactions to abort ...
        }
        commit();
      }
      
      //--- Overloading the receiver's half.
      protected void receive() { 
        //--- The vector containing the subtransfers.
        Vector w = new Vector();
    
        //--- Temporary vector containing the names of subtransfer types.
        Vector x = (Vector)read();
        //--- Temporary reference.
        TransferTransaction tta = null;
        
        
        //--- For all elements in vector _x: get class name of subtransfer;
        //--- instantiate a new TransferTransaction object from it; 
        //--- prepare it to receive.
        for(int i=0; i < x.size(); i++) {
          try {
            tta = (TransferTransaction) ((Class)x.elementAt(i)).newInstance();
            w.addElement(tta);
            tta.prepareToReceive(_tid+"."+i);
            tta.begin();
          } catch(Exception e) { e.printStackTrace(); }
        }
        
        //--- Waiting for the subtransactions to finish.
        for(int i=0; i < w.size(); i++) {
          ((TransferTransaction)w.elementAt(i)).join();
        }
    
        //--- Now check the outcome:
        for(int i=0; i < w.size(); i++) {
          if( ((TransferTransaction)w.elementAt(i)).getStatus() 
              == TransferTransaction.ABORTED) abort();
        }
    
        //--- If the program control is here, the outcome was not to abort.
        //--- Therefore, the new Vector can be assembled.
        _v = new Vector();
        for(int i=0; i < w.size(); i++) {
          _v.addElement(((TransferTransaction)w.elementAt(i)).getObject());
        }
        //--- All is ok and successful: commit now.
        commit();
      }
      
      public Object getObject() { 
        return _v; 
      }
    }

    Note that in the sender() method it is not really neccessary to have four loops. The first two could be in one, since the begin() method returns at once (thread). The loops three and four could also be in one; it is not necessary to wait until all subtransfers have finished if it is clear that the transaction is to be aborted. It is four loops for more clarity.

    How to Write an Extension

    This section is a step-by-step manual for the owners / programmers of existing Classes desired to be Transferable.  Two main steps are to follow: 

    Making a class Transferable

    The Interface Transferable has exactly one method which must be implemented. It is the factory method

    The object providing this is requested to create a subclass of TransferTransaction of its choice. Doing this choice of a suitable subclass of TransferTransaction fofr the particular class has of course to be done by the programmer. Code example:  Suppose a SerializingTransfer is to be chosen. Then implementing the Transferable interface is as simple as this:

    This is example is the simpliest one. The method also might choose the protocol dynamically, and it might record the TransferTransaction itself for some reason, etc....

    At the moment there are three flavours supported by the txlayer. These are

    If unfortunately no suitable transfer class is available yet, it has to be programmed before doing using the mewly transferable class. This is explained in the next subsection.

    Extending the class TransferTransaction

    To be done first: Invent a protocol. Dicide if it is token based or not. Then, these are methods which may be overloaded:

    Constructors. There have to be two constructors for the new subclass:

    Runninng the protocol: There are two interfaces with the invocation of the protocol, a token-based interface, and sequential read/write interface.

    Retrieving the result: Since the field representing the transferable is bound to a particular type, it is not anticipated in the superclass. As a consequence the method

    has to be implemented. But this is probably an easy exercise.

    Further thinking: Some considerations not yet mentioned have to be done. These are:

    ---> That's it for the moment. The next thing then is to explain how to use hooks on Transaction specific operation and where they are (Have to think myself about this), and why all this is the way it is. Thank you for your attention.

    Remarks

  • TransferTransactions do not consider cycles in object structures. This leads to the effect that if two items in one container reference the same object, the receiver gets two different dereferencees.
  • The security attributes are evaluated by the transfer itself. This might be done inside a transaction by plugging into the data flow in the read and write methods.
  • The communication model inside a transaction for subclassers would be more elegant, if on arrival of data a processTransferMessage() method were automatically called by the transaction logic. The read() and write() would be obsolete then, and an automata logic could be handled by the superclass. But unfortunetely, java's lack of method pointers would be revealing.
  • Much of the stuff that the class TransferTransaction does belongs to Transactions, those without 'transfer'. In the sooner future, this will be found in the Transaction class in the txlayer.transaction package. TransferTransaction will derived from this, and also be abstract soon. But I can't see a point how this would affect the use of TransferTransactions. So this remark is just for information.

  • Configuration options

    There is a hidden feature in the class NRTransfer that enables a confirmation from the user when an NRToken is to be signed. Add the following line into your _sempconfig file:
    	#semper.txlayer.askBeforeSign 1