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.