package COM.xinit.demon.co.uk.3tier.database;

import java.io.*;
import java.net.*;
import java.util.*;
import msql.*;
import database.*;

public class dbProxy implements Runnable {


    int listenPort = 5500;
    int alternatePort = listenPort;
    RulesThread checkIt;
    ServerSocket myServer = null;
    Socket answerSocket;
    Database myDB;

   public void init(String databaseServer) { 
   // listen() gets called from main() & tries to create the Server Socket,
   // using an alternate port if it fails

	try {
	    myDB = new Database (databaseServer);
	} catch (MsqlException e) {
	    System.out.println ("Error connecting to Database at " +
	    databaseServer);
	} 

        try { 
            myServer = new ServerSocket(listenPort,5);
        } catch (IOException e) {
	    System.out.println(e.toString());

            listenPort = alternatePort++;

            System.out.println("Unable to create Server Socket," + 
                "trying alternate port " + alternatePort);
        } // close catch   


        System.out.println("Notify all clients that the current Server Port"
         + " is " + listenPort );
    } //end listen


    public void run() {
        // loop forever, waiting to accept connections

	for(;;) {

            try {
                answerSocket = myServer.accept();
            } catch (IOException e) { 
                return; 
            }

            // put the socket connection on its own thread, so my ServerSocket
            // can go back to listen for new connection requests
            System.out.println("Accepted connection from client");
            checkIt = new RulesThread(answerSocket, this);

            // Have to be polite, so my other threads can run()
            Thread.yield();

        } 
    } 


    public static void main(String args[]) {

        // Test to see if any argument was passed - need the hostname of the
 	// database server

        if (args.length < 1) {
            System.out.println ("Usage: java dbProxy <DatabaseHostname>");
            System.exit (1);
        }

        // create an instance of this class

        dbProxy myHandler = new dbProxy();

        // start up the Server Socket

        String databaseServer = args[0];
        myHandler.init(databaseServer);

        // construct a new thread & tell it to find run() in myHandler's class
        Thread myThread = new Thread (myHandler);

        // answer those client requests
        myThread.start();
    } 
} 


class RulesThread extends Thread {
    Database myDB;
    Socket talkToMe;
    DataOutputStream sendStream;
    DataInputStream recvStream;
    boolean success = true;
    dbProxy myHandler;

    private static final int BUYSHARES      = 10;    
    private static final int SELLSHARES     = 20;    
    private static final int READSTOCKLIST  = 30;    
    private static final int READASTOCK     = 40;    
    private static final int READCUSTLIST   = 50;    
    private static final int VIEWACUSTOMER  = 60;    
    private static final int ADDACUSTOMER   = 70;    
    private static final int UPDATECUSTOMER = 80;    
    private static final int DELETECUSTOMER = 90;    

    public RulesThread (Socket s, dbProxy parent){

        talkToMe = s;
        myHandler = parent;
        myDB = parent.myDB;

        try {

            sendStream = new DataOutputStream(talkToMe.getOutputStream());
            recvStream = new DataInputStream(talkToMe.getInputStream());

        } catch (IOException e) { 
            System.out.println("Error in RulesThread creating Input or Output Stream");
            success = false;
        }

        if (success) {
            this.start();
        } else {
            return;
        }
    } 


    // The specific methods for marshalling each request

    // readStockList - reads the current list of stock and prices
    // and returns them

    public void readStockList () throws IOException {

        StockRec s[] =  myDB.getAllStocks();
        if (s.length <= 0) {
            sendStream.writeInt(-1);
            System.out.println("Error in READSTOCKLIST");
            return;
        } else {
            sendStream.writeInt(s.length);
            for (int i=0;i < s.length;i++) {
                sendStream.writeUTF(s[i].getSymbol());
                sendStream.writeFloat(s[i].getPrice());
            }
        }

    }


    // readCustList - reads the current list of customers -
    // name and ssn 
    public void readCustList () throws IOException {
        // Get the customer list (if one exists)
        CustomerRec cr[] =  myDB.getAllCustomers();
        if (cr.length <= 0) {
            sendStream.writeInt(-1);
            System.out.println("Error in READCUSTLIST"); 
               return;
        } else {
            sendStream.writeInt(cr.length);
            for (int i=0;i < cr.length;i++) {
                sendStream.writeUTF(cr[i].ssn);
                sendStream.writeUTF(cr[i].name);
                sendStream.writeUTF(cr[i].addr);
            }
        }

    } 


