You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nutch.apache.org by cu...@apache.org on 2005/05/04 21:38:50 UTC

svn commit: r168175 - /incubator/nutch/trunk/src/java/org/apache/nutch/ipc/RPC.java

Author: cutting
Date: Wed May  4 12:38:45 2005
New Revision: 168175

URL: http://svn.apache.org/viewcvs?rev=168175&view=rev
Log:
Fixed bugs with handling of nulls, improved documentation and variable names.

Modified:
    incubator/nutch/trunk/src/java/org/apache/nutch/ipc/RPC.java

Modified: incubator/nutch/trunk/src/java/org/apache/nutch/ipc/RPC.java
URL: http://svn.apache.org/viewcvs/incubator/nutch/trunk/src/java/org/apache/nutch/ipc/RPC.java?rev=168175&r1=168174&r2=168175&view=diff
==============================================================================
--- incubator/nutch/trunk/src/java/org/apache/nutch/ipc/RPC.java (original)
+++ incubator/nutch/trunk/src/java/org/apache/nutch/ipc/RPC.java Wed May  4 12:38:45 2005
@@ -30,10 +30,26 @@
 import org.apache.nutch.io.*;
 import org.apache.nutch.util.*;
 
-/** A simple RPC mechanism.  A protocol is a Java interface.  All methods
- * should throw only IOException.  No field data is transmitted. */
+/** A simple RPC mechanism.
+ *
+ * A <i>protocol</i> is a Java interface.  All parameters and return types must
+ * be one of:
+ *
+ * <ul> <li>a primitive type, <code>boolean</code>, <code>byte</code>,
+ * <code>char</code>, <code>short</code>, <code>int</code>, <code>long</code>,
+ * <code>float</code>, <code>double</code>, or <code>void</code>; or</li>
+ *
+ * <li>a {@link String}; or</li>
+ *
+ * <li>a {@link Writable}; or</li>
+ *
+ * <li>an array of the above types</li> </ul>
+ *
+ * All methods in the protocol should throw only IOException.  No field data of
+ * the protocol instance is transmitted.
+ */
 public class RPC {
-  public static final Logger LOG =
+  private static final Logger LOG =
     LogFormatter.getLogger("org.apache.nutch.ipc.RPC");
 
   private RPC() {}                                  // no public ctor
@@ -52,68 +68,85 @@
   }
 
   private static class NullInstance implements Writable {
-    private Class theClass;
+    private Class declaredClass;
     public NullInstance() {}
-    public NullInstance(Class theClass) { this.theClass = theClass; }
+    public NullInstance(Class declaredClass) {
+      this.declaredClass = declaredClass;
+    }
     public void readFields(DataInput in) throws IOException {
-      try {
-        theClass = Class.forName(UTF8.readString(in));
-      } catch (ClassNotFoundException e) {
-        throw new RuntimeException(e.toString());
+      String className = UTF8.readString(in);
+      declaredClass = (Class)PRIMITIVE_NAMES.get(className);
+      if (declaredClass == null) {
+        try {
+          declaredClass = Class.forName(className);
+        } catch (ClassNotFoundException e) {
+          throw new RuntimeException(e.toString());
+        }
       }
     }
     public void write(DataOutput out) throws IOException {
-      UTF8.writeString(out, theClass.getName());
+      UTF8.writeString(out, declaredClass.getName());
     }
   }
 
   private static void writeObject(DataOutput out, Object instance,
-                                  Class theClass) throws IOException {
+                                  Class declaredClass) throws IOException {
 
     if (instance == null) {                       // null
-      instance = new NullInstance(theClass);
-      theClass = NullInstance.class;
+      instance = new NullInstance(declaredClass);
+      declaredClass = NullInstance.class;
+    }
+
+    if (instance instanceof Writable) {           // Writable
+
+      // write instance's class, to support subclasses of the declared class
+      UTF8.writeString(out, instance.getClass().getName());
+      
+      ((Writable)instance).write(out);
+
+      return;
     }
 
-    UTF8.writeString(out, theClass.getName());
+    // write declared class for primitives, as they can't be subclassed, and
+    // the class of the instance may be a wrapper
+    UTF8.writeString(out, declaredClass.getName());
 
-    if (theClass.isArray()) {                     // array
+    if (declaredClass.isArray()) {                // array
       int length = Array.getLength(instance);
       out.writeInt(length);
       for (int i = 0; i < length; i++) {
-        writeObject(out, Array.get(instance, i), theClass.getComponentType());
+        writeObject(out, Array.get(instance, i),
+                    declaredClass.getComponentType());
       }
       
-    } else if (theClass == String.class) {        // String
+    } else if (declaredClass == String.class) {   // String
       UTF8.writeString(out, (String)instance);
       
-    } else if (theClass.isPrimitive()) {          // primitive type
+    } else if (declaredClass.isPrimitive()) {     // primitive type
 
-      if (theClass == Boolean.TYPE) {            // boolean
+      if (declaredClass == Boolean.TYPE) {        // boolean
         out.writeBoolean(((Boolean)instance).booleanValue());
-      } else if (theClass == Character.TYPE) {    // char
+      } else if (declaredClass == Character.TYPE) { // char
         out.writeChar(((Character)instance).charValue());
-      } else if (theClass == Byte.TYPE) {         // byte
+      } else if (declaredClass == Byte.TYPE) {    // byte
         out.writeByte(((Byte)instance).byteValue());
-      } else if (theClass == Short.TYPE) {        // short
+      } else if (declaredClass == Short.TYPE) {   // short
         out.writeShort(((Short)instance).shortValue());
-      } else if (theClass == Integer.TYPE) {      // int
+      } else if (declaredClass == Integer.TYPE) { // int
         out.writeInt(((Integer)instance).intValue());
-      } else if (theClass == Long.TYPE) {         // long
+      } else if (declaredClass == Long.TYPE) {    // long
         out.writeLong(((Long)instance).longValue());
-      } else if (theClass == Float.TYPE) {        // float
+      } else if (declaredClass == Float.TYPE) {   // float
         out.writeFloat(((Float)instance).floatValue());
-      } else if (theClass == Double.TYPE) {       // double
+      } else if (declaredClass == Double.TYPE) {  // double
         out.writeDouble(((Double)instance).doubleValue());
-      } else if (theClass == Void.TYPE) {         // void
+      } else if (declaredClass == Void.TYPE) {    // void
       } else {
-        throw new IllegalArgumentException("Not a known primitive: "+theClass);
+        throw new IllegalArgumentException("Not a primitive: "+declaredClass);
       }
       
-    } else if (instance instanceof Writable) {        // Writable
-      ((Writable)instance).write(out);
     } else {
-      throw new IOException("Can't write: " + instance + " as " + theClass);
+      throw new IOException("Can't write: "+instance+" as "+declaredClass);
     }
   }
   
@@ -123,74 +156,79 @@
     return readObject(in, null);
   }
     
-  private static Object readObject(DataInput in, Class[] storeClass)
+  private static Object readObject(DataInput in, ObjectWritable objectWritable)
     throws IOException {
-    
-    String name = UTF8.readString(in);
-    Class theClass = (Class)PRIMITIVE_NAMES.get(name);
-    if (theClass == null) {
+    String className = UTF8.readString(in);
+    Class declaredClass = (Class)PRIMITIVE_NAMES.get(className);
+    if (declaredClass == null) {
       try {
-        theClass = Class.forName(name);
+        declaredClass = Class.forName(className);
       } catch (ClassNotFoundException e) {
         throw new RuntimeException(e.toString());
       }
     }    
 
-    if (storeClass != null)
-      storeClass[0] = theClass;
-
-    if (theClass == NullInstance.class) {         // null
-      NullInstance instance = new NullInstance();
-      instance.readFields(in);
-      storeClass[0] = instance.theClass;
-      return null;
-
-    } else if (theClass.isPrimitive()) {          // primitive types
-
-      if (theClass == Boolean.TYPE) {             // boolean
-        return Boolean.valueOf(in.readBoolean());
-      } else if (theClass == Character.TYPE) {    // char
-        return new Character(in.readChar());
-      } else if (theClass == Byte.TYPE) {         // byte
-        return new Byte(in.readByte());
-      } else if (theClass == Short.TYPE) {        // short
-        return new Short(in.readShort());
-      } else if (theClass == Integer.TYPE) {      // int
-        return new Integer(in.readInt());
-      } else if (theClass == Long.TYPE) {         // long
-        return new Long(in.readLong());
-      } else if (theClass == Float.TYPE) {        // float
-        return new Float(in.readFloat());
-      } else if (theClass == Double.TYPE) {       // double
-        return new Double(in.readDouble());
-      } else if (theClass == Void.TYPE) {         // void
-        return null;
+    Object instance;
+    
+    if (declaredClass == NullInstance.class) {         // null
+      NullInstance wrapper = new NullInstance();
+      wrapper.readFields(in);
+      declaredClass = wrapper.declaredClass;
+      instance = null;
+
+    } else if (declaredClass.isPrimitive()) {          // primitive types
+
+      if (declaredClass == Boolean.TYPE) {             // boolean
+        instance = Boolean.valueOf(in.readBoolean());
+      } else if (declaredClass == Character.TYPE) {    // char
+        instance = new Character(in.readChar());
+      } else if (declaredClass == Byte.TYPE) {         // byte
+        instance = new Byte(in.readByte());
+      } else if (declaredClass == Short.TYPE) {        // short
+        instance = new Short(in.readShort());
+      } else if (declaredClass == Integer.TYPE) {      // int
+        instance = new Integer(in.readInt());
+      } else if (declaredClass == Long.TYPE) {         // long
+        instance = new Long(in.readLong());
+      } else if (declaredClass == Float.TYPE) {        // float
+        instance = new Float(in.readFloat());
+      } else if (declaredClass == Double.TYPE) {       // double
+        instance = new Double(in.readDouble());
+      } else if (declaredClass == Void.TYPE) {         // void
+        instance = null;
       } else {
-        throw new IllegalArgumentException("Not a known primitive: "+theClass);
+        throw new IllegalArgumentException("Not a primitive: "+declaredClass);
       }
 
-    } else if (theClass.isArray()) {              // array
+    } else if (declaredClass.isArray()) {              // array
       int length = in.readInt();
-      Object array = Array.newInstance(theClass.getComponentType(), length);
+      instance = Array.newInstance(declaredClass.getComponentType(), length);
       for (int i = 0; i < length; i++) {
-        Array.set(array, i, readObject(in));
+        Array.set(instance, i, readObject(in));
       }
-      return array;
       
-    } else if (theClass == String.class) {        // String
-      return UTF8.readString(in);
+    } else if (declaredClass == String.class) {        // String
+      instance = UTF8.readString(in);
       
     } else {                                      // Writable
       try {
-        Writable instance = (Writable)theClass.newInstance();
-        instance.readFields(in);
-        return instance;
+        Writable writable = (Writable)declaredClass.newInstance();
+        writable.readFields(in);
+        instance = writable;
       } catch (InstantiationException e) {
         throw new RuntimeException(e);
       } catch (IllegalAccessException e) {
         throw new RuntimeException(e);
       }
     }
+
+    if (objectWritable != null) {                 // store values
+      objectWritable.declaredClass = declaredClass;
+      objectWritable.instance = instance;
+    }
+
+    return instance;
+      
   }
 
   /** A method invocation, including the method name and its parameters.*/
@@ -221,10 +259,10 @@
       parameters = new Object[in.readInt()];
       parameterClasses = new Class[parameters.length];
 
-      Class[] storeClass = new Class[1];
+      ObjectWritable objectWritable = new ObjectWritable();
       for (int i = 0; i < parameters.length; i++) {
-        parameters[i] = readObject(in, storeClass);
-        parameterClasses[i] = storeClass[0];
+        parameters[i] = readObject(in, objectWritable);
+        parameterClasses[i] = objectWritable.declaredClass;
       }
     }
 
@@ -255,13 +293,13 @@
    * Also handles arrays and strings w/o a Writable wrapper.
    */
   private static class ObjectWritable implements Writable {
-    private Class theClass;
+    private Class declaredClass;
     private Object instance;
 
     public ObjectWritable() {}
 
-    public ObjectWritable(Class theClass, Object instance) {
-      this.theClass = theClass;
+    public ObjectWritable(Class declaredClass, Object instance) {
+      this.declaredClass = declaredClass;
       this.instance = instance;
     }
 
@@ -269,13 +307,11 @@
     public Object get() { return instance; }
 
     public void readFields(DataInput in) throws IOException {
-      Class[] storeClass = new Class[1];
-      instance = readObject(in, storeClass);
-      theClass = storeClass[0];
+      readObject(in, this);
     }
 
     public void write(DataOutput out) throws IOException {
-      writeObject(out, instance, theClass);
+      writeObject(out, instance, declaredClass);
     }
 
   }
@@ -305,7 +341,7 @@
                                   new Invoker(addr));
   }
 
-  /** Make multiple, parallel calls to a set of servers. */
+  /** Expert: Make multiple, parallel calls to a set of servers. */
   public static Object[] call(Method method, Object[][] params,
                               InetSocketAddress[] addrs)
     throws IOException {
@@ -319,18 +355,21 @@
     Object[] values =
       (Object[])Array.newInstance(method.getReturnType(),wrappedValues.length);
     for (int i = 0; i < values.length; i++)
-      values[i] = ((ObjectWritable)wrappedValues[i]).get();
+      if (wrappedValues[i] != null)
+        values[i] = ((ObjectWritable)wrappedValues[i]).get();
     
     return values;
   }
   
 
-  /** Construct a server for the named instance listening on the named port. */
+  /** Construct a server for a protocol implementation instance listening on a
+   * port. */
   public static Server getServer(final Object instance, final int port) {
     return getServer(instance, port, 1, false);
   }
 
-  /** Construct a server for the named instance listening on the named port. */
+  /** Construct a server for a protocol implementation instance listening on a
+   * port. */
   public static Server getServer(final Object instance, final int port,
                                  final int numHandlers,
                                  final boolean verbose) {