0

so I have been working on a long project trying to understand the basics of multi threading and the use of sockets but I seem to stumble into some sort of a block, not sure where its coming from.

the application is supposed to simulate a storage which is the server side, a shop which is the client/server and then shop itself have clients of her own.

sometimes I get "NullPointerException" at the switch/case method processInput at Warehouse.java (code will be added below), and the program doesn't seem to release the lock on the first while loop at the .run method in Shop.Java.

Main.Java

    package exe6;

public class Main {

    static Thread mainThread = Thread.currentThread();

    public static void main(String[] args) throws InterruptedException{
        Box box = new Box();
        PayPalAcc pp1 = new PayPalAcc();
        mainThread.setName("mainThread");

        Thread DaniCustomerThread = new Thread(new Customer(box, pp1, "Daniel Netzer"), Customer.getName());
        Thread POShopThread = new Thread(new Shop(box, pp1, "Post Office"), Shop.getName());
        Thread WareHouse = new Thread(new Warehouse(), "Warehouse");

        WareHouse.start();
        DaniCustomerThread.start();
        POShopThread.start();

        Thread.sleep(3*60*100);


        POShopThread.interrupt();
        DaniCustomerThread.interrupt();
    }
}

Shop.java

    package exe6;

import java.net.*;

import java.io.*;

public class Shop implements Runnable{

    private static Box box;
    private static PayPalAcc paypal;
    private static String name;

    // Threads Monitors
    private static Object shopBox = new Object();
    private static Object shopPP = new Object();
    private static Object shopIS = new Object();

    // Socket Variables/Properties
    private static final String hostName = "Localhost";
    private static final int portNumber = 1234;

    static boolean isInStorage = false;

    // Getters/Setters/Constructors
    public Shop(Box box,PayPalAcc paypal, String name){
        Shop.box = box;
        Shop.name = name;
        Shop.setPaypal(paypal);
    }

    public static Object getShopBoxMonitor(){
        return Shop.shopBox;
    }

    public static int getShopPort(){
        return portNumber;
    }

    public static Object getShopWHMonitor(){
        return Shop.shopIS;
    }

    public static Object getShopPPMonitor() {
        return Shop.shopPP;
    }

    public static String getName() {
        return name;
    }

    private static PayPalAcc getPaypal() {
        return paypal;
    }

    private static synchronized void setPaypal(PayPalAcc paypal) {
        Shop.paypal = paypal;
    }

    //Shop Methods
    //Depositing a package into a selected box.
    private synchronized void  depositBox(){
        Shop.box.setBoxStatus(true);
        printsShop(1);
        synchronized(Customer.getCustomerLockMonitor()){
            Customer.getCustomerLockMonitor().notify();}
    }

    //Withdrawing money from selected PayPal account.
    private synchronized void withdrawFromPayPal(int amountToWithdraw){
        Shop.getPaypal().setPayPalAccStatus(Shop.getPaypal().getPayPalAccStatus() - amountToWithdraw);
        printsShop(2);
    }

    //Switch/Case to hold all shop printable.
    private synchronized void  printsShop(int caseNum){
        switch(caseNum){
        case 1: System.out.println(Shop.getName() +" deposited new package in " +Customer.getName() +" box.");
                break;
        case 2: System.out.println(Shop.getName() +" withdrawed money from shared PayPal account.");
                break;
        case 3: System.out.println(Shop.getName() +" box is full, waiting for customer withdrawal.");
                break;
        case 4: System.out.println(Customer.getName() +" did not deposited money into PayPal account yet.");
                break;
        case 5: System.out.println("Program have finished, closing safely " +Thread.currentThread().getName() +" thread.");
                break;
        }
    }

    public static void clientSocket(){
        try (
                Socket ShopSocket = new Socket(hostName, portNumber);
                PrintWriter out = new PrintWriter(ShopSocket.getOutputStream(), true);
                BufferedReader in = new BufferedReader(
                    new InputStreamReader(ShopSocket.getInputStream()));) {
            BufferedReader stdIn =
                    new BufferedReader(new InputStreamReader(System.in));
                String fromServer;
                String fromUser;

                while (!Shop.isInStorage) {
                    fromServer = in.readLine();
                    System.out.println("Warehouse Response: " + fromServer);

                    fromUser = stdIn.readLine();
                    if (fromUser != null) {
                        System.out.println("Shop Query: " + fromUser);
                        out.println(fromUser);
                    }
                }
                synchronized(Shop.getShopWHMonitor()){ Shop.getShopWHMonitor().notify(); };   
            } catch (UnknownHostException e) {
                System.err.println("Don't know about host " + hostName);
                System.exit(1);
            } catch (IOException e) {
                System.err.println("Couldn't get I/O for the connection to " +
                    hostName);
                System.exit(1);
            }
    }