    public void readAStock (String id) throws IOException {

        // make the database call to return the current price
        float price = myDB.getStockPrice(id);
        if (price == -1.0f) {
            sendStream.writeInt(-1);
            System.out.println("Error in READASTOCK"); 
            return;
        } else {
            sendStream.writeInt(0);
            sendStream.writeFloat(price);
        }    

    } 


    public void viewACustomer (String id) throws IOException {

        //make the database call to verify that the customer exists
        if (verifyCustomerExists(id) == -1) {
            sendStream.writeInt(-1);
            System.out.println("Customer doesn't exist"); 
            return;
        } else {
            try { 
                CustomerRec aCustomer = myDB.getCustomer(id);
                //send the customer info back 

                sendStream.writeInt(0);
                sendStream.writeUTF(aCustomer.ssn);
                sendStream.writeUTF(aCustomer.name);
                sendStream.writeUTF(aCustomer.addr);
        
                // Check to see if there are any SharesRec objects in
                // the portfolio, return zero if there aren't any ...
                // First check to see if the portfolio is not null - T.McG
                int size = 0;
                if (aCustomer.portfolio != null) {
                    size = ((Vector)(aCustomer.portfolio)).size();
                }

                if (size == 0) {
                    sendStream.writeInt(0);
                } else { 
                    // otherwise, return the number of SharesRec objects
                    sendStream.writeInt(size);
                    // and the symbol/price pairs
                    for (int j=0; j < size; j++) {
                        sendStream.writeUTF(((SharesRec)(aCustomer.portfolio.elementAt(j))).symbol);
                        sendStream.writeInt(((SharesRec)(aCustomer.portfolio.elementAt(j))).quantity);
                    }
                }
            } catch (RecordNotFoundException e) {
                sendStream.writeInt(-1);
                System.out.println("Error in VIEWACUSTOMER");  
                return;
            }
        }
    } 


    public void deleteCustomer (String id) throws IOException {

        //make the database call to verify that the customer exists
        if (verifyCustomerExists(id) == -1) {
            sendStream.writeInt(-1);
            System.out.println("Customer doesn't exist"); 
            return;
        } else {
            //make the database call to delete the customer
            try {
                myDB.deleteCustomer(id);
                sendStream.writeInt(0);
            } catch (RecordNotFoundException e) { 
                sendStream.writeInt(-1);
                System.out.println("Error in DELETECUSTOMER");  
                return;
            }
        }

    } 



    public void updateCustomer (String ssn, String name, String addr)
    throws IOException {
        // if customer doesn't exist, return error code
        if (verifyCustomerExists(ssn) == -1) {     
            sendStream.writeInt(-1);
                System.out.println("Error in UPDATECUSTOMER");  
                return;
        } else {
            try {
                // Database's updateCustomer is a little odd -
                // the arguments are name, ssn, addr - T.McG
                myDB.updateCustomer (name, ssn, addr);
                sendStream.writeInt(0);
            } catch (RecordNotFoundException e) {
                sendStream.writeInt(-1);
                System.out.println("Error in UPDATECUSTOMER");  
                return;
            }
        }

    }



    public void addACustomer (String ssn, String name, String addr)
    throws IOException {
        // if customer already exists, return error code
        if (verifyCustomerExists(ssn) == 0) {
            sendStream.writeInt(-1);
                System.out.println("Error in ADDACUSTOMER");  
                return;
        } else {
            try {
                    // Database's addCustomer is a little odd -
                    // the arguments are name, ssn, addr - T.McG
            // myDB.addCustomer(ssn,name,addr);
                    myDB.addCustomer(name, ssn, addr);
            sendStream.writeInt(0);
            } catch (Exception e) {
            sendStream.writeInt(-1);
                    System.out.println("Error in ADDACUSTOMER");
            return;
            }
        }
    } 


