Package com.sun.grid.jgrid.proxy

Source Code of com.sun.grid.jgrid.proxy.ComputeProxy

/*************************************************************************
*
*  The Contents of this file are made available subject to the terms of
*  the Sun Industry Standards Source License Version 1.2
*
*  Sun Microsystems Inc., March, 2001
*
*
*  Sun Industry Standards Source License Version 1.2
*  =================================================
*  The contents of this file are subject to the Sun Industry Standards
*  Source License Version 1.2 (the "License"); You may not use this file
*  except in compliance with the License. You may obtain a copy of the
*  License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
*
*  Software provided under this License is provided on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
*  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
*  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
*  See the License for the specific provisions governing your rights and
*  obligations concerning the Software.
*
*   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
*   Copyright: 2001 by Sun Microsystems, Inc.
*
*   All Rights Reserved.
*
************************************************************************/
/*
* ComputeProxy.java
*
* Created on June 19, 2002, 4:52 PM
*/

package com.sun.grid.jgrid.proxy;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.AccessException;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.StubNotFoundException;
import java.rmi.dgc.Lease;
import java.rmi.dgc.VMID;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.ObjID;
import java.rmi.server.UID;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.*;

import sun.rmi.server.MarshalOutputStream;
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.TransportConstants;

import com.sun.grid.jgrid.Computable;
import com.sun.grid.jgrid.Job;

/** This class pretends to be an RMI registry and an RMI server
* in order to intercept RMI communications and feed them through
* an instance of the Sun Grid Engine.
* @author Daniel Templeton
* @version 1.9
* @deprecated This class has been superceeded by ComputeServer as of 0.2.1
* @since 0.1
*/
public class ComputeProxy implements Runnable {
  /** The usage information String
   */ 
  private static final String USAGE =
    "Usage: java -Djava.rmi.server.codebase=codebase " +
    "com.sun.grid.jgrid.proxy.ComputeProxy [-d job_path] " +
    "[-sub submit_command] [-skel skeleton_command] [-p port] [-debug] [-help]";
  /** The ObjID for the registry
   */ 
  private static final ObjID REGISTRY_OID = new ObjID (ObjID.REGISTRY_ID);
  /** The number of the bind method on the Registry
   */ 
  private static final int REGISTRY_OP_BIND = 0;
  /** The number of the list method on the Registry
   */ 
  private static final int REGISTRY_OP_LIST = 1;
  /** The number of the lookup method on the Registry
   */ 
  private static final int REGISTRY_OP_LOOKUP = 2;
  /** The number of the rebind method on the Registry
   */ 
  private static final int REGISTRY_OP_REBIND = 3;
  /** The number of the unbind method on the Registry
   */ 
  private static final int REGISTRY_OP_UNBIND = 4;
  /** The ObjID of the DGC
   */ 
  private static final ObjID DGC_OID = new ObjID (ObjID.DGC_ID);
  /** The number of the clean method on the DGCRegistry
   */ 
  private static final int DGC_OP_CLEAN = 0;
  /** The number of the dirty method on the DGCRegistry
   */ 
  private static final int DGC_OP_DIRTY = 1;
  /** The method hash for the compute method
   */ 
  private static final long HASH_COMPUTE = 3908630515974072420L;
  /** The method hash for the computeAsynch method
   */ 
  private static final long HASH_COMPUTEASYNCH = 8164115102769782894L;
  /** The method hash for the getResults method
   */ 
  private static final long HASH_GETRESULTS = -728148089723471111L;
  /** The method hash for the isComplete method
   */ 
  private static final long HASH_ISCOMPLETE = -5321554526954319352L;
  /** The UID of this server
   */ 
  private static final UID uid = new UID ();
  /** A reference to this server
   */ 
  private static final LiveRef ref = new LiveRef (1099);
  /** The logging mechanism
   */ 
  private static Logger log = null;
  /** A place to store Lock objects referenced by job id.  When a
   * job comes in, a Lock is created and placed in the lockbox
   * under the job id.  The server thread then waits on that
   * Lock (if synchronous).  The ResultChannelImpl notifies the
   * Lock when the ComputeEngineImpl returns a result.
   * @see ResultChannelImpl
   * @see Lock
   */ 
  private static Map lockbox = Collections.synchronizedMap (new HashMap ());
  /** The next job id to be assigned
   */ 
  private static long nextProcessId = Long.MIN_VALUE;
  /** The path to the serialized job files
   */ 
  private static String jobPath = "ser/";
  /** The command used to submit job to the grid engine queue
   */ 
  private static String submitCommand = "qsub -notify";
  /** The command for the grid engine execution engine to run on
   * the execution host
   */ 
  private static String skeletonCommand = "skel.sh submit";
  /** The port on which to start the fake server
   */ 
  private static int port = 1099;
  /** Whether debug information should be printed
   */ 
  private static boolean debug = false;
  /** The Socket over which communications will take place
   */ 
  private Socket socket;
 