    //Thread operations.
    @Override
    public void run() {
        while(Main.mainThread.isAlive()){
            while (!isInStorage) {
                clientSocket();
                synchronized(Shop.getShopWHMonitor()){ 
                    try {
                        Shop.getShopWHMonitor().wait();
                    } catch (InterruptedException e) {
                        printsShop(5);
                        Thread.currentThread().interrupt();
                        break;
                    } 
                }

                while(Shop.getPaypal().getPayPalAccStatus() < 100){
                    synchronized(Shop.getShopPPMonitor()){
                        try {
                            printsShop(4);
                            Shop.getShopPPMonitor().wait();
                        } catch (InterruptedException e) {
                            printsShop(5);
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                    withdrawFromPayPal(100);

                    while(box.isBoxStatus()){
                        synchronized(Shop.getShopBoxMonitor()){
                            try {
                                printsShop(3);
                                Shop.getShopBoxMonitor().wait();
                            } catch (InterruptedException e) {
                                printsShop(5);
                                Thread.currentThread().interrupt();
                                break;
                            }
                        }
                    }
                }
            }
            depositBox();
            isInStorage = false;
            if (Thread.currentThread().isInterrupted()) { break; }
        }
    }
}

Warehouse.java

    package exe6;

import java.net.*;
import java.io.*;

public class Warehouse implements Runnable{

    private static final String WAITING = "";
    private static final String CHECKREQUEST = "Check if Package is in warehouse.";
    static final String SENTREQUEST = "Request Package.";
    static final String SENTREQUEST_RESPONSE = "Package have been sent to " +Shop.getName() +".";
    private static final String CHECKREQUEST_RESPONSE = "The pacakge is availble in the warehouse.";
    private static final String WAITING_RESPONSE = "Waiting for shop query.";
    private static final String DEFAULT_RESPONSE = "Query inserted is not legal.";

     public static synchronized String processInput(String theInput) {
            String theOutput = null;

            switch(theInput){
                case WAITING: theOutput = WAITING_RESPONSE;
                    break;
                case CHECKREQUEST: theOutput = CHECKREQUEST_RESPONSE;
                    break;
                case SENTREQUEST: { theOutput = SENTREQUEST_RESPONSE;
                                    Shop.isInStorage = true;
                                    synchronized(Shop.getShopWHMonitor()){ Shop.getShopWHMonitor().notify(); }
                                    }
                    break;
                default: theOutput = DEFAULT_RESPONSE;
                }

            return theOutput;
        }

    @Override
    public void run() {
        while(Main.mainThread.isAlive()){
            try ( 
                    ServerSocket WHSocket = new ServerSocket(Shop.getShopPort());
                    Socket ShopSocket = WHSocket.accept();
                    PrintWriter out =
                            new PrintWriter(ShopSocket.getOutputStream(), true);
                    BufferedReader in = new BufferedReader(
                            new InputStreamReader(ShopSocket.getInputStream()));
                    ) {

                String inputLine, outputLine;

                // Initiate conversation with client
                outputLine = processInput("");
                out.println(outputLine);

                while (!Shop.isInStorage) {
                    inputLine = in.readLine();
                    outputLine = processInput(inputLine);
                    out.println(outputLine);
                }
            } catch (IOException e) {
                System.out.println("Exception caught when trying to listen on port "
                        + Shop.getShopPort() + " or listening for a connection");
                System.out.println(e.getMessage());
            }
        }
    }
}

I would also appreciate very much any design and coding advices.

EDIT: As someone mentioned it as a duplicate for a NullPointerException, I would like to point that the main issue here is not the Null pointer since I can easily overcome it by avoiding any null strings into the Server Reader function, the real issue I'm trying to overcome in this question is the inability to use the RESPOND from the warehouse which is the Server Side as a .notify() and therefor release the Shop Runnable from waiting as the program cease to advance.

Daniel Netzer
  • 2,151
  • 14
  • 22
  • 1
    Design advice: a shop needs a warehouse to function, and a customer needs a shop in order to be considered a customer. Try putting these as parameters in the constructors, rather than sharing them as static variables. To anyone looking at the "main" method, it is unclear how the customer, warehouse, and shop know about each other. – Andrew Williamson Dec 28 '15 at 16:57
  • Also, http://codereview.stackexchange.com/ is a better place to go for questions like this. – Andrew Williamson Dec 28 '15 at 16:59
  • there are 2 more java files i havent included in the question which is the box and the paypal account which are shared for the customer and the shop. but I understand what your intentions are. does codereview is valid for none working code? – Daniel Netzer Dec 28 '15 at 17:00

0 Answers0