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 }