  /** Creates a new instance of ComputeProxy
   * @param socket The Socket over which communications will take place
   */
  private ComputeProxy (Socket socket) {
    this.socket = socket;
  }
 
  /** The main method creates a registry on 1100 for return channel
   * communications and creates a fake registry on 1099 to intercep
   * RMI calls.
   * @param args the command line arguments
   */
  public static void main (String[] args) {
    prepareLogging ();
    processArguments (args);
   
    log.log (Level.FINER, "Starting ComputeProxy");
   
    log.log (Level.FINEST, "Setting SecurityManager");
    System.setSecurityManager (new RMISecurityManager ());
   
    ResultChannelImpl resultChannel = null;
    ServerSocket ss = null;
   
    //Prepare the return data channel
    log.log (Level.FINEST, "Registering ResultChannel");
    try {
      resultChannel = new ResultChannelImpl (lockbox);
      Registry r = LocateRegistry.createRegistry (ResultChannel.PORT);
      r.rebind (ResultChannel.LOOKUP_NAME, resultChannel);
    }
    catch (RemoteException e) {
      log.severe ("Unable to establish return data channel: " + e.getMessage ());
      log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "main", e);
     
      System.exit (1);
    }
   
    //Prepare to receive connections
    log.log (Level.FINEST, "Opening ServerSocket");
    try {
      ss = new ServerSocket (1099);
     
      System.out.println ("Ready.");
     
      //When we get a connection, spawn a thread to handle it
      while (true) {
        log.log (Level.FINE, "Accepting connections");
        Socket s = ss.accept ();
       
        log.log (Level.FINE, "Received connection -- spawing handler");
        Thread t = new Thread (new ComputeProxy (s));
        t.start ();
      }
    }
    catch (IOException e) {
      log.severe ("Error while handling connection: " + e.getMessage ());
      log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "main", e);
     