    public void buyShares (String ssn, String stock, int qty)
    throws IOException {
        //make the database call to verify that the customer exists
        if (verifyCustomerExists(ssn) == -1) {
            sendStream.writeInt(-1);
            System.out.println("Customer doesn't exist");
            return;
        }

        // verify that qty > 0, and make the database call to buy
        if (qty <= 0) {
            sendStream.writeInt(-3);
            System.out.println("Error in BUYSHARES: invalid number");
            return;
        } else {
            try {
                myDB.buyShares(ssn,stock,qty);
                sendStream.writeInt (0);
            } catch (RecordNotFoundException e) {
                sendStream.writeInt(-1);
                System.out.println("Error in BUYSHARES");              
                return;
            }
        }

    }


    public 
    void 
    sellShares (String ssn, String stock, int qty)
    throws IOException {

        //make the database call to verify that the customer exists

        if (verifyCustomerExists(ssn) == -1) {
            sendStream.writeInt(-1);
            System.out.println("Customer doesn't exist");
            return;
        }

        // make the database call to verify that I have that many
        // shares to sell, and if I do, make the call to sell them
        try{
            Vector myVector = myDB.getPortfolio(ssn);
            SharesRec sr[] = new SharesRec[myVector.size()];
            int i = 0;
            // Search the portfolio for this stock
            for (; i < myVector.size(); i++) {
                sr[i] = (SharesRec)myVector.elementAt(i);
                if (sr[i].symbol.equals(stock)) {
                    break;
                }
            }

            int curQty = sr[i].quantity;
            if (qty > curQty) {
                sendStream.writeInt(-3);
                System.out.println("Error in SELLSHARES: invalid number");
                return;
            } else {
                if (qty == curQty) {
                    myDB.sellShares(ssn,stock);
                     sendStream.writeInt (0);  
                } else {
                    myDB.sellShares(ssn, stock, qty);
                    sendStream.writeInt (0);
                }
            }
        } catch (Exception e) {
            sendStream.writeInt(-1);
            System.out.println("Error in SELLSHARES");
            return;
        }

    } 

    // General purpose method to validate customer ssn
    public int verifyCustomerExists(String ssn) {
        if (myDB.ssnExists(ssn)) {
            return (0);
           } else {
            return (-1);
        }
    
    }



    public void run() {

        // get the client command, pass it through the business rules, 
        // make the appropriate database call(s) & send the result back


        for (;;) {

            // wait for the client command

            try {
                int command = recvStream.readInt();

            // based on the command we receive, we know how many and
            // what types of reads need to be made from the inputstream

            switch (command) {
                case READSTOCKLIST:
                    readStockList ();
                    break;

                case READCUSTLIST:
                    readCustList ();
                    break;

                case VIEWACUSTOMER:
                    viewACustomer (recvStream.readUTF());
                    break;

                case READASTOCK:
                    readAStock (recvStream.readUTF());
                    break;

                case DELETECUSTOMER:
                    deleteCustomer (recvStream.readUTF());
                    break;

                case UPDATECUSTOMER:
                    updateCustomer (recvStream.readUTF(), 
		    	recvStream.readUTF(), recvStream.readUTF());
                    break;

                case ADDACUSTOMER:
                    addACustomer (recvStream.readUTF(), 
		    	recvStream.readUTF(), recvStream.readUTF());
                    break;

                case BUYSHARES:
                    buyShares (recvStream.readUTF(), 
		    	recvStream.readUTF(), recvStream.readInt());
                    break;

                case SELLSHARES:
                    sellShares (recvStream.readUTF(), 
		    	recvStream.readUTF(), recvStream.readInt());
                    break;

                default:
                    try { 
                        // Tell client that we received an invalid command
                        sendStream.writeInt(-4); 
                    } catch (IOException e) {
                        System.out.println("Failed to write error condition to client");
                        stop();
                    }

            }

            // Yeild to the other threads and drop back 
	    // into my blocking readInt
            this.yield(); 
 
            } catch (Exception e) {
                System.out.println ("Error reading command value from client");
                System.out.println (e.toString());
                System.out.println("Closing connection to client");
                try {
                    recvStream.close();
                    sendStream.close();
                } catch (IOException e9) {}
                    return;
            }
        }
    }
} 



Last Updated