public void run() {
    DOMParser p = new DOMParser();
    int numRounds = DEFAULT_NUM_ROUNDS;
    double timeAllowed = DEFAULT_TIME_ALLOWED;
    double timeUsed = 0;
    try {
      BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
      InputStreamReader isr = new InputStreamReader(is);
      InputSource isrc = readOneMessage(isr);
      requestedInstance = null;
      processXMLSessionRequest(p, isrc, this);
      System.out.println(requestedInstance);

      if (!rddl._tmInstanceNodes.containsKey(requestedInstance)) {
        System.out.println("Instance name '" + requestedInstance + "' not found.");
        return;
      }

      BufferedOutputStream os = new BufferedOutputStream(connection.getOutputStream());
      OutputStreamWriter osw = new OutputStreamWriter(os, "US-ASCII");
      String msg = createXMLSessionInit(numRounds, timeAllowed, this);
      sendOneMessage(osw, msg);

      initializeState(rddl, requestedInstance);
      // System.out.println("STATE:\n" + state);

      double accum_total_reward = 0;
      ArrayList<Double> rewards = new ArrayList<Double>(DEFAULT_NUM_ROUNDS * instance._nHorizon);
      int r = 0;
      for (; r < numRounds; r++) {
        isrc = readOneMessage(isr);
        if (!processXMLRoundRequest(p, isrc)) {
          break;
        }
        resetState();
        msg = createXMLRoundInit(r + 1, numRounds, timeUsed, timeAllowed);
        sendOneMessage(osw, msg);

        System.out.println("Round " + (r + 1) + " / " + numRounds);
        if (SHOW_MEMORY_USAGE)
          System.out.print(
              "[ Memory usage: "
                  + _df.format((RUNTIME.totalMemory() - RUNTIME.freeMemory()) / 1e6d)
                  + "Mb / "
                  + _df.format(RUNTIME.totalMemory() / 1e6d)
                  + "Mb"
                  + " = "
                  + _df.format(
                      ((double) (RUNTIME.totalMemory() - RUNTIME.freeMemory())
                          / (double) RUNTIME.totalMemory()))
                  + " ]\n");

        double accum_reward = 0.0d;
        double cur_discount = 1.0d;
        int h = 0;
        HashMap<PVAR_NAME, HashMap<ArrayList<LCONST>, Object>> observStore = null;
        for (; h < instance._nHorizon; h++) {

          // if ( observStore != null) {
          //	for ( PVAR_NAME pn : observStore.keySet() ) {
          //		System.out.println("check3 " + pn);
          //		for( ArrayList<LCONST> aa : observStore.get(pn).keySet()) {
          //			System.out.println("check3 :" + aa + ": " + observStore.get(pn).get(aa));
          //		}
          //	}
          // }
          msg = createXMLTurn(state, h + 1, domain, observStore);
          if (SHOW_MSG) System.out.println("Sending msg:\n" + msg);
          sendOneMessage(osw, msg);

          isrc = readOneMessage(isr);
          if (isrc == null) throw new Exception("FATAL SERVER EXCEPTION: EMPTY CLIENT MESSAGE");

          ArrayList<PVAR_INST_DEF> ds = processXMLAction(p, isrc, state);
          if (ds == null) {
            break;
          }
          // Sungwook: this is not required.  -Scott
          // if ( h== 0 && domain._bPartiallyObserved && ds.size() != 0) {
          //	System.err.println("the first action for partial observable domain should be noop");
          // }
          if (SHOW_ACTIONS) System.out.println("** Actions received: " + ds);

          try {
            state.computeNextState(ds, 0, rand);
          } catch (Exception ee) {
            System.out.println("FATAL SERVER EXCEPTION:\n" + ee);
            // ee.printStackTrace();
            throw ee;
            // System.exit(1);
          }
          // for ( PVAR_NAME pn : state._observ.keySet() ) {
          //	System.out.println("check1 " + pn);
          //	for( ArrayList<LCONST> aa : state._observ.get(pn).keySet()) {
          //		System.out.println("check1 :" + aa + ": " + state._observ.get(pn).get(aa));
          //	}
          // }
          if (domain._bPartiallyObserved) observStore = copyObserv(state._observ);

          // Calculate reward / objective and store
          double reward =
              ((Number)
                      domain._exprReward.sample(
                          new HashMap<LVAR, LCONST>(), state, rand, new BooleanPair()))
                  .doubleValue();
          rewards.add(reward);
          accum_reward += cur_discount * reward;
          // System.out.println("Accum reward: " + accum_reward + ", instance._dDiscount: " +
          // instance._dDiscount +
          //   " / " + (cur_discount * reward) + " / " + reward);
          cur_discount *= instance._dDiscount;

          stateViz.display(state, h);
          state.advanceNextState();
        }
        accum_total_reward += accum_reward;
        msg = createXMLRoundEnd(r, accum_reward, h, 0);
        if (SHOW_MSG) System.out.println("Sending msg:\n" + msg);
        sendOneMessage(osw, msg);
      }
      msg = createXMLSessionEnd(accum_total_reward, r, 0, this.clientName, this.id);
      if (SHOW_MSG) System.out.println("Sending msg:\n" + msg);
      sendOneMessage(osw, msg);

      BufferedWriter bw = new BufferedWriter(new FileWriter(LOG_FILE, true));
      bw.write(msg);
      bw.newLine();
      bw.flush();

      // need to wait 10 seconds to pretend that we're processing something
      //			try {
      //				Thread.sleep(10000);
      //			}
      //			catch (Exception e){}
      //			TimeStamp = new java.util.Date().toString();
      //			String returnCode = "MultipleSocketServer repsonded at "+ TimeStamp + (char) 3;
    } catch (Exception e) {
      e.printStackTrace();
      System.out.println("\n>> TERMINATING TRIAL.");
    } finally {
      try {
        connection.close();
      } catch (IOException e) {
      }
    }
  }