      System.exit (1);
    }
    finally {
      try {
        log.log (Level.FINEST, "Closing ServerSocket");
        ss.close ();
      }
      catch (IOException e2) {
        //Don't care
        log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "main", e2);
      }
    }
   
    log.log (Level.FINER, "Exiting ComputeProxy");

    flushLogs ();
  }
 
  /** This method processes the command line arguments and sets
   * the appropriate variables
   * @param args The args array from main()
   */ 
  private static void processArguments (String[] args) {
    int count = 0;
    String error = null;
   
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processArguments");
   
    while (count < args.length) {
      if (args[count].equals ("-d")) {
        count++;
       
        if (count < args.length) {
          String path = args[count++];
         
          File file = new File (path);
         
          if (!file.exists ()) {
            error = "Specified job path does not exist.";
           
            break;
          }
         
          if (path.endsWith ("/")) {
            jobPath = path;
          }
          else {
            jobPath = path + "/";
          }
        }
        else {
          error = USAGE;
          break;
        }
       
        log.log (Level.FINE, "Job path set to " + jobPath);
      }
      else if (args[count].equals ("-sub")) {
        count++;
       
        if (count < args.length) {
          submitCommand = args[count++];
        }
       
        log.log (Level.FINE, "Submit command set to \"" + submitCommand + "\"");
      }
      else if (args[count].equals ("-skel")) {
        count++;
       
        if (count < args.length) {
          skeletonCommand = args[count++];
        }
       
        log.log (Level.FINE, "Skeleton command set to \"" + skeletonCommand + "\"");
      }
      else if (args[count].equals ("-debug")) {
        count++;
        debug = true;
       
        Handler ha = new StreamHandler (System.out, new SimpleFormatter ());
       
        log.addHandler (ha);
        ha.setLevel (Level.ALL);
        log.setLevel (Level.ALL);
       
        log.log (Level.FINE, "Debugging enabled");
      }
      else if (args[count].equals ("-p")) {
        count++;
       
        if (count < args.length) {
          try {
            port = Integer.parseInt (args[count]);
          }
          catch (NumberFormatException e) {
            error = "Inavlid port number: " + args[count];
           
            break;
          }
         
          count++;
        }
       
        log.log (Level.FINE, "Port set to " + Integer.toString (port));
      }
      else if (args[count].equals ("-help")) {
        System.out.println (USAGE);
        System.out.println ("\t-d = set the path where job files are written");
        System.out.println ("\t\tdefaults to \"./ser/\"");
        System.out.println ("\t-sub = set the command used to submit jobs to the grid");
        System.out.println ("\t\tdefaults to \"qsub\"");
        System.out.println ("\t-skel = set the command to be run on the execution host");
        System.out.println ("\t\tdefaults to \"skel\"");
        System.out.println ("\t-p = set the port number for the RMI registry");
        System.out.println ("\t\tdefaults to 1099");
        System.out.println ("\t-debug = turn on debugging messages");
        System.out.println ("\t-help = print this message");
        System.out.println ("");
       
        break;
      }
      else {
        error = USAGE;
        break;
      }
    }
   
    if (error != null) {
      System.err.println (error);
      System.exit (1);
    }
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processArguments");
  }
 
  /** This method sets up the Logger object
   */ 
  private static void prepareLogging () {
    log = Logger.getLogger ("com.sun.grid.jgrid.proxy.ComputeProxy");
    log.setUseParentHandlers (false);
   
    ConsoleHandler ha = new ConsoleHandler ();
    ha.setFormatter (new Formatter () {
      public String format (LogRecord record) {
        return formatMessage (record);
      }
    });

    log.addHandler (ha);
    ha.setLevel (Level.INFO);
    log.setLevel (Level.INFO);
  }
 
  /** This methods flushes the logs
   */ 
  private static void flushLogs () {
    Handler[] has = log.getHandlers ();
   
    for (int count = 0; count < has.length; count++) {
      has[0].flush ();
    }
  }
 
  /** This method begins the communications process
   */ 
  public void run () {
    byte[] buffer = new byte[256];
   
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "run");
   
    try {
      //Prepare the streams
      log.log (Level.FINEST, "Getting socket streams");
      DataInputStream in = new DataInputStream (socket.getInputStream ());
      DataOutputStream out = new DataOutputStream (new BufferedOutputStream (socket.getOutputStream ()));
     
      //Handle the JRMP handshake
      log.log (Level.FINE, "Doing handshake");
      this.doHandshake (in, out);
     
      //Open communication channel until done or error
      log.log (Level.FINE, "Handling messages");
      processConnection (in, out);
    }
    catch (EOFException e) {
      log.finer ("Connection has been closed");
    }
    catch (IOException e) {
      log.warning ("The following error occured while processing the stream: " + e.getMessage () + "\n");
      log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "run", e);
    }
    finally {
      //Close the socket when we're done
      log.log (Level.FINEST, "Closing socket");
      try {
        socket.close ();
      }
      catch (IOException e) {
        //Don't care
        log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "run", e);
      }
     
      socket = null;
    }
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "run");
  }
 
  /** This method handles the initial JRMP handshake
   * @param in the input stream
   * @param out the outputstream
   * @throws IOException if an error occurs during communications
   */ 
  private void doHandshake (DataInputStream in, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "doHandshake");
   
    //Read handshake
    log.log (Level.FINEST, "Reading magic, version and protocol");
    int magic = in.readInt ();
   
    if (magic != TransportConstants.Magic) {
      throw new StreamException (Integer.toString (TransportConstants.Magic), Integer.toString (magic));
    }
   
    short version = in.readShort ();
   
    if (version != TransportConstants.Version) {
      throw new StreamException (Short.toString (TransportConstants.Version), Short.toString (version));
    }
   
    byte streamType = in.readByte ();
   
    if (streamType != TransportConstants.StreamProtocol) {
      throw new StreamException (Byte.toString (TransportConstants.StreamProtocol), Byte.toString (streamType));
    }
   
    //Respond to handshake
    log.log (Level.FINEST, "Writing ip address and port");
    String socketIPAddress = socket.getInetAddress ().getHostAddress ();
   
    out.writeByte (TransportConstants.ProtocolAck);
    out.writeUTF (socketIPAddress);
    out.writeInt (socket.getPort ());
    out.flush ();
   
    //Read remainder of handshake
    log.log (Level.FINEST, "Reading ip address and port");
    String ipAddress = in.readUTF ();
   
    /* If our take on the IP address is localhost, we will accept any response
     * for the client IP address since the client may give its actual IP address
     * instead of localhost. */
    if (!socketIPAddress.equals (ipAddress) && !socketIPAddress.equals ("127.0.0.1")) {
      throw new StreamException (socket.getInetAddress ().getHostAddress (), ipAddress);
    }
   
    int port = in.readInt ();
   
    if (port != 0) {
      throw new StreamException ("0", Integer.toString (port));
    }
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "doHandshake");
  }
 
  /** This method handles the connection communication
   * @param in the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processConnection (DataInputStream in, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processConnection");
   
    while (true) {
      byte type = 0;

      //Read the type of the message
      type = in.readByte ();

      log.log (Level.FINER, "Read message of type: " + Integer.toString (type, 16));
     
      if (type == TransportConstants.Call) {
        log.log (Level.FINEST, "Handling remote method call");
        ProxyInputStream objIn = new ProxyInputStream (in);

        //Read the call header
        ObjID objId = ObjID.read (objIn);
        log.log (Level.FINER, "Read object id of " + objId.toString ());
        int opNum = objIn.readInt ();
        log.log (Level.FINER, "Read op num of " + Integer.toString (opNum));
        long hash = objIn.readLong ();       
        log.log (Level.FINER, "Read hash code of " + Long.toString (hash, 16));

        if (objId.equals (REGISTRY_OID)) {
          if (opNum == REGISTRY_OP_BIND) {
            log.log (Level.FINE, "Handling call to Registry.bind()");
            processBindCall (objIn, out);
          }
          else if (opNum == REGISTRY_OP_LIST) {
            log.log (Level.FINE, "Handling call to Registry.list()");
            processListCall (objIn, out);
          }
          else if (opNum == REGISTRY_OP_LOOKUP) {
            log.log (Level.FINE, "Handling call to Registry.lookup()");
            processLookupCall (objIn, out);
          }
          else if (opNum == REGISTRY_OP_REBIND) {
            log.log (Level.FINE, "Handling call to Registry.rebind()");
            processRebindCall (objIn, out);
          }
          else if (opNum == REGISTRY_OP_UNBIND) {
            log.log (Level.FINE, "Handling call to Registry.unbind()");
            processUnbindCall (objIn, out);
          }
        }
        else if (objId.equals (DGC_OID)) {
          if (opNum == DGC_OP_CLEAN) {
            log.log (Level.FINE, "Handling call to DGC.clean()");
            processCleanCall (objIn, out);
          }
          else if (opNum == DGC_OP_DIRTY) {
            log.log (Level.FINE, "Handling call to DGC.dirty()");
            processDirtyCall (objIn, out);
          }
        }
        else if (objId.equals (ref.getObjID ())) {
          processCall (objIn, out, opNum, hash);
        }
      }
      else if (type == TransportConstants.Ping) {
        //Acknowledge the ping
        log.log (Level.FINE, "Responding to ping");
        out.writeByte (TransportConstants.PingAck);

        out.flush ();
      }
      else {
        throw new StreamException ("a valid message type", Byte.toString (type));
      }
    }
  }
 
  /** This method handles calls to the bind method of the Registry
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processBindCall (ObjectInputStream objIn, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processBindCall");
    //Read arguments
    try {
      /* We don't bother casting the arguments to their proper types because
       * we're not going to use them.  We're just reading them to get them
       * off the stream. */
      Object name = objIn.readObject ();
      Object stub = objIn.readObject ();
    }
    catch (ClassNotFoundException e) {
      this.processException (out, new StubNotFoundException ("Unable to find stub class", e));
      log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "processBindCall", e);
     
      return;
    }
   
    this.processException (out, new AccessException ("Bind operation not permitted on this server"));
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processBindCall");
  }
 
  /** This method handles calls to the list method of the Registry
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processListCall (ObjectInputStream objIn, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processListCall");
    //Write message type
    log.log (Level.FINEST, "Writing return header");
    out.writeByte (TransportConstants.Return);

    MarshalOutputStream objOut = new MarshalOutputStream (out);

    //Write return header
    objOut.writeByte (TransportConstants.NormalReturn);
    uid.write (objOut);
   
    //Write a list of valid lookup names
    log.log (Level.FINEST, "Writing list of valid lookup names");
    objOut.writeObject (new String[] {"ComputeEngine"});

    objOut.flush ();
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processListCall");
  }
 
  /** This method handles calls to the lookup method of the Registry
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processLookupCall (ObjectInputStream objIn, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processLookupCall");
    //Read argument
    String lookupName = null;
   
    try {
      lookupName = (String)objIn.readObject ();
      log.log (Level.FINE, "Lookup call for " + lookupName);
    }
    catch (ClassNotFoundException e) {
      processException (out, new RemoteException ("Unable to find class", e));
      log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "processLookupCall", e);
     
      return;
    }
    catch (ClassCastException e) {
      this.processException (out, new RemoteException ("Incorrect argument type", e));
      log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "processLookupCall", e);
     
      return;
    }

    //Write message type
    log.log (Level.FINEST, "Writing return header");
    out.writeByte (TransportConstants.Return);

    MarshalOutputStream objOut = new MarshalOutputStream (out);

    //Write return header
    objOut.writeByte (TransportConstants.NormalReturn);
    uid.write (objOut);
   
    //Write a stub that points back to this port
    log.log (Level.FINEST, "Writing new stub");
    /* This used to write out a new stub, but since I've removed the stub code
     * from the source base, I'm just writing out null here so I can get it to
     * compile.  This won't work, but this class has been deprecated, so I don't
     * really care. */
    objOut.writeObject (null);

    objOut.flush ();
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processLookupCall");
  }
 
  /** This method handles calls to the rebind method of the Registry
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processRebindCall (ObjectInputStream objIn, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processRebindCall");
    //Read arguments
    try {
      /* We don't bother casting the arguments to their proper types because
       * we're not going to use them.  We're just reading them to get them
       * off the stream. */
      Object name = objIn.readObject ();
      Object stub = objIn.readObject ();
    }
    catch (ClassNotFoundException e) {
      this.processException (out, new StubNotFoundException ("Unable to find stub class", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processRebindCall", e);
      return;
    }
   
    this.processException (out, new AccessException ("Rebind operation not permitted on this server"));
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processRebindCall");
  }
 
  /** This method handles calls to the unbind method of the Registry
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processUnbindCall (ObjectInputStream objIn, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processUnbindCall");
    //Read arguments
    try {
      /* We don't bother casting the argument to its proper types because
       * we're not going to use it.  We're just reading it to get it
       * off the stream. */
      Object name = objIn.readObject ();
    }
    catch (ClassNotFoundException e) {
      this.processException (out, new RemoteException ("Unable to find class", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processUnbindCall", e);
     
      return;
    }
   
    this.processException (out, new AccessException ("Unbind operation not permitted on this server"));
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processUnbindCall");
  }
 
  /** This method handles calls to the clean method of the DGC
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processCleanCall (ObjectInputStream objIn, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processCleanCall");
    //Read arguments
    log.log (Level.FINEST, "Reading arguments");
    try {
      Object ids = objIn.readObject ();
      long seqNumber = objIn.readLong ();
      Object vmid = objIn.readObject ();
      boolean bool = objIn.readBoolean ();
    }
    catch (ClassNotFoundException e) {
      this.processException (out, new RemoteException ("Unable to find class", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processCleanCall", e);
     
      return;
    }

    //Write message type
    log.log (Level.FINEST, "Writing return header");
    out.writeByte (TransportConstants.Return);

    MarshalOutputStream objOut = new MarshalOutputStream (out);

    //Write message header
    objOut.writeByte (TransportConstants.NormalReturn);
    uid.write (objOut);
   
    /* We don't do anything with this call because we don't have any actual
     * objects to keep track of. */

    objOut.flush ();
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processCleanCall");
  }
 
  /** This method handles calls to the dirty method of the DGC
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processDirtyCall (ObjectInputStream objIn, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processDirtyCall");
   
    //Read arguments
    ObjID[] ids = null;
    long seqNum = -1L;
    Lease lease = null;
   
    log.log (Level.FINEST, "Reading arguments");
    try {
      ids = (ObjID[])objIn.readObject ();
      seqNum = objIn.readLong ();
      lease = (Lease)objIn.readObject ();
     
      if (ids.length > 0) {
        log.log (Level.FINE, "Dirty call for " + ids[0].toString ());
      }
    }
    catch (ClassNotFoundException e) {
      this.processException (out, new RemoteException ("Unable to find class", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processDirtyCall", e);
     
      return;
    }
    catch (ClassCastException e) {
      this.processException (out, new RemoteException ("Incorrect argument type", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processDirtyCall", e);
     
      return;
    }

    //Write message type
    log.log (Level.FINEST, "Writing return header");
    out.writeByte (TransportConstants.Return);

    MarshalOutputStream objOut = new MarshalOutputStream (out);

    //Write message header
    objOut.writeByte (TransportConstants.NormalReturn);
    uid.write (objOut);

    //If the lease we were passed has a valid VM ID, write it
    if (lease.getVMID () != null) {
      log.log (Level.FINEST, "Writing old lease object");
      objOut.writeObject (lease);
    }
    //If not, create a valid lease and write it
    else {
      log.log (Level.FINEST, "Writing new lease object");
      objOut.writeObject (new Lease (new VMID (), lease.getValue ()));
    }

    objOut.flush ();
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processDirtyCall");
  }
 
  /** This method handles calls to com.sun.grid.jgrid.ComputeEngine methods
   * @param opNum The number of the method called - will always be -1
   * @param hash The hash of the method called
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processCall (ObjectInputStream objIn, DataOutputStream out, int opNum, long hash) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processCall");
    if (((opNum == -1) && (hash == HASH_COMPUTE)) || (opNum == 0)) {
      log.log (Level.FINE, "Handling call to compute()");
      this.processComputeCall (objIn, out, false);
    }
    else if (((opNum == -1) && (hash == HASH_COMPUTEASYNCH)) || (opNum == 1)) {
      log.log (Level.FINE, "Handling call to compute(Asynch)");
      this.processComputeCall (objIn, out, true);
    }
    else if (((opNum == -1) && (hash == HASH_GETRESULTS)) || (opNum == 2)) {
      log.log (Level.FINE, "Handling call to getResults()");
      this.processGetResultsCall (objIn, out);
    }
    else if (((opNum == -1) && (hash == HASH_ISCOMPLETE)) || (opNum == 3)) {
      log.log (Level.FINE, "Handling call to isComplete()");
      this.processIsCompleteCall (objIn, out);
    }
    else {
      throw new StreamException ("a valid method hash", Long.toString (hash));
    }
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processCall");
  }
 
  /** This method handles calls to the compute and computeAsynch methods of ComputeEngine
   * @param asynch whether this call should be asynchronous
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processComputeCall (ObjectInputStream objIn, DataOutputStream out, boolean asynch) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processComputeCall");
    //Read argument
    Computable job = null;
   
    try {
      job = (Computable)objIn.readObject ();
      log.log (Level.FINE, "Compute call with " + job.getClass ().getName ());
    }
    catch (ClassNotFoundException e) {
      this.processException (out, new RemoteException ("Unable to find class", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processComputeCall", e);
     
      return;
    }
    catch (ClassCastException e) {
      this.processException (out, new RemoteException ("Incorrect argument type", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processComputeCall", e);
     
      return;
    }
   
    //Get annotation information so we know where it came from
    log.log (Level.FINEST, "Getting annotation information");
    String className = job.getClass ().getName ();
    Map annotations = ((ProxyInputStream)objIn).getAnnotations ();
    String annotation = (String)annotations.get (className);
   
    //Process the compute call
    Object returnValue = this.process (job, annotation, asynch);

    //Write message type
    log.log (Level.FINEST, "Writing return header");
    out.writeByte (TransportConstants.Return);

    MarshalOutputStream objOut = new MarshalOutputStream (out);

    //Write message header
    if (returnValue instanceof Throwable) {
      log.log (Level.FINER, "Exceptional return");
      objOut.writeByte (TransportConstants.ExceptionalReturn);

      //If the exception is a RemoteException, wrap it in a RemoteException
      if (!(returnValue instanceof RemoteException)) {
        log.log (Level.FINEST, "Wrapping exception in RemoteException");
        returnValue = new RemoteException ("An error occured while processing the Computable object", (Throwable)returnValue);
      }
    }
    else {
      log.log (Level.FINER, "Normal return");
      objOut.writeByte (TransportConstants.NormalReturn);
    }

    uid.write (objOut);
   
    //Write results
    log.log (Level.FINEST, "Writing results");
    objOut.writeObject (returnValue);

    objOut.flush ();
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processComputeCall");
  }
 
  /** This method handles calls to the getResults method of ComputeEngine
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processGetResultsCall (ObjectInputStream objIn, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processGetResultsCall");
   
    //Read argument
    String id = null;
   
    try {
      id = (String)objIn.readObject ();
      log.log (Level.FINE, "GetResults call for " + id);
    }
    catch (ClassNotFoundException e) {
      this.processException (out, new RemoteException ("Unable to find class", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processGetResultsCall", e);
     
      return;
    }
    catch (ClassCastException e) {
      this.processException (out, new RemoteException ("Incorrect argument type", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processGetResultsCall", e);
     
      return;
    }
   
    log.log (Level.FINEST, "Retrieving lock");
    Object lock = lockbox.get (id);

    if (lock == null) {
      this.processException (out, new RemoteException ("Invalid processId"));
     
      return;
    }
   
    //Write message type
    log.log (Level.FINEST, "Writing return header");
    out.writeByte (TransportConstants.Return);

    MarshalOutputStream objOut = new MarshalOutputStream (out);

    //Write message header
    objOut.writeByte (TransportConstants.NormalReturn);
    uid.write (objOut);
   
    //Write results
    log.log (Level.FINEST, "Writing results");
    if (lock instanceof Lock) {
      log.log (Level.FINE, "Process is not complete");
      objOut.writeObject (null);
    }
    else {
      log.log (Level.FINE, "Process is complete");
      objOut.writeObject (lock);
      lockbox.remove (id);
    }
   
    objOut.flush ();

    log.log (Level.FINER, "Deleting job file");
    this.deleteJob (id);
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processGetResultsCall");
  }
 
  /** This method handles calls to the isComplete method of ComputeEngine
   * @param objIn the input stream
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processIsCompleteCall (ObjectInputStream objIn, DataOutputStream out) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processIsCompleteCall");
   
    //Read argument
    String id = null;
   
    try {
      id = (String)objIn.readObject ();
      log.log (Level.FINE, "IsComplete call for " + id);
    }
    catch (ClassNotFoundException e) {
      this.processException (out, new RemoteException ("Unable to find class", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processIsCompleteCall", e);
     
      return;
    }
    catch (ClassCastException e) {
      this.processException (out, new RemoteException ("Incorrect argument type", e));
      log.throwing ("com.sun.grid.jgrid.ComputeEngine", "processIsCompleteCall", e);
     
      return;
    }
   
    log.log (Level.FINEST, "Retrieving lock");
    Object lock = lockbox.get (id);

    if (lock == null) {
      this.processException (out, new RemoteException ("Invalid processId"));
     
      return;
    }
   
    //Write message type
    log.log (Level.FINEST, "Writing return header");
    out.writeByte (TransportConstants.Return);

    MarshalOutputStream objOut = new MarshalOutputStream (out);

    //Write message header
    objOut.writeByte (TransportConstants.NormalReturn);
    uid.write (objOut);
   
    //Write results
    log.log (Level.FINEST, "Writing results");
    if (lock instanceof Lock) {
      log.log (Level.FINE, "Process is not complete");
      objOut.writeBoolean (false);
    }
    else {
      log.log (Level.FINE, "Process is complete");
      objOut.writeBoolean (true);
    }
   
    objOut.flush ();
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processIsCompleteCall");
  }
 
  /** This method handles exceptions
   * @param e the exception encountered
   * @param out the output stream
   * @throws IOException if an error occurs during communications
   */ 
  private void processException (DataOutputStream out, Exception e) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "processException");
   
    //Write the message type
    log.log (Level.FINEST, "Writing return header");
    out.writeByte (TransportConstants.Return);
   
    ObjectOutputStream objOut = new ObjectOutputStream (out);
   
    //Write the return header
    objOut.writeByte (TransportConstants.ExceptionalReturn);
    uid.write (objOut);
   
    //Write the exception
    log.log (Level.FINEST, "Writing exception");
    objOut.writeObject (e);
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "processException");
  }
   
  /** This method does the actual processing for calls to compute and computeAsynch on ComputeEngine
   * @param computable the job to process
   * @param annotation the source for the client class files
   * @param asynch whether this job should be executed asynchronously
   * @throws IOException if an error occurs during communications
   * @return the result of the job is synchronous or null if asycnhronous
   */ 
  private Object process (Computable computable, String annotation, boolean asynch) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "process");
   
    String processId = this.getNextProcessId ();
    log.log (Level.FINE, "Process id is " + processId);
   
    Job job = new Job (processId, computable, asynch);

    Object result = this.submitJob (job);
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "process");
               
    return result;
  }
 
  /** This method returns the next job id
   * @return the next job id
   */ 
  private static String getNextProcessId () {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "getNextProcessId");
    long id;
   
    synchronized (ComputeProxy.class) {
      id = nextProcessId++;
    }
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "getNextProcessId");
    return Long.toHexString (id);
  }

  /** This method serializes the Job object to disk at the location
   * given by jobPath.  The job file name is the job id.
   * @param job the job to be serialized
   * @param annotation the location of the client class files
   * @throws IOException if an error occurs while writing the job to disk
   */ 
  private void writeJobToDisk (Job job, String annotation) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "writeJobToDisk");
   
    log.log (Level.FINEST, "Opening file for writing");
    File file = new File (jobPath + job.getJobId ());
    ObjectOutputStream oos = new ProxyOutputStream (new FileOutputStream (file));
    ObjID tempId = new ObjID (0);
   
    job.setFilename (file.getAbsolutePath ());
    ((ProxyOutputStream)oos).setAnnotation (annotation);
   
    log.log (Level.FINEST, "Writing job file");
    oos.writeObject (job);
    oos.flush ();
    oos.close ();
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "writeJobToDisk");
  }
 
  /** This method creates a Lock object for the job and stores it
   * in the lockbox
   * @param processId the id of the job for which to create a lock
   */ 
  private static void setLock (String processId) {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "setLock");
   
    Object lock = new Lock ();
   
    log.log (Level.FINEST, "Storing lock");
    lockbox.put (processId, lock);
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "setLock");
  }
 
  /** This method waits for the job to complete and returns the
   * results
   * @param processId the job id
   * @return results of the job
   */ 
  private static Object getResult (String processId) {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "getResult");
   
    Object lock = lockbox.get (processId);
    Object results = null;
   
    log.log (Level.FINEST, "Waiting for lock");
   
    flushLogs ();
   
    if (lock instanceof Lock) {
      synchronized (lock) {
        try {
          lock.wait ();
        }
        catch (InterruptedException e) {
          //Don't care
          log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "getResult", e);
        }
      }

      log.log (Level.FINEST, "Getting results");   
      results = lockbox.get (processId);
    }
    else {
      results = lock;
    }
   
    log.log (Level.FINEST, "Removing lock");
    lockbox.remove (processId);
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "getResult");
   
    return results;
  }
 
  /** This method removes a job from the lockbox and disk.
   * @param id the id of the job to remove
   * @throws IOException if an error occurs while removing the job from disk
   */ 
  private void deleteJob (String id) throws IOException {
    log.entering ("com.sun.grid.jgrid.proxy.ComputeProxy", "deleteJob");
   
    File file = new File (jobPath + id);
   
    log.log (Level.FINEST, "Deleting job file");
    file.delete ();
   
    log.exiting ("com.sun.grid.jgrid.proxy.ComputeProxy", "deleteJob");
  }
 
  /** This Exception is used to signal that an error occured
   * while reading from the input stream that was not mechanical.
   */ 
  private class StreamException extends IOException {
   
    /** What was expected
     */
    private String wanted;
   
    /** What was actually read
     */   
    private String  got;
   
    /** Creates a new StreamException
     * @param wanted what was expected
     * @param got what was actually read
     */   
    StreamException (String wanted, String got) {
      this.wanted = wanted;
      this.got = got;
    }
   
    /** Returns the exception error message
     * @return the exception error message
     */   
    public String getMessage () {
      return "Expected to read: \"" + wanted + "\", actually read: \"" + got + "\".";
    }
  }
 
  private Object submitJob (Job job) throws IOException {
    Object result = null;
   
    log.log (Level.FINE, "Writing job to disk");
    this.writeJobToDisk (job, job.getAnnotation ());
   
    this.setLock (job.getJobId ());
   
    if (submitCommand == null) {
/*      SGEAdapter adapter = SGEAdapter.getSGEAdapter ();
     
      if (!adapter.isSetup ()) {
        adapter.setupGDI ();
      }
     
      adapter.submitJob (skeletonCommand, job.getJobId ());

      log.log (Level.FINER, "Waiting for results");
      result = this.getResult (job.getJobId ());

      log.log (Level.FINER, "Deleting job");
      this.deleteJob (job.getJobId ());*/
    }
    else {
      //Create command string
      String[] cmd = createCommandStringArray (new String[] {submitCommand, skeletonCommand, job.getJobId (), "-d", jobPath});

      //Execute command string
      log.log (Level.FINE, "Submitting job to queue");
      Process proc = Runtime.getRuntime ().exec (cmd);

      if (!job.isAsynch ()) {
        //Wait until the process completes
        try {
          log.log (Level.FINEST, "Waiting for process to complete");
          proc.waitFor ();
        }
        catch (InterruptedException e) {
          //Don't care
          log.throwing ("com.sun.grid.jgrid.proxy.ComputeProxy", "process", e);
        }

        if (proc.exitValue () == 1) {
          log.severe ("Unable to execute submit command");

          return null;
        }

        log.log (Level.FINER, "Waiting for results");
        result = this.getResult (job.getJobId ());

        log.log (Level.FINER, "Deleting job");
        this.deleteJob (job.getJobId ());
      }
      else {
        //computeAsynch returns the job id as a String
        result = job.getJobId ();
      }
    }
   
    return result;
  }

  private static String[] createCommandStringArray (String[] parts) {
    StringBuffer buf = new StringBuffer ();
   
    for (int count = 0; count < parts.length; count++) {
      if (count > 0) {
        buf.append (' ');
      }
     
      buf.append (parts[count]);
    }
   
    log.finest ("Using submit command: " + buf.toString ());
   
    StringTokenizer tok = new StringTokenizer (buf.toString ());   
    String[] array = new String[tok.countTokens ()];
    int count = 0;
   
    while (tok.hasMoreTokens ()) {
      array[count++] = tok.nextToken ();
    }
   
    return array;
  }
 
  /** This class is used by ComputeProxyto wait for jobs to
   * complete.
   */ 
  private static class Lock implements Serializable {
  }
}
TOP

Related Classes of com.sun.grid.jgrid.proxy.ComputeProxy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.