Save This Page
Home » openjdk-7 » sun.rmi » transport » [javadoc | source]
    1   /*
    2    * Copyright 1996-2005 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package sun.rmi.transport;
   27   
   28   import java.io.DataInputStream;
   29   import java.io.DataOutputStream;
   30   import java.io.IOException;
   31   import java.io.ObjectInput;
   32   import java.io.ObjectOutput;
   33   import java.io.StreamCorruptedException;
   34   import java.rmi.RemoteException;
   35   import java.rmi.MarshalException;
   36   import java.rmi.UnmarshalException;
   37   import java.rmi.server.ObjID;
   38   import java.rmi.server.RemoteCall;
   39   import sun.rmi.runtime.Log;
   40   import sun.rmi.server.UnicastRef;
   41   import sun.rmi.transport.tcp.TCPEndpoint;
   42   
   43   /**
   44    * Stream-based implementation of the RemoteCall interface.
   45    *
   46    * @author Ann Wollrath
   47    */
   48   public class StreamRemoteCall implements RemoteCall {
   49       private ConnectionInputStream in = null;
   50       private ConnectionOutputStream out = null;
   51       private Connection conn;
   52       private boolean resultStarted = false;
   53       private Exception serverException = null;
   54   
   55       public StreamRemoteCall(Connection c) {
   56           conn = c;
   57       }
   58   
   59       public StreamRemoteCall(Connection c, ObjID id, int op, long hash)
   60           throws RemoteException
   61       {
   62           try {
   63               conn = c;
   64               Transport.transportLog.log(Log.VERBOSE,
   65                   "write remote call header...");
   66   
   67               // write out remote call header info...
   68               // call header, part 1 (read by Transport)
   69               conn.getOutputStream().write(TransportConstants.Call);
   70               getOutputStream();           // creates a MarshalOutputStream
   71               id.write(out);               // object id (target of call)
   72               // call header, part 2 (read by Dispatcher)
   73               out.writeInt(op);            // method number (operation index)
   74               out.writeLong(hash);         // stub/skeleton hash
   75           } catch (IOException e) {
   76               throw new MarshalException("Error marshaling call header", e);
   77           }
   78       }
   79   
   80       /**
   81        * Return the connection associated with this call.
   82        */
   83       public Connection getConnection() {
   84           return conn;
   85       }
   86   
   87       /**
   88        * Return the output stream the stub/skeleton should put arguments/results
   89        * into.
   90        */
   91       public ObjectOutput getOutputStream() throws IOException {
   92           return getOutputStream(false);
   93       }
   94   
   95       private ObjectOutput getOutputStream(boolean resultStream)
   96           throws IOException
   97       {
   98           if (out == null) {
   99               Transport.transportLog.log(Log.VERBOSE, "getting output stream");
  100   
  101               out = new ConnectionOutputStream(conn, resultStream);
  102           }
  103           return out;
  104       }
  105   
  106       /**
  107        * Release the outputStream  Currently, will not complain if the
  108        * output stream is released more than once.
  109        */
  110       public void releaseOutputStream() throws IOException {
  111           try {
  112               if (out != null) {
  113                   try {
  114                       out.flush();
  115                   } finally {
  116                       out.done();         // always start DGC ack timer
  117                   }
  118               }
  119               conn.releaseOutputStream();
  120           } finally {
  121               out = null;
  122           }
  123       }
  124   
  125       /**
  126        * Get the InputStream the stub/skeleton should get results/arguments
  127        * from.
  128        */
  129       public ObjectInput getInputStream() throws IOException {
  130           if (in == null) {
  131               Transport.transportLog.log(Log.VERBOSE, "getting input stream");
  132   
  133               in = new ConnectionInputStream(conn.getInputStream());
  134           }
  135           return in;
  136       }
  137   
  138       /**
  139        * Release the input stream, this would allow some transports to release
  140        * the channel early.
  141        */
  142       public void releaseInputStream() throws IOException {
  143           /* WARNING: Currently, the UnicastRef.java invoke methods rely
  144            * upon this method not throwing an IOException.
  145            */
  146   
  147           try {
  148               if (in != null) {
  149                   // execute MarshalInputStream "done" callbacks
  150                   try {
  151                       in.done();
  152                   } catch (RuntimeException e) {
  153                   }
  154   
  155                   // add saved references to DGC table
  156                   in.registerRefs();
  157   
  158                   /* WARNING: The connection being passed to done may have
  159                    * already been freed.
  160                    */
  161                   in.done(conn);
  162               }
  163               conn.releaseInputStream();
  164           } finally {
  165               in = null;
  166           }
  167       }
  168   
  169       /**
  170        * Returns an output stream (may put out header information
  171        * relating to the success of the call).
  172        * @param success If true, indicates normal return, else indicates
  173        * exceptional return.
  174        * @exception StreamCorruptedException If result stream previously
  175        * acquired
  176        * @exception IOException For any other problem with I/O.
  177        */
  178       public ObjectOutput getResultStream(boolean success) throws IOException {
  179           /* make sure result code only marshaled once. */
  180           if (resultStarted)
  181               throw new StreamCorruptedException("result already in progress");
  182           else
  183               resultStarted = true;
  184   
  185           // write out return header
  186           // return header, part 1 (read by Transport)
  187           DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
  188           wr.writeByte(TransportConstants.Return);// transport op
  189           getOutputStream(true);  // creates a MarshalOutputStream
  190           // return header, part 2 (read by client-side RemoteCall)
  191           if (success)            //
  192               out.writeByte(TransportConstants.NormalReturn);
  193           else
  194               out.writeByte(TransportConstants.ExceptionalReturn);
  195           out.writeID();          // write id for gcAck
  196           return out;
  197       }
  198   
  199       /**
  200        * Do whatever it takes to execute the call.
  201        */
  202       public void executeCall() throws Exception {
  203           byte returnType;
  204   
  205           // read result header
  206           DGCAckHandler ackHandler = null;
  207           try {
  208               if (out != null) {
  209                   ackHandler = out.getDGCAckHandler();
  210               }
  211               releaseOutputStream();
  212               DataInputStream rd = new DataInputStream(conn.getInputStream());
  213               byte op = rd.readByte();
  214               if (op != TransportConstants.Return) {
  215                   if (Transport.transportLog.isLoggable(Log.BRIEF)) {
  216                       Transport.transportLog.log(Log.BRIEF,
  217                           "transport return code invalid: " + op);
  218                   }
  219                   throw new UnmarshalException("Transport return code invalid");
  220               }
  221               getInputStream();
  222               returnType = in.readByte();
  223               in.readID();        // id for DGC acknowledgement
  224           } catch (UnmarshalException e) {
  225               throw e;
  226           } catch (IOException e) {
  227               throw new UnmarshalException("Error unmarshaling return header",
  228                                            e);
  229           } finally {
  230               if (ackHandler != null) {
  231                   ackHandler.release();
  232               }
  233           }
  234   
  235           // read return value
  236           switch (returnType) {
  237           case TransportConstants.NormalReturn:
  238               break;
  239   
  240           case TransportConstants.ExceptionalReturn:
  241               Object ex;
  242               try {
  243                   ex = in.readObject();
  244               } catch (Exception e) {
  245                   throw new UnmarshalException("Error unmarshaling return", e);
  246               }
  247   
  248               // An exception should have been received,
  249               // if so throw it, else flag error
  250               if (ex instanceof Exception) {
  251                   exceptionReceivedFromServer((Exception) ex);
  252               } else {
  253                   throw new UnmarshalException("Return type not Exception");
  254               }
  255           default:
  256               if (Transport.transportLog.isLoggable(Log.BRIEF)) {
  257                   Transport.transportLog.log(Log.BRIEF,
  258                       "return code invalid: " + returnType);
  259               }
  260               throw new UnmarshalException("Return code invalid");
  261           }
  262       }
  263   
  264       /**
  265        * Routine that causes the stack traces of remote exceptions to be
  266        * filled in with the current stack trace on the client.  Detail
  267        * exceptions are filled in iteratively.
  268        */
  269       protected void exceptionReceivedFromServer(Exception ex) throws Exception {
  270           serverException = ex;
  271   
  272           StackTraceElement[] serverTrace = ex.getStackTrace();
  273           StackTraceElement[] clientTrace = (new Throwable()).getStackTrace();
  274           StackTraceElement[] combinedTrace =
  275               new StackTraceElement[serverTrace.length + clientTrace.length];
  276           System.arraycopy(serverTrace, 0, combinedTrace, 0,
  277                            serverTrace.length);
  278           System.arraycopy(clientTrace, 0, combinedTrace, serverTrace.length,
  279                            clientTrace.length);
  280           ex.setStackTrace(combinedTrace);
  281   
  282           /*
  283            * Log the details of a server exception thrown as a result of a
  284            * remote method invocation.
  285            */
  286           if (UnicastRef.clientCallLog.isLoggable(Log.BRIEF)) {
  287               /* log call exception returned from server before it is rethrown */
  288               TCPEndpoint ep = (TCPEndpoint) conn.getChannel().getEndpoint();
  289               UnicastRef.clientCallLog.log(Log.BRIEF, "outbound call " +
  290                   "received exception: [" + ep.getHost() + ":" +
  291                   ep.getPort() + "] exception: ", ex);
  292           }
  293   
  294           throw ex;
  295       }
  296   
  297       /*
  298        * method to retrieve possible server side exceptions (which will
  299        * be throw from exceptionReceivedFromServer(...) )
  300        */
  301       public Exception getServerException() {
  302           return serverException;
  303       }
  304   
  305       public void done() throws IOException {
  306           /* WARNING: Currently, the UnicastRef.java invoke methods rely
  307            * upon this method not throwing an IOException.
  308            */
  309   
  310           releaseInputStream();
  311       }
  312   }

Save This Page
Home » openjdk-7 » sun.rmi » transport » [javadoc | source]