View Javadoc

1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.ipc;
21  
22  import org.apache.hadoop.conf.Configurable;
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.io.HbaseObjectWritable;
25  import org.apache.hadoop.io.VersionMismatchException;
26  import org.apache.hadoop.io.VersionedWritable;
27  
28  import java.io.DataInput;
29  import java.io.DataOutput;
30  import java.io.IOException;
31  import java.lang.reflect.Field;
32  import java.lang.reflect.Method;
33  
34  /** A method invocation, including the method name and its parameters.*/
35  public class Invocation extends VersionedWritable implements Configurable {
36    protected String methodName;
37    @SuppressWarnings("rawtypes")
38    protected Class[] parameterClasses;
39    protected Object[] parameters;
40    protected Configuration conf;
41    private long clientVersion;
42    private int clientMethodsHash;
43  
44    private static byte RPC_VERSION = 1;
45  
46    public Invocation() {}
47  
48    public Invocation(Method method,
49        Class<? extends VersionedProtocol> declaringClass, Object[] parameters) {
50      this.methodName = method.getName();
51      this.parameterClasses = method.getParameterTypes();
52      this.parameters = parameters;
53      if (declaringClass.equals(VersionedProtocol.class)) {
54        //VersionedProtocol is exempted from version check.
55        clientVersion = 0;
56        clientMethodsHash = 0;
57      } else {
58        try {
59          Field versionField = declaringClass.getField("VERSION");
60          versionField.setAccessible(true);
61          this.clientVersion = versionField.getLong(declaringClass);
62        } catch (NoSuchFieldException ex) {
63          throw new RuntimeException("The " + declaringClass, ex);
64        } catch (IllegalAccessException ex) {
65          throw new RuntimeException(ex);
66        }
67        this.clientMethodsHash = ProtocolSignature.getFingerprint(
68            declaringClass.getMethods());
69      }
70    }
71  
72    /** @return The name of the method invoked. */
73    public String getMethodName() { return methodName; }
74  
75    /** @return The parameter classes. */
76    @SuppressWarnings({ "rawtypes" })
77    public Class[] getParameterClasses() { return parameterClasses; }
78  
79    /** @return The parameter instances. */
80    public Object[] getParameters() { return parameters; }
81  
82    long getProtocolVersion() {
83      return clientVersion;
84    }
85  
86    protected int getClientMethodsHash() {
87      return clientMethodsHash;
88    }
89  
90    /**
91     * Returns the rpc version used by the client.
92     * @return rpcVersion
93     */
94    public long getRpcVersion() {
95      return RPC_VERSION;
96    }
97  
98    public void readFields(DataInput in) throws IOException {
99      try {
100       super.readFields(in);
101       methodName = in.readUTF();
102       clientVersion = in.readLong();
103       clientMethodsHash = in.readInt();
104     } catch (VersionMismatchException e) {
105       // VersionMismatchException doesn't provide an API to access
106       // expectedVersion and foundVersion.  This is really sad.
107       if (e.toString().endsWith("found v0")) {
108         // Try to be a bit backwards compatible.  In previous versions of
109         // HBase (before HBASE-3939 in 0.92) Invocation wasn't a
110         // VersionedWritable and thus the first thing on the wire was always
111         // the 2-byte length of the method name.  Because no method name is
112         // longer than 255 characters, and all method names are in ASCII,
113         // The following code is equivalent to `in.readUTF()', which we can't
114         // call again here, because `super.readFields(in)' already consumed
115         // the first byte of input, which can't be "unread" back into `in'.
116         final short len = (short) (in.readByte() & 0xFF);  // Unsigned byte.
117         final byte[] buf = new byte[len];
118         in.readFully(buf, 0, len);
119         methodName = new String(buf);
120       }
121     }
122     parameters = new Object[in.readInt()];
123     parameterClasses = new Class[parameters.length];
124     HbaseObjectWritable objectWritable = new HbaseObjectWritable();
125     for (int i = 0; i < parameters.length; i++) {
126       parameters[i] = HbaseObjectWritable.readObject(in, objectWritable,
127         this.conf);
128       parameterClasses[i] = objectWritable.getDeclaredClass();
129     }
130   }
131 
132   public void write(DataOutput out) throws IOException {
133     super.write(out);
134     out.writeUTF(this.methodName);
135     out.writeLong(clientVersion);
136     out.writeInt(clientMethodsHash);
137     out.writeInt(parameterClasses.length);
138     for (int i = 0; i < parameterClasses.length; i++) {
139       HbaseObjectWritable.writeObject(out, parameters[i], parameterClasses[i],
140                                  conf);
141     }
142   }
143 
144   @Override
145   public String toString() {
146     StringBuilder buffer = new StringBuilder(256);
147     buffer.append(methodName);
148     buffer.append("(");
149     for (int i = 0; i < parameters.length; i++) {
150       if (i != 0)
151         buffer.append(", ");
152       buffer.append(parameters[i]);
153     }
154     buffer.append(")");
155     buffer.append(", rpc version="+RPC_VERSION);
156     buffer.append(", client version="+clientVersion);
157     buffer.append(", methodsFingerPrint="+clientMethodsHash);
158     return buffer.toString();
159   }
160 
161   public void setConf(Configuration conf) {
162     this.conf = conf;
163   }
164 
165   public Configuration getConf() {
166     return this.conf;
167   }
168 
169   @Override
170   public byte getVersion() {
171     return RPC_VERSION;
172   }
173 }