An active instance of the payment service block will contain the following objects:
PaymentManager object
(in reality, the PaymentManager is a static class.)
Purse objects
PaymentTransaction objects (each corresponding
to an ongoing purse transaction)
PaymentTransactionRecord and one Evidence
objects for each PaymentTransaction object. (Note: these are
created each time an
PaymentTransaction is created. But the PaymentTransaction
object is discarded once the transaction is over while the
PaymentTransactionRecord is stored for longer periods.
It is not clear yet if PaymentTransactionRecord and
Evidence should be merged into one).
Figure 1: A Payment Service Block in Action
(Courtesy Günter Karjoth)
The functionality expected from payment systems is captured in the
PurseServices interface hierarchy. The root
PurseServices interface contains methods corresponding to
services expected from all payment systems. Additional services
that are specific to various payment models is captured in sub-interfaces
that extend the root interface.
- PurseServices -+--- AccountBasedPurseServices
|
|
|
+--- CashLikePurseServices
|
|
These interfaces describe the generic purse services required by the
various payment models. These will be implemented by:
the PaymentTransaction subclass (see below) corresponding to
each payment system of the appropriate model.
Generic purses that are optional are defined separately. An example
is the MicropaymentService interface. Each category of
optional services will be in the form of a parallel interface
hierarchy similar to the PurseServices hierarchy.
It is not mandatory for the subclasses of the Transaction
class to implement the optional part of the purse services interface.
- Purse-+--- AccountBasedPurse -+---AbcPurse
| |
| +---....
|
+--- CashLikePurse -------+---....
| |
| +---....
A purse is a repository of information related an installed payment
system. As with the PurseServices hierarchy, the
Purse class hierarchy has a root class and model-specific
subclasses of it.
- PaymentTransaction -+--- AbcTransaction
|
|
|
+--- ....
|
Objects of this class hierarchy are the primary objects in the payment
service block for providing payment services. A
PaymentTransaction
object can
be thought of as an abstraction of a "transaction." The root class
simply provides the functionality of a generic "transaction" (e.g.: methods
to abort and to status check). Each payment system is required to have a subclass
of the PaymentTransaction class that implement the
PurseServices interfaces (both regular and grouped) for
its payment model.
Note that we could have abstract subclasses AccountBasedTransaction and
CashLikeTransaction and then make AbcTransaction a subclass of one of
these classes. We have not done this at this time because there
doesn't seem to be a need for it (if defined, such classes would be empty
at least as of now). If it becomes necessary, they can always be
defined.
Currently, the model-specific functionality provided by the
transaction objects is expressed by the corresponding sub-interface in the
PurseServices
interface hierarchy. Functionality expected from a generic transaction is
expressed by the PaymentTransaction class. The adapter of a
payment system will subclass the PaymentTransaction
class to inherit
specifications of the generic transaction functionality and implement
the model-specific PurseServices sub interface to inherit
specifications of the model-specific functionality.
Hence there is no need for the aforementioned intermediate
subclasses of PaymentTransaction.
Finally, note that subclass designers should ensure that only methods
corresponding to a single transaction are executed on an
PaymentTransaction object. (e.g. if someone creates an
PaymentTransaction object, invokes pay() on it and
then attempts to make another invocation of a purse service on the same object, the
second attempt must be disallowed; however multiple invocations of
doMicroPayment() or capture() on the same PaymentTransaction
object is legal).
PaymentTransaction object keeps any data with
long-term relevance in a corresponding
PaymentTransactionRecord object. Recall that the latter
object is the one that is archived after the transaction is complete.
Typically, the designer of the adapter for a payment system will
subclass the PaymentTransactionRecord class.
exchangeCurrency), and
PaymentManager class is an implementation of the above.
To incorporate a payment system into the payment service block, the following are necessary:
PaymentTransaction class which
implements the purse services defined in the interface corresponding
to the appropriate payment model, AbcTransaction class that implements:
AccountBasedPurseServices interface, and
MicropaymentServices interface)
PaymentTransactionRecord
class. If necessary, a subclass of the
PaymentTransactionRecord class may be defined and
used to suit the needs of specific payment systems.
Purse class,
implementing all abstract methods in the Purse class.
AbcPurse class that extends:
AccountBasedPurse class.
CreatePurse
method of the
PaymentManager) or to "install" a new payment
module into the payment service block. The class
PurseManagement
provides a set of methods to
facilitate the creation and configuration of purses using
interaction via Tinguin.
Each adapter will have to provide certain standard methods that
are used by the PaymentManager and
PurseManagement classes. Currently, these are all
expected from the subclass of the Purse class. They
are:
init() to initialise the purse during
startup, and
setup() to perform configuration of a
purse via user interaction.
Default implementations are available in the root
Purse class.
Also, if a payment system provides more functionality than
the what is assumed by the SEMPER payment service block model,
special business applications will be necessary to configure, and
use such functionality.
If a payment system does not provide a particular service required by
the corresponding interface, the adapter still has to implement a
cover method that returns a "not implemented" error/exception.
Note that if trusted I/O is required by an object in the payment service
block during the execution of such a special business application, it
may have to deal directly with TINGUIN (and not via the access control
manager).
In this section, we give brief examples of usage:
Here is what the user does:
Simultaneously, the shop does the following:
The above assumes that
Individual payment modules should be in packages like
Purse Transactions
For each transaction, there will be a corresponding PaymentTransaction object.
The caller would do something like:
Here are some examples of usage:
abcTr1 = (AbcTransaction) abcPurse1.startTransaction(<parameters>);
abcTr1.pay(<parameters>);
abcTr1 = (AbcTransaction) abcPurse1.startTransaction(<parameters>);
abcTr1.startMicropayment (<parameters>);
abcTr1.doMicropayment (<parameters>);
[...]
abcTr1.doMicropayment (<parameters>);
abcTr1.stopMicropayment (<parameters>);
status = abcTr1.status();
or
abcTr1.abort();
Protocols
Initially at least, only a simple negotiation protocol will be
implemented. Messages in the negotiation protocol will be in the form
of a list of lists. Each secondary list is used to negotiate the value
of a single parameter (e.g. "payment service name"). The head of this
list will be an object of the MessageListHead class.
It contains the following attributes:
The PaymentManager provides various methods such as
choosePS and requestPSChoice to negotiate
the selection of payment systems. Further, there are methods for
local selection as well (for example, based on preferences,
or interaction with the user). Different purse selection
policies can be implemented by combining these methods in different
ways. A pair of methods selectPayingPurse and
selectReceivingPurse implementing a particular policy
are also provided in the PaymentManager class.
Currently, we plan for synchronous negotiations between two
payment managers.
Later, we may extend this to asynchronous negotiations, and
negotiations between two PaymentTransaction objects.
Interaction with the User
[to be done]
Notes
PurseManagement
class.
In addition,
each payment system will come with special business applications to
create a purse and perform additional system-specific tasks.
Interactions with Other Blocks
initalise() method of the
PaymentManager> will attempt to load the
its preference group from the preference manager; if none
exists, one will be created with initial defaults. Each purse
should also do the same.
Issues
In this section, we list proposed or forthcoming changes to the design
and issues that need to be discussed:
PurseServices interface:
Using the Payment Service Block
Transfer Manager in the SEMPER transfer layer is likely to be the
commonest user of services from the Payment Service Block. However,
as mentioned before special Business Applications that manipulate the
configuration of the payment service block will interact directly with
objects in the payment service block. Also, in principle, there is
nothing to prevent normal Business Applications or the Commerce Layer
to interact directly with these objects as well.
Simple Payment
Scenario: A user "Alice" wants to make a payment of 100 PST to a
shop, "Bob Inc.".
The shop is at bob.com. The user and the
shop have already started a commerce session. They agree to use a
common external reference string (we assume that this is available in
the variable ext_ref) to identify this session. They have
also not selected any specific payment mechanisms but would like to
leave it to their respective payment service blocks to negotiate it.
// seller's address
// The port number and path have no relevance -- so we just use placeholders
ComPointAddress seller_addr = new ComPointAddress ("tcp", "bob.com", 0, "");
PaymentEntity seller = new PaymentEntity ("Bob Inc.", seller_addr);
// We don't want to use any specific alias (just the name we have on
// the selected purse)
String my_alias = null;
// We have no preferences about the means of payment
Vector preferred_payment_systems = null;
Vector preferred_purses = null;
// We have no security options
Vector options = null;
// Create a single element array for external reference so that we
// can receive it as a return parameter if necessary.
String a_ext_ref[] = { ext_ref };
// Now select a purse -- this involves negotiation with peer
PurseReference chosen_purse = PaymentManager.selectPayingPurse
(seller, my_alias, amount, preferred_payment_systems,
preferred_purses, options, ext_ref);
Purse chosen_purse = chosen_purse_ref.getPurse();
// carry out the payment
PaymentTransaction tr = chosen_purse.startTransaction();
tr.pay(seller, amount, options, a_ext_ref);
// our address (PaymentManager.init() had already registered this address
// with the communication manager
// The port number and path have no relevance -- so we just use placeholders
ComPointAddress seller_addr = new ComPointAddress ("tcp", "bob.com", 0, "");
PaymentEntity seller = new PaymentEntity ("Bob Inc.", seller_addr);
// We don't particularly care for the buyer's address since they will open
// a channel to us with the agreed upon "ext_ref"
PaymentEntity buyer = null;
// The rest, as with the buyer side
Vector preferred_payment_systems = null;
Vector preferred_purses = null;
Vector options = null;
String a_ext_ref[] = { ext_ref };
// Now select a purse -- this involves negotiation with peer
PurseReference chosen_purse = PaymentManager.selectReceivingPurse
(buyer, seller, amount, preferred_payment_systems,
preferred_purses, options, ext_ref);
Purse chosen_purse = chosen_purse_ref.getPurse();
// receive the payment
PaymentTransaction tr = chosen_purse.startTransaction();
tr.receivePayment(buyer, amount, options, a_ext_ref);
Since these are not yet available, any test program should do the
necessary initialisation by itself. The test programs
PaymentManager and
each purse has already been executed. This will be done by the SEMPER
startup business application.
Seller.java and Buyer.java in the
Test directory of the source are examples of such test programs.
Forthcoming Changes
PurseServices methods is not a return parameter
(has not been for a while now). Therefore, we plan to make it a
simple String instead of the one-element array of
String since the kluge for a return parameter is no
longer necessary.
pay() and
receivePayment() synchronously. However, with
minor changes, the payment block can easily support an
asynchronous scenario. We propose to define the additional
service definitions required for the asynchronous model as an
optional PurseServices interface.
Miscellany
The payment service block will be in package
semper.payment.
The documentation includes an index
and a
tree depicting the class structure.
semper.payment.ecash. The semper.payment
package is unaware of
the various individual modules. Each payment module may provide an
"installer/configurator" application which can use the services that
have been already provided,such as
createPurse
and those in the
PurseManagement class as well as any additional
services speicific to that payment module.