Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

The AccountServerFactory (itself a Factory pattern instance) is responsible for

ID: 3670245 • Letter: T

Question

The AccountServerFactory (itself a Factory pattern instance) is responsible for creating the AccountServer. However, there should only be one AccountServer object in the entire application, but AccountServerFactory does not implement this constraint right now. Refactor AccountServerFactory to implement a full Singleton pattern. Note: You must NOT modify any code outside of AccountServerFactory to get this pattern to work!

public class AccountServerFactory {

   public AccountServerFactory() {

   }

   public IAccountServer getAccountServer() {

       return new ServerSolution();

   }

}

Explanation / Answer

Main.java

import javax.swing.JFrame;

final class Main {
   /**
   * Private constructor to address STYLE issue.
   */

   private Main() {
   }
  
   /**
   * All methods should have a Javadoc according to STYLE.
   * @param args command-line arguments
   * @throws Exception as per typical main specifications
   */
   public static void main(final String[] args) throws Exception {

       if (args.length != 1) {
           System.out.println("Usage: java FormMain <property file>");
           System.exit(1);
       }

       String propertyFile = args[0];
       JFrame frame = new MainFrame(propertyFile);
       frame.setVisible(true);

   }
}

MainFrame.java

import javax.swing.JFrame;


final class Main {
   /**
   * Private constructor to address STYLE issue.
   */

   private Main() {
   }
  
   /**
   * All methods should have a Javadoc according to STYLE.
   * @param args command-line arguments
   * @throws Exception as per typical main specifications
   */
   public static void main(final String[] args) throws Exception {

       if (args.length != 1) {
           System.out.println("Usage: java FormMain <property file>");
           System.exit(1);
       }

       String propertyFile = args[0];
       JFrame frame = new MainFrame(propertyFile);
       frame.setVisible(true);

   }
}

Account.java


public abstract class Account implements java.io.Serializable {
    private static final long serialVersionUID = 1L;

    protected enum State {
        OPEN, CLOSED, OVERDRAWN
    };

    protected float balance = 0.0F;
    protected String _name;
    private State _state;

    protected Account(String n) {
        _name = n;
        _state = State.OPEN;
    }

    protected Account(String n, float b) {
        this(n);
        balance = b;
    }

    /**
     Method: getName()
     Inputs:none
     Returns:name of the Account
   
     Description:returns the Account
     */
    public final String getName() {
        return _name;
    }
    /**
     Method: getBalance()
     Inputs:none
     Returns:balance in the Account
   
     Description:gets the balance of an account
     */

    public final float getBalance() {
        return balance;
    }
    /**
     Method: deposit()
     Inputs:none
     Returns:balance in the Account
   
     Description:Adds money to an account. May not be done if the account is CLOSED
     @param parameter
                amount is a deposit and must be > 0
     @return true if the deposit was successful, false if not due to amount or
              invalid state
     */

    public abstract boolean deposit(float amount);

    /**
     Method: withdrawl()
     Inputs:amount
     Returns:Checking or Savings
   
     Description:     * Takes money out of an account. If the balance falls below 0 then the
     * account is moved to an OVERDRAWN state
     *
     * @param parameter
     *            amount is a withdrawal and must be > 0
     * @return true if the deposit was successful, false if not due to amount or
     *         invalid state
     */
  
    public abstract boolean withdraw(float amount);

    /**
     * @return either "Checking" or "Savings"
     */
  
    /**
     Method: getType()
     Inputs:none
     Returns:type
   
     Description:returns the Type
     */
  
    public abstract String getType();

  
    /**
     Method: _getState()
     Inputs:none
     Returns:state
   
     Description:returns the State
     */
    protected final State _getState() {
        return _state;
    }

  
    /**
     Method: _getState()
     Inputs:state
     Returns:final state
   
     Description:returns the final State
     */
    protected final void _setState(State s) {
        _state = s;
    }

  
    /**
     Method: getString()
     Inputs:none
     Returns:string
   
     Description:converts account name balance and state to string
   
     */
    public String toString() {
        return "Account " + _name + " has $" + balance + "and is " + getState()
                + " ";
    }
}

AccountServer.java

import java.io.IOException;
import java.util.List;

public interface AccountServer {

   /**
     Method: _newAccount()
     Inputs:type name and balance
     Returns:boolean
   * Create a new account object in the server. if an account already exists with the given name
   * then a new account is not created and stored.
   *
       @param type must be one of Savings or Checking
       @param name leading or trailing whitespace is removed
       @param balance must be non-negative
       @throws IllegalArgumentException if the account type is invalid or the balance is non-negative.
       @return boolean true if the account was created and stored, false otherwise
   */
   public boolean   newAccount(String type, String name, float balance) throws IllegalArgumentException;

