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.