001 package org.cocome.tradingsystem.testdriver;
002
003 import java.rmi.AccessException;
004 import java.rmi.NotBoundException;
005 import java.rmi.RMISecurityManager;
006 import java.rmi.RemoteException;
007 import java.rmi.registry.LocateRegistry;
008 import java.rmi.registry.Registry;
009 import java.rmi.server.UnicastRemoteObject;
010 import java.util.HashMap;
011 import java.util.Map;
012
013 import org.cocome.tradingsystem.external.Debit;
014 import org.cocome.tradingsystem.external.TransactionID;
015 import org.cocome.tradingsystem.systests.interfaces.IBank;
016
017 /**
018 * Implementation of a bank that we can control (as opposed to the bank coming
019 * with the implementation).
020 *
021 * @author Benjamin Hummel
022 * @author $Author: hummel $
023 * @version $Rev: 63 $
024 * @levd.rating GREEN Rev: 63
025 */
026 public class Bank extends UnicastRemoteObject implements IBank,
027 org.cocome.tradingsystem.external.Bank {
028
029 /** The offset added to create a transaction ID from a card number. */
030 private static final int TID_OFFSET = 42;
031
032 /** Create a new Bank. */
033 protected Bank() throws RemoteException {
034 super();
035 register();
036 }
037
038 /** ID for serialization in the RMI context. */
039 private static final long serialVersionUID = 1556930771225198542L;
040
041 /** All available credit cards. */
042 private final Map<Integer, CreditCard> creditCards = new HashMap<Integer, CreditCard>();
043
044 /** Register at RMI. */
045 private void register() throws AccessException, RemoteException {
046 if (System.getSecurityManager() == null) {
047 System.setSecurityManager(new RMISecurityManager());
048 }
049 Registry reg = LocateRegistry.getRegistry("localhost", 1098);
050 reg.rebind("Bank", this);
051 }
052
053 /** Unregister from RMI. */
054 public void unregister() throws AccessException, RemoteException,
055 NotBoundException {
056 Registry reg = LocateRegistry.getRegistry("localhost", 1098);
057 reg.unbind("Bank");
058 }
059
060 /** {@inheritDoc} */
061 public void createCreditCard(int cardNumber, int pinNumber,
062 int availableMoney) {
063 creditCards.put(cardNumber, new CreditCard(pinNumber, availableMoney));
064 }
065
066 /** {@inheritDoc} */
067 public void deleteCreditCard(int cardNumber) {
068 creditCards.remove(cardNumber);
069 }
070
071 /** {@inheritDoc} */
072 public int getAvailableMoney(int cardNumber) {
073 return creditCards.get(cardNumber).money;
074 }
075
076 /** {@inheritDoc} */
077 public Debit debitCard(TransactionID id) throws RemoteException {
078 int number = findCardFromTID(id);
079 if (number < 0) {
080 return Debit.TRANSACTION_ID_NOT_VALID;
081 }
082
083 CreditCard cc = creditCards.get(number);
084 if (cc == null) {
085 return Debit.TRANSACTION_ID_NOT_VALID;
086 }
087
088 // We have to use a simple approach here, as the reference
089 // implementation does not care about the amount of money
090 if (cc.money > 0) {
091 return Debit.OK;
092 }
093 return Debit.NOT_ENOUGH_MONEY;
094 }
095
096 /**
097 * Extract the card number from a transaction ID. This is not an efficient
098 * method, but the TransactionID class does not provide any access to its
099 * internals and also does not implement hashCode (although it should, when
100 * overriding equals).
101 *
102 * @return the number of the credit card contained in this TID, or -1 if no
103 * matching card was found.
104 */
105 private int findCardFromTID(TransactionID id) {
106 for (int ccNumber : creditCards.keySet()) {
107 if (new TransactionID(ccNumber + TID_OFFSET).equals(id)) {
108 return ccNumber;
109 }
110 }
111 return -1;
112 }
113
114 /** {@inheritDoc} */
115 public TransactionID validateCard(String cardInformation, int pinnumber)
116 throws RemoteException {
117 int cardNumber;
118 try {
119 cardNumber = Integer.parseInt(cardInformation);
120 } catch (NumberFormatException e) {
121 return null;
122 }
123
124 CreditCard cc = creditCards.get(cardNumber);
125 if (cc == null || cc.pin != pinnumber) {
126 return null;
127 }
128
129 // we use the card number plus an offset for the transaction ID (not
130 // perfect, but works in this context)
131 return new TransactionID(cardNumber + TID_OFFSET);
132 }
133
134 /** Data storage for credit card. */
135 private static final class CreditCard {
136 /** The pin code of the card. */
137 private final int pin;
138
139 /** The available money for the card. */
140 private int money;
141
142 /** Create a new card. */
143 public CreditCard(int pinNumber, int availableMoney) {
144 this.pin = pinNumber;
145 this.money = availableMoney;
146 }
147 }
148 }