Designing RMI Applications
import java.rmi.*; import java.rmi.server.*; /* Has timer-based lock management on server-side */ public class Account3_Impl extends UnicastRemoteObject implements Account3 { private static final int TIMER_DURATION = 120000; // Two minutes private static final int THREAD_SLEEP_TIME = 10000; // 10 seconds private Money _balance; private String _currentClient; private int _timeLeftUntilLockIsReleased; public Account3_Impl(Money startingBalance) throws RemoteException { _balance = startingBalance; _timeLeftUntilLockIsReleased = 0; new Thread(new CountDownTimer()).start(); } public synchronized Money getBalance() throws RemoteException, LockedAccountException { checkAccess(); return _balance; } public synchronized void makeDeposit(Money amount) throws RemoteException, LockedAccountException, NegativeAmountException { checkAccess(); checkForNegativeAmount(amount); _balance.add(amount); return; } public synchronized void makeWithdrawal(Money amount) throws RemoteException, OverdraftException, LockedAccountException, NegativeAmountException { checkAccess(); checkForNegativeAmount(amount); checkForOverdraft(amount); _balance.subtract(amount); return; } private void checkAccess() throws LockedAccountException { String clientHost = wrapperAroundGetClientHost(); if (null == _currentClient) { _currentClient = clientHost; } else { if (!_currentClient.equals(clientHost)) { throw new LockedAccountException(); } } resetCounter(); return; } private void resetCounter() { _timeLeftUntilLockIsReleased = TIMER_DURATION; } private void releaseLock() { if (null != _currentClient) { _currentClient = null; } } private String wrapperAroundGetClientHost() { String clientHost = null; try { clientHost = getClientHost(); } catch (ServerNotActiveException ignored) { } return clientHost; } private void checkForNegativeAmount(Money amount) throws NegativeAmountException { int cents = amount.getCents(); if (0 > cents) { throw new NegativeAmountException(); } } private void checkForOverdraft(Money amount) throws OverdraftException { if (amount.greaterThan(_balance)) { throw new OverdraftException(false); } return; } /** The expire thread */ private class CountDownTimer implements Runnable { public void run() { while (true) { try { Thread.sleep(THREAD_SLEEP_TIME); } catch (Exception ignored) { } synchronized (Account3_Impl.this) { if (_timeLeftUntilLockIsReleased > 0) { _timeLeftUntilLockIsReleased -= THREAD_SLEEP_TIME; } else { releaseLock(); } } } } } }
35 of 49