   /**
     Method: closeAccount()
     Inputs:name
     Returns:sobect or null
   
     Close an account
       @param name leading or trailing whitespace is removed
   * @return boolean true if there was an account with this name and close was successful
   */
   public boolean   closeAccount(String name);

   /**
     Method: getAccount()
     Inputs:name
     Returns:list
   * @param name name of the account
   * @return Account object or null if not found.
   */
   public Account   getAccount(String name);

   /**
     Method: getAllAccount(s)
     Inputs:name
     Returns:a list of accounts
   * @return a list of all Accounts inside the server
   */
   public List<Account> getAllAccounts();

   /**
     Method: getActiveAccounts()
     Inputs:none
     Returns:list of all accounts
   * @return a list of Accounts inside the server that are not CLOSED
   */
   public List<Account> getActiveAccounts();

   /**
     Method: saveAccounts()
     Inputs:none
     Returns:nothing
   * Saves the state of the server
   * @throws IOException if unable to save the state
   */
   public void   saveAccounts() throws IOException;
}

AccountServerFactory.java


public class AccountServerFactory {

   protected static AccountServerFactory singleton = null;

   protected AccountServerFactory() {

   }

   public static AccountServerFactory getMe() {
       if (singleton == null) {
           singleton = new AccountServerFactory();
       }

       return singleton;
   }
    /**
     Method: lookup()
     Inputs:none
     Returns:serverSolution

     Description: looks up ServerSolution
     */
   public AccountServer lookup() {
       return new ServerSolution();
   }
}

Checking.java

public class Checking extends Account {

   private static final long serialVersionUID = 11L;
   private int numWithdraws = 0;
  
   private Checking(String name) {
       super(name);
   }

    /**
     Method:createChecking()
     Inputs:name
     Returns: new name
   
     Description:Creates checking account
     */
    public static Checking createChecking(String name) {
        return new Checking(name);
    }

   public Checking(String name, float balance) {
       super(name, balance);
   }
  
    /**
     Method: desposit()
     Inputs:amount
     Returns:boolean
   
     Description:A deposit may be made unless the Checking account is closed @param float is the deposit amount
     */
   public boolean deposit(float amount) {
       if (getState() != State.CLOSED && amount > 0.0f) {
           balance = balance + amount;
           if (balance >= 0.0f) {
               setState(State.OPEN);
           }
           return true;
       }
       return false;
   }
    /**
     Method: withdrawl()
     Inputs:amount
     Returns:boolean
   
     Description:After 10 withdrawals a fee of $2 is charged per transaction You may
     * continue to withdraw an overdrawn account until the balance is below -$100
     */
  
   public boolean withdraw(float amount) {
       if (amount > 0.0f) {      
           // KG: incorrect, last balance check should be >=
           if (getState() == State.OPEN || (getState() == State.OVERDRAWN && balance > -100.0f)) {
               balance = balance - amount;
               numWithdraws++;
                if (numWithdraws > 10){
                   balance = balance - 2.0f;
                }
                if (balance < 0.0f){
                   setState(State.OVERDRAWN);
                }
               return true;
           }
       }
       return false;
   }

    /**
     Method: getType()
     Inputs:none
     Returns:Checking type
   
     Description:returns the Checking type of account
     */
  
   public String getType() { return "Checking"; }
  
    /**
     Method: toString()
     Inputs:none
     Returns:converts the name and balance of checking account to a string
   
     Description:returns the Checking type of account
     */
   public String toString() {
       return "Checking: " + getName() + ": " + getBalance();
   }
}

Savings.java

public class Savings extends Account {
   private static final long serialVersionUID = 111L;
   private int numWithdraws = 0;

   public Savings(String name) {
       super(name);
   }

   public Savings(String name, float balance) throws IllegalArgumentException {
       super(name, balance);
   }

   /**
     /**
     Method: deposit()
     Inputs:amount
     Returns:boolean
     * Create a new account object in the server. if an account already exists with the given name
     * then a new acc
   * A deposit comes with a fee of 50 cents per deposit
   */
   public boolean deposit(float amount) {
       if (getState() != State.CLOSED && amount > 0.0f) {
           balance = balance + amount - 0.50F;
           if (balance >= 0.0f) {
               setState(State.OPEN);
           }
       }
       return false;
   }

