title: Java RMI server side threading
body: <p>I'm just getting started with RMI and I'm trying to write a simple program that simulates a train booking system.  I have the basics set up - Server, Client, and a Remote object exported.  It works fine with one Client connection.  However when more than 1 Client connects, the Clients seem to be executing in the same thread.  This is the case when I run multiple Clients on the same machine or when I connect a Client from another laptop.</p>
  
  <p>I was under the impression that RMI handled threading on the server side?  If not, how do I go about handling multiple Client connections given the code below?</p>
  
  <p>Here are the classes of interest.</p>
  
  <p>Server.....</p>
  
  <pre><code>public class Server {
  
      public Server() {
          try {
              Booking stub = (Booking) UnicastRemoteObject.exportObject(new BookingProcess(), 0);
              Registry registry = LocateRegistry.getRegistry();
              registry.bind("Booking", stub);
              System.err.println("Server Ready");
          } catch (RemoteException e) {
              System.err.println("Server exception: " + e.toString());
              e.printStackTrace();
          } catch (AlreadyBoundException e) {
              System.err.println("Server exception: " + e.toString());
              e.printStackTrace();
          }
      }
  
      public static void main(String[] args) {
          Server server = new Server();
      }
  
  }
  </code></pre>
  
  <p>BookingProcess.....(I've left out the private methods that processInput(String input) uses)</p>
  
  <pre><code>public class BookingProcess implements Booking {
  
      private static Journey dublinGalway = new Journey("Dublin to Galway");
      private static Journey dublinLimerick = new Journey("Dublin to Limerick");
      private static Journey dublinCork = new Journey("Dublin to Cork");
      private Journey currentJourney;
  
      private enum State {
          INITIAL, JOURNEYS_DISPLAYED, JOURNEY_CHOSEN, ANOTHER_BOOKING_OFFERED, SOLD_OUT;
      }
  
      private State currentState = State.INITIAL;
  
      public synchronized String processInput(String input) {
          String output = "";
  
          if(currentState == State.INITIAL) {
              if(bookedOut()) {
                  output = "Sorry, there are no seats remaining on any route. Get the bus.";
                  currentState = State.SOLD_OUT;
              }
              else {
                  output = "Please choose a journey to book: " + "1: " + dublinGalway.getDescription() + ", 2: " + dublinLimerick.getDescription() + ", 3: " + dublinCork.getDescription();
                  currentState = State.JOURNEYS_DISPLAYED;
              }
          }
  
          else if(currentState == State.JOURNEYS_DISPLAYED) {
              output = this.processJourneyChoice(input);
          }
  
          else if(currentState == State.JOURNEY_CHOSEN) {
              output = "Do you wish to confirm this booking? (y/n)";
              if(input.equalsIgnoreCase("y")) {
                  if(bookingConfirmed()) {
                      output = "Thank you. Your journey from " + currentJourney.getDescription() + " is confirmed. Hit return to continue.";
                      //currentState = State.ANOTHER_BOOKING_OFFERED;
                  }
                  else {
                      output = "Sorry, but the last seat on the " + currentJourney.getDescription() + " route has just been booked by another user.";
                      //currentState = State.ANOTHER_BOOKING_OFFERED;
                  }
                  currentState = State.ANOTHER_BOOKING_OFFERED;
              }
              else if(input.equalsIgnoreCase("n")) {
                  output = "You have cancelled this booking. Hit return to continue.";
                  currentState = State.ANOTHER_BOOKING_OFFERED;
              }
          }
  
          else if(currentState == State.ANOTHER_BOOKING_OFFERED) {
              output = "Would you like to make another booking? (y/n)";
              if(input.equalsIgnoreCase("y")) {
                  output = "Hit Return to continue.";
                  currentState = State.INITIAL;
              }
              else if(input.equalsIgnoreCase("n")){
                  output = "Goodbye.";
                  try {
                      Thread.currentThread().join(10);
                  } catch (InterruptedException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
                  }
                  currentState = State.INITIAL;
              }
          }
  
          else if(currentState == State.SOLD_OUT) {
              output = "Goodbye.";
          }
  
          return output;
      }
  </code></pre>
  
  <p>And finally Client......</p>
  
  <pre><code>public class Client {
  
      public static void main(String[] args) {
          Client client = new Client();
          client.runClient();
      }
  
      public void runClient() {
  
          try {
              BufferedReader consoleInput = new BufferedReader(new InputStreamReader(System.in));
              Registry registry = LocateRegistry.getRegistry("localhost");
              Booking stub = (Booking) registry.lookup("Booking");
              String serverResponse = stub.processInput("begin");
              System.out.println("Server: " + serverResponse);
  
              while((serverResponse = stub.processInput(consoleInput.readLine())) != null) {
                   System.out.println(serverResponse);
                   if(serverResponse.equals("Goodbye.")) {
                          break;
                   }
              }
          } catch (Exception e) {
              System.err.println("Client exception " + e.toString());
              e.printStackTrace();
          }
      }
  
  
  }
  </code></pre>