/**
   * The main processing loop for this actor. All we do here is call
   * <em>ourSession.shellMainLoop</em>. This allows the shell session to begin processing commands
   * with the proper permissions for invoking the local "impl" commands.
   */
  @pausable
  public void execute() {
    try {
      //      Log.println("<ShellActorImpl.run>: Requesting session reference from service...");
      Object[] invokeArgs = new Object[1];
      invokeArgs[0] = create.constructorArgs[0];
      ourSession =
          (ShellSession) mgrActorInvokeService(manager, Shell.name, "shellProxyInit", invokeArgs);
    } catch (Exception e) {
      // If we get an error here then we have no reliable way of
      // reporting it because the creator of this actor is set to
      // null.  So, just log the error and kill ourselves by calling
      // actorFatalError.
      //      Log.println("Error in run loop of shell actor: " + e);

      // Have to do some handstands to log the stack trace.
      CharArrayWriter temp1 = new CharArrayWriter();
      PrintWriter temp2 = new PrintWriter(temp1, true);
      e.printStackTrace(temp2);
      temp2.close();
      temp1.close();
      //      Log.println(temp1.toString());

      // kill ourselves
      mgrActorFatalError(manager, e);
    }

    // Now initialize our session actor before running it
    //    Log.println("<ShellActorImpl.run>: Received references, initializing session...");
    ourSession.ourActor = self;
    ourSession.ourActorRef = this;
    active = true;

    //    Log.println("<ShellActorImpl.run>: Creating stream aliases...");
    stdinName = ((BasicActorManager) manager).actorCreateAlias(this);
    stdoutName = ((BasicActorManager) manager).actorCreateAlias(this);
    stderrName = ((BasicActorManager) manager).actorCreateAlias(this);

    // When the shell loop exits we are considered in active.  We also
    // close the standard streams at this point.
    ourSession.shellMainLoop();
    try {
      if (stdinStream != null) stdinStream.close();
      if (stdoutStream != null) stdoutStream.close();
      if (stderrStream != null) stderrStream.close();
    } catch (IOException e) {
      // We ignore these since it probably indicates that the
      // connection has already been closed.
    }
    active = false;

    // Even though our shell session has died at this point.  We still
    // need to keep this actor around as our address may have been
    // propagated over the network.  So we just suspend the actor here
    // and rely on garbage collection to eventually clean up old shell
    // actors.
    // suspend();

  }
  /**
   * Receive a new message from our manager. Depending on who the message is targeted to, we may
   * either deliver the message to the shell session by calling <em>ShellSession.newShellMsg</em>,
   * or we may perform a stream operation. In either case, we dump the message if this shell session
   * is no longer active.
   *
   * <p>
   *
   * @param <b>msg</b> The <em>ActorMsgRequest</em> structure to be delivered. This structure must
   *     be maintained by the actor as it is required if an exception is returned to the manager.
   */
  protected void actorDeliver(ActorMsgRequest msg) {
    Object rVal = null;
    String mName = null;
    Object[] mArgs = null;

    try {

      // PRAGMA [debug,osl.service.shell.ShellActorImpl] Log.println("<ShellActorImpl> Handling
      // request: " + msg);
      // We only deliver the message if we are still active (that is,
      // the shell session we are associated with is still running).
      // Otherwise we just dump the message.
      if (active) {
        // What we do depends on who the message is targetted to
        if (msg.receiver.equals(self)) {
          // give the message to our shell session
          ourSession.newShellMsg(msg);
          return;
        }

        // This message should be to one of our stream aliases so
        // handle it.
        try {

          // Decode the name and args
          mName = msg.method;
          mArgs = msg.methodArgs;
          rVal = null;

          if ((mName.equals("asynchException"))
              && (mArgs.length == 2)
              && (mArgs[0] instanceof ActorRequest)
              && (mArgs[1] instanceof Exception)) {
            // We just log these messages.
            // Log.println(this, "Received exception for request: " + mArgs[0]);
            // Log.println(this, "Exception stack trace follows:");
            // Log.logExceptionTrace(this, (Exception)mArgs[1]);
            return;

          } else if (msg.receiver.equals(stdinName)) {
            // this should be a request to the stdin stream we encapsulate
            // If the stream connection was never answered then just dump the message
            if (stdinStream == null) return;

            if ((mName.equals("read")) && (mArgs.length == 0)) {
              rVal = read();

            } else if ((mName.equals("read"))
                && (mArgs.length == 2)
                && (mArgs[0] instanceof ActorName)
                && (mArgs[1] instanceof String)) {
              read((ActorName) mArgs[0], (String) mArgs[1]);

            } else if ((mName.equals("read"))
                && (mArgs.length == 1)
                && (mArgs[0] instanceof Integer)) {
              rVal = read((Integer) mArgs[0]);

            } else if ((mName.equals("read"))
                && (mArgs.length == 3)
                && (mArgs[0] instanceof ActorName)
                && (mArgs[1] instanceof String)
                && (mArgs[2] instanceof Integer)) {
              read((ActorName) mArgs[0], (String) mArgs[1], (Integer) mArgs[2]);

            } else if ((mName.equals("skip"))
                && (mArgs.length == 1)
                && (mArgs[0] instanceof Long)) {
              rVal = skip((Long) mArgs[0]);

            } else if ((mName.equals("skip"))
                && (mArgs.length == 3)
                && (mArgs[0] instanceof ActorName)
                && (mArgs[1] instanceof String)
                && (mArgs[2] instanceof Long)) {
              skip((ActorName) mArgs[0], (String) mArgs[1], (Long) mArgs[2]);

            } else if ((mName.equals("available")) && (mArgs.length == 0)) {
              rVal = available();

            } else if ((mName.equals("available"))
                && (mArgs.length == 2)
                && (mArgs[0] instanceof ActorName)
                && (mArgs[1] instanceof String)) {
              available((ActorName) mArgs[0], (String) mArgs[1]);

            } else if ((mName.equals("close")) && (mArgs.length == 0)) {
              close();

            } else if ((mName.equals("mark"))
                && (mArgs.length == 1)
                && (mArgs[0] instanceof Integer)) {
              mark((Integer) mArgs[0]);

            } else if ((mName.equals("reset")) && (mArgs.length == 0)) {
              reset();

            } else if ((mName.equals("markSupported")) && (mArgs.length == 0)) {
              rVal = markSupported();

            } else if ((mName.equals("markSupported"))
                && (mArgs.length == 2)
                && (mArgs[0] instanceof ActorName)
                && (mArgs[1] instanceof String)) {
              markSupported((ActorName) mArgs[0], (String) mArgs[1]);

            } else if ((mName.equals("readln")) && (mArgs.length == 0)) {
              rVal = readln();

            } else if ((mName.equals("readln"))
                && (mArgs.length == 2)
                && (mArgs[0] instanceof ActorName)
                && (mArgs[1] instanceof String)) {
              readln((ActorName) mArgs[0], (String) mArgs[1]);

            } else {
              // Throw a NoSuchMethodException.
              String argVals = "(";
              for (int i = 0; i < mArgs.length; i++)
                argVals = argVals + mArgs[0].getClass().toString() + ", ";
              argVals = argVals + ")";
              throw new NoSuchMethodException(mName + argVals);
            }
          } else {
            // this is either a request for the stdout or stderr stream we
            // encapsulate
            OutputStream out = (msg.receiver.equals(stdoutName) ? stdoutStream : stderrStream);

            // If the stream connection was never answered then just dump the message
            if (out == null) return;

            if ((mName.equals("write")) && (mArgs.length == 1) && (mArgs[0] instanceof Integer)) {
              write(out, (Integer) mArgs[0]);

            } else if ((mName.equals("write"))
                && (mArgs.length == 1)
                && (mArgs[0] instanceof Byte[])) {
              write(out, (Byte[]) mArgs[0]);

            } else if ((mName.equals("write"))
                && (mArgs.length == 3)
                && (mArgs[0] instanceof Byte[])
                && (mArgs[1] instanceof Integer)
                && (mArgs[2] instanceof Integer)) {
              write(out, (Byte[]) mArgs[0], (Integer) mArgs[1], (Integer) mArgs[2]);

            } else if ((mName.equals("print"))
                &&
                // 			(mArgs.length == 1)             &&
                // 			(mArgs[0] instanceof String) ) {
                (mArgs.length == 1)) {
              print(out, mArgs[0].toString());

            } else if ((mName.equals("println"))
                &&
                // 			(mArgs.length == 1)             &&
                // 			(mArgs[0] instanceof String) ) {
                (mArgs.length == 1)) {
              println(out, mArgs[0].toString());

            } else if ((mName.equals("flush")) && (mArgs.length == 0)) {
              flush(out);

            } else if ((mName.equals("close")) && (mArgs.length == 0)) {
              close(out);

            } else {
              // Throw a NoSuchMethodException.  This will be ignored
              // if the original message is asynchException, in which
              // case we just log it.
              String argVals = "(";
              for (int i = 0; i < mArgs.length; i++)
                argVals = argVals + mArgs[0].getClass().toString() + ", ";
              argVals = argVals + ")";
              throw new NoSuchMethodException(mName + argVals);
            }
          }

          // If this message is an RPC request, then send out the
          // reply message
          if (msg.RPCRequest) {
            Object[] returnIt = new Object[1];
            ActorMsgRequest theReply =
                new ActorMsgRequest(msg.receiver, msg.sender, "__RPCReply", returnIt, false);
            returnIt[0] = rVal;
            theReply.originator = self;
            stampRequest(theReply);

            // PRAGMA [debug,osl.service.shell.ShellActorImpl] Log.println("<ShellActorImpl> Sending
            // reply message: " + theReply);
            mgrActorSend(manager, theReply);
          }

        } catch (Exception e) {
          // Any exception caught here is sent back to the original
          // caller as an asynchException message.
          Object[] args = new Object[2];
          ActorMsgRequest errMsg =
              new ActorMsgRequest(msg.receiver, msg.sender, "asynchException", args, false);
          args[0] = msg;
          args[1] = e;
          errMsg.originator = self;
          stampRequest(errMsg);

          mgrActorSend(manager, errMsg);
        }
      }
    } catch (Throwable e) {
      // Any errors which we fail to trap above are bonafied bugs so
      // we kill ourselves off here.  Note that we ignore ThreadDeath
      // in case this thread was being killed for some strange reason.
      if (e instanceof ThreadDeath) throw (ThreadDeath) e;
      else
        mgrActorFatalError(
            manager, new RemoteCodeException("Error in <ShellActorImpl.actorDeliver>:", e));
    }
  }