   /**
     Method: withdrawl()
     Inputs:amount
     Returns:boolean
   * A withdrawal. After 3 withdrawals a fee of $1 is added to each withdrawal.
   * An account whose balance dips below 0 is in an OVERDRAWN state
   */
   public boolean withdraw(float amount) {
       if (getState() == State.OPEN && amount > 0.0f) {
           balance = balance - amount;
           numWithdraws++;
           if (numWithdraws > 3)
               balance = balance - 1.0f;
           // KG BVA: should be < 0
           if (balance <= 0.0f) {
               setState(State.OVERDRAWN);
           }
           return true;
       }
       return false;
   }
    /**
     Method: getType()
     Inputs:none
     Returns:type!

     */
   public String getType() { return "Savings"; } //return wrong type

    /**
     Method: toString()
     Inputs:none
     Returns:string of name and balance
   
     */
   public String toString() {
       return "Savings: " + getName() + ": " + getBalance();
   }
}

ServerSolution.java

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.io.*;

class ServerSolution implements AccountServer {

   static String fileName = "accounts.ser";

   Map<String,Account> accountMap = null;

   public ServerSolution() {
       accountMap = new HashMap<String,Account>();
       File file = new File(fileName);
       ObjectInputStream in = null;
       try {
           if (file.exists()) {
               System.out.println("Reading from file " + fileName + "...");
               in = new ObjectInputStream(new FileInputStream(file));

               Integer sizeI = (Integer) in.readObject();
               int size = sizeI.intValue();
               for (int i=0; i < size; i++) {
                   Account acc = (Account) in.readObject();
                   if (acc != null)
                       accountMap.put(acc.getName(), acc);
               }
           }
       } catch (Exception e) {
           System.out.println(e.getMessage());
           e.printStackTrace();
       } finally {
           if (in != null) {
               try {
                   in.close();
               } catch (Throwable t) {
                   t.printStackTrace();
               }
           }
       }
   }
  
    /**
     Method: _newAccountFactory(String type, String name, float balance)
     Inputs:String type, String name, float balance
     Returns:boolean
   
     Description:checks if account is valid
     */
   private boolean _newAccountFactory(String type, String name, float balance)
       throws IllegalArgumentException {
      
       if (accountMap.get(name) != null) return false;
      
       Account acc;
       if ("Checking".equals(type)) {
           acc = new Checking(name, balance);

       } else if ("Savings".equals(type)) {
           acc = new Savings(name, balance);

       } else {
           throw new IllegalArgumentException("Bad account type:" + type);
       }
       try {
           accountMap.put(acc.getName(), acc);
       } catch (Exception exc) {
           return false;
       }
       return true;
   }

    /**
     Method: newAccount(String type, String name, float balance)
     Inputs:String type, String name, float balance
     Returns:boolean
   
     Description:creates new account
     */
   public boolean newAccount(String type, String name, float balance)
       throws IllegalArgumentException {
      
       if (balance < 0.0f) throw new IllegalArgumentException("New account may not be started with a negative balance");
      
       return newAccountFactory(type, name, balance);
   }

  
    /**
     Method: closeAccount(String name)
     Inputs:String name
     Returns:boolean
   
     Description:closes an account
     */
   public boolean closeAccount(String name) {
       Account acc = accountMap.get(name);
       if (acc == null) {
           return false;
       }
       acc.setState(State.CLOSED);
       return true;
   }

    /**
     Method: getAccount(String name)
     Inputs:String name
     Returns:Account name
   
     Description:returns the Account
     */
   public Account getAccount(String name) {
       return accountMap.get(name);
   }

    /**
     Method: getAllAccount()
     Inputs:none
     Returns:Array List of all the Accounts
   
     Description:returns the Account
     */
   public List<Account> getAllAccounts() {
       return new ArrayList<Account>(accountMap.values());
   }

    /**
     Method: getActiveAccount()
     Inputs:none
     Returns:active accounts
   
     Description:returns the Account
     */
   public List<Account> getActiveAccounts() {
       List<Account> result = new ArrayList<Account>();

       for (Account acc : accountMap.values()) {
           if (acc.getState() != State.CLOSED) {
               result.add(acc);
           }
       }
       return result;
   }
    /**
     Method: saveAccounts()
     Inputs:none
     Returns: none
   
     Description:saves account
     */
   public void saveAccounts() throws IOException {
       ObjectOutputStream out = null;
       try {
           out = new ObjectOutputStream(new FileOutputStream(fileName));

           out.writeObject(Integer.valueOf(accountMap.size()));
           for (int i=0; i < accountMap.size(); i++) {
               out.writeObject(accountMap.get(i));
           }
       } catch (Exception e) {
           e.printStackTrace();
           throw new IOException("Could not write file:" + fileName);
       } finally {
           if (out != null) {
               try {
                   out.close();
               } catch (Throwable t) {
                   t.printStackTrace();
               }
           }
       }
   }

}