View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distr=ibuted on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.protobuf;
19  
20  
21  import static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType.REGION_NAME;
22  
23  import java.io.ByteArrayOutputStream;
24  import java.io.IOException;
25  import java.lang.reflect.Constructor;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  import java.lang.reflect.ParameterizedType;
29  import java.lang.reflect.Type;
30  import java.nio.ByteBuffer;
31  import java.util.ArrayList;
32  import java.util.Collection;
33  import java.util.HashMap;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.Map.Entry;
37  import java.util.NavigableSet;
38  
39  import org.apache.hadoop.conf.Configuration;
40  import org.apache.hadoop.fs.Path;
41  import org.apache.hadoop.hbase.Cell;
42  import org.apache.hadoop.hbase.CellScanner;
43  import org.apache.hadoop.hbase.CellUtil;
44  import org.apache.hadoop.hbase.TableName;
45  import org.apache.hadoop.hbase.DoNotRetryIOException;
46  import org.apache.hadoop.hbase.HBaseConfiguration;
47  import org.apache.hadoop.hbase.HConstants;
48  import org.apache.hadoop.hbase.HRegionInfo;
49  import org.apache.hadoop.hbase.HTableDescriptor;
50  import org.apache.hadoop.hbase.KeyValue;
51  import org.apache.hadoop.hbase.KeyValueUtil;
52  import org.apache.hadoop.hbase.NamespaceDescriptor;
53  import org.apache.hadoop.hbase.ServerName;
54  import org.apache.hadoop.hbase.client.Append;
55  import org.apache.hadoop.hbase.client.Delete;
56  import org.apache.hadoop.hbase.client.Durability;
57  import org.apache.hadoop.hbase.client.Get;
58  import org.apache.hadoop.hbase.client.Increment;
59  import org.apache.hadoop.hbase.client.Mutation;
60  import org.apache.hadoop.hbase.client.Put;
61  import org.apache.hadoop.hbase.client.Result;
62  import org.apache.hadoop.hbase.client.Scan;
63  import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
64  import org.apache.hadoop.hbase.exceptions.DeserializationException;
65  import org.apache.hadoop.hbase.filter.ByteArrayComparable;
66  import org.apache.hadoop.hbase.filter.Filter;
67  import org.apache.hadoop.hbase.io.TimeRange;
68  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
69  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
70  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService;
71  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionRequest;
72  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionResponse;
73  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetOnlineRegionRequest;
74  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetOnlineRegionResponse;
75  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoRequest;
76  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoResponse;
77  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetServerInfoRequest;
78  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetServerInfoResponse;
79  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileRequest;
80  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileResponse;
81  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.MergeRegionsRequest;
82  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionRequest;
83  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.ServerInfo;
84  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.SplitRegionRequest;
85  import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos;
86  import org.apache.hadoop.hbase.protobuf.generated.CellProtos;
87  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
88  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.BulkLoadHFileRequest;
89  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.BulkLoadHFileResponse;
90  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ClientService;
91  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.Column;
92  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall;
93  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceRequest;
94  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceResponse;
95  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest;
96  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetResponse;
97  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
98  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.ColumnValue;
99  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.ColumnValue.QualifierValue;
100 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.DeleteType;
101 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType;
102 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
103 import org.apache.hadoop.hbase.protobuf.generated.ComparatorProtos;
104 import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
105 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
106 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameBytesPair;
107 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo;
108 import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionLoad;
109 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
110 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
111 import org.apache.hadoop.hbase.protobuf.generated.MapReduceProtos;
112 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.CreateTableRequest;
113 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsResponse;
114 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MasterService;
115 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerReportRequest;
116 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
117 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.CompactionDescriptor;
118 import org.apache.hadoop.hbase.security.access.Permission;
119 import org.apache.hadoop.hbase.security.access.TablePermission;
120 import org.apache.hadoop.hbase.security.access.UserPermission;
121 import org.apache.hadoop.hbase.security.token.AuthenticationTokenIdentifier;
122 import org.apache.hadoop.hbase.util.Bytes;
123 import org.apache.hadoop.hbase.util.DynamicClassLoader;
124 import org.apache.hadoop.hbase.util.Methods;
125 import org.apache.hadoop.hbase.util.Pair;
126 import org.apache.hadoop.io.Text;
127 import org.apache.hadoop.ipc.RemoteException;
128 import org.apache.hadoop.security.token.Token;
129 
130 import com.google.common.collect.ArrayListMultimap;
131 import com.google.common.collect.ListMultimap;
132 import com.google.common.collect.Lists;
133 import com.google.protobuf.ByteString;
134 import com.google.protobuf.InvalidProtocolBufferException;
135 import com.google.protobuf.Message;
136 import com.google.protobuf.Parser;
137 import com.google.protobuf.RpcChannel;
138 import com.google.protobuf.Service;
139 import com.google.protobuf.ServiceException;
140 import com.google.protobuf.TextFormat;
141 import com.google.protobuf.ZeroCopyLiteralByteString;
142 
143 /**
144  * Protobufs utility.
145  */
146 public final class ProtobufUtil {
147 
148   private ProtobufUtil() {
149   }
150 
151   /**
152    * Primitive type to class mapping.
153    */
154   private final static Map<String, Class<?>>
155     PRIMITIVES = new HashMap<String, Class<?>>();
156 
157 
158   /**
159    * Many results are simple: no cell, exists true or false. To save on object creations,
160    *  we reuse them across calls.
161    */
162   private final static Cell[] EMPTY_CELL_ARRAY = new Cell[]{};
163   private final static Result EMPTY_RESULT = Result.create(EMPTY_CELL_ARRAY);
164   private final static Result EMPTY_RESULT_EXISTS_TRUE = Result.create(null, true);
165   private final static Result EMPTY_RESULT_EXISTS_FALSE = Result.create(null, false);
166 
167   private final static ClientProtos.Result EMPTY_RESULT_PB;
168   private final static ClientProtos.Result EMPTY_RESULT_PB_EXISTS_TRUE;
169   private final static ClientProtos.Result EMPTY_RESULT_PB_EXISTS_FALSE;
170 
171   static {
172     ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder();
173 
174     builder.setExists(true);
175     builder.setAssociatedCellCount(0);
176     EMPTY_RESULT_PB_EXISTS_TRUE =  builder.build();
177 
178     builder.clear();
179 
180     builder.setExists(false);
181     builder.setAssociatedCellCount(0);
182     EMPTY_RESULT_PB_EXISTS_FALSE =  builder.build();
183 
184     builder.clear();
185     builder.setAssociatedCellCount(0);
186     EMPTY_RESULT_PB =  builder.build();
187   }
188 
189   /**
190    * Dynamic class loader to load filter/comparators
191    */
192   private final static ClassLoader CLASS_LOADER;
193 
194   static {
195     ClassLoader parent = ProtobufUtil.class.getClassLoader();
196     Configuration conf = HBaseConfiguration.create();
197     CLASS_LOADER = new DynamicClassLoader(conf, parent);
198 
199     PRIMITIVES.put(Boolean.TYPE.getName(), Boolean.TYPE);
200     PRIMITIVES.put(Byte.TYPE.getName(), Byte.TYPE);
201     PRIMITIVES.put(Character.TYPE.getName(), Character.TYPE);
202     PRIMITIVES.put(Short.TYPE.getName(), Short.TYPE);
203     PRIMITIVES.put(Integer.TYPE.getName(), Integer.TYPE);
204     PRIMITIVES.put(Long.TYPE.getName(), Long.TYPE);
205     PRIMITIVES.put(Float.TYPE.getName(), Float.TYPE);
206     PRIMITIVES.put(Double.TYPE.getName(), Double.TYPE);
207     PRIMITIVES.put(Void.TYPE.getName(), Void.TYPE);
208   }
209 
210   /**
211    * Magic we put ahead of a serialized protobuf message.
212    * For example, all znode content is protobuf messages with the below magic
213    * for preamble.
214    */
215   public static final byte [] PB_MAGIC = new byte [] {'P', 'B', 'U', 'F'};
216   private static final String PB_MAGIC_STR = Bytes.toString(PB_MAGIC);
217 
218   /**
219    * Prepend the passed bytes with four bytes of magic, {@link #PB_MAGIC}, to flag what
220    * follows as a protobuf in hbase.  Prepend these bytes to all content written to znodes, etc.
221    * @param bytes Bytes to decorate
222    * @return The passed <code>bytes</codes> with magic prepended (Creates a new
223    * byte array that is <code>bytes.length</code> plus {@link #PB_MAGIC}.length.
224    */
225   public static byte [] prependPBMagic(final byte [] bytes) {
226     return Bytes.add(PB_MAGIC, bytes);
227   }
228 
229   /**
230    * @param bytes Bytes to check.
231    * @return True if passed <code>bytes</code> has {@link #PB_MAGIC} for a prefix.
232    */
233   public static boolean isPBMagicPrefix(final byte [] bytes) {
234     return isPBMagicPrefix(bytes, 0, bytes.length);
235   }
236 
237   /**
238    * @param bytes Bytes to check.
239    * @return True if passed <code>bytes</code> has {@link #PB_MAGIC} for a prefix.
240    */
241   public static boolean isPBMagicPrefix(final byte [] bytes, int offset, int len) {
242     if (bytes == null || len < PB_MAGIC.length) return false;
243     return Bytes.compareTo(PB_MAGIC, 0, PB_MAGIC.length, bytes, offset, PB_MAGIC.length) == 0;
244   }
245 
246   /**
247    * @param bytes
248    * @throws DeserializationException if we are missing the pb magic prefix
249    */
250   public static void expectPBMagicPrefix(final byte [] bytes) throws DeserializationException {
251     if (!isPBMagicPrefix(bytes)) {
252       throw new DeserializationException("Missing pb magic " + PB_MAGIC_STR + " prefix");
253     }
254   }
255 
256   /**
257    * @return Length of {@link #PB_MAGIC}
258    */
259   public static int lengthOfPBMagic() {
260     return PB_MAGIC.length;
261   }
262 
263   /**
264    * Return the IOException thrown by the remote server wrapped in
265    * ServiceException as cause.
266    *
267    * @param se ServiceException that wraps IO exception thrown by the server
268    * @return Exception wrapped in ServiceException or
269    *   a new IOException that wraps the unexpected ServiceException.
270    */
271   public static IOException getRemoteException(ServiceException se) {
272     Throwable e = se.getCause();
273     if (e == null) {
274       return new IOException(se);
275     }
276     if (e instanceof RemoteException) {
277       e = ((RemoteException)e).unwrapRemoteException();
278     }
279     return e instanceof IOException ? (IOException) e : new IOException(se);
280   }
281 
282   /**
283    * Convert a ServerName to a protocol buffer ServerName
284    *
285    * @param serverName the ServerName to convert
286    * @return the converted protocol buffer ServerName
287    * @see #toServerName(org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ServerName)
288    */
289   public static HBaseProtos.ServerName
290       toServerName(final ServerName serverName) {
291     if (serverName == null) return null;
292     HBaseProtos.ServerName.Builder builder =
293       HBaseProtos.ServerName.newBuilder();
294     builder.setHostName(serverName.getHostname());
295     if (serverName.getPort() >= 0) {
296       builder.setPort(serverName.getPort());
297     }
298     if (serverName.getStartcode() >= 0) {
299       builder.setStartCode(serverName.getStartcode());
300     }
301     return builder.build();
302   }
303 
304   /**
305    * Convert a protocol buffer ServerName to a ServerName
306    *
307    * @param proto the protocol buffer ServerName to convert
308    * @return the converted ServerName
309    */
310   public static ServerName toServerName(final HBaseProtos.ServerName proto) {
311     if (proto == null) return null;
312     String hostName = proto.getHostName();
313     long startCode = -1;
314     int port = -1;
315     if (proto.hasPort()) {
316       port = proto.getPort();
317     }
318     if (proto.hasStartCode()) {
319       startCode = proto.getStartCode();
320     }
321     return ServerName.valueOf(hostName, port, startCode);
322   }
323 
324   /**
325    * Get HTableDescriptor[] from GetTableDescriptorsResponse protobuf
326    *
327    * @param proto the GetTableDescriptorsResponse
328    * @return HTableDescriptor[]
329    */
330   public static HTableDescriptor[] getHTableDescriptorArray(GetTableDescriptorsResponse proto) {
331     if (proto == null) return null;
332 
333     HTableDescriptor[] ret = new HTableDescriptor[proto.getTableSchemaCount()];
334     for (int i = 0; i < proto.getTableSchemaCount(); ++i) {
335       ret[i] = HTableDescriptor.convert(proto.getTableSchema(i));
336     }
337     return ret;
338   }
339 
340   /**
341    * get the split keys in form "byte [][]" from a CreateTableRequest proto
342    *
343    * @param proto the CreateTableRequest
344    * @return the split keys
345    */
346   public static byte [][] getSplitKeysArray(final CreateTableRequest proto) {
347     byte [][] splitKeys = new byte[proto.getSplitKeysCount()][];
348     for (int i = 0; i < proto.getSplitKeysCount(); ++i) {
349       splitKeys[i] = proto.getSplitKeys(i).toByteArray();
350     }
351     return splitKeys;
352   }
353 
354   /**
355    * Convert a protobuf Durability into a client Durability
356    */
357   public static Durability toDurability(
358       final ClientProtos.MutationProto.Durability proto) {
359     switch(proto) {
360     case USE_DEFAULT:
361       return Durability.USE_DEFAULT;
362     case SKIP_WAL:
363       return Durability.SKIP_WAL;
364     case ASYNC_WAL:
365       return Durability.ASYNC_WAL;
366     case SYNC_WAL:
367       return Durability.SYNC_WAL;
368     case FSYNC_WAL:
369       return Durability.FSYNC_WAL;
370     default:
371       return Durability.USE_DEFAULT;
372     }
373   }
374 
375   /**
376    * Convert a client Durability into a protbuf Durability
377    */
378   public static ClientProtos.MutationProto.Durability toDurability(
379       final Durability d) {
380     switch(d) {
381     case USE_DEFAULT:
382       return ClientProtos.MutationProto.Durability.USE_DEFAULT;
383     case SKIP_WAL:
384       return ClientProtos.MutationProto.Durability.SKIP_WAL;
385     case ASYNC_WAL:
386       return ClientProtos.MutationProto.Durability.ASYNC_WAL;
387     case SYNC_WAL:
388       return ClientProtos.MutationProto.Durability.SYNC_WAL;
389     case FSYNC_WAL:
390       return ClientProtos.MutationProto.Durability.FSYNC_WAL;
391     default:
392       return ClientProtos.MutationProto.Durability.USE_DEFAULT;
393     }
394   }
395 
396   /**
397    * Convert a protocol buffer Get to a client Get
398    *
399    * @param proto the protocol buffer Get to convert
400    * @return the converted client Get
401    * @throws IOException
402    */
403   public static Get toGet(
404       final ClientProtos.Get proto) throws IOException {
405     if (proto == null) return null;
406     byte[] row = proto.getRow().toByteArray();
407     Get get = new Get(row);
408     if (proto.hasCacheBlocks()) {
409       get.setCacheBlocks(proto.getCacheBlocks());
410     }
411     if (proto.hasMaxVersions()) {
412       get.setMaxVersions(proto.getMaxVersions());
413     }
414     if (proto.hasStoreLimit()) {
415       get.setMaxResultsPerColumnFamily(proto.getStoreLimit());
416     }
417     if (proto.hasStoreOffset()) {
418       get.setRowOffsetPerColumnFamily(proto.getStoreOffset());
419     }
420     if (proto.hasTimeRange()) {
421       HBaseProtos.TimeRange timeRange = proto.getTimeRange();
422       long minStamp = 0;
423       long maxStamp = Long.MAX_VALUE;
424       if (timeRange.hasFrom()) {
425         minStamp = timeRange.getFrom();
426       }
427       if (timeRange.hasTo()) {
428         maxStamp = timeRange.getTo();
429       }
430       get.setTimeRange(minStamp, maxStamp);
431     }
432     if (proto.hasFilter()) {
433       FilterProtos.Filter filter = proto.getFilter();
434       get.setFilter(ProtobufUtil.toFilter(filter));
435     }
436     for (NameBytesPair attribute: proto.getAttributeList()) {
437       get.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
438     }
439     if (proto.getColumnCount() > 0) {
440       for (Column column: proto.getColumnList()) {
441         byte[] family = column.getFamily().toByteArray();
442         if (column.getQualifierCount() > 0) {
443           for (ByteString qualifier: column.getQualifierList()) {
444             get.addColumn(family, qualifier.toByteArray());
445           }
446         } else {
447           get.addFamily(family);
448         }
449       }
450     }
451     if (proto.hasExistenceOnly() && proto.getExistenceOnly()){
452       get.setCheckExistenceOnly(true);
453     }
454     if (proto.hasClosestRowBefore() && proto.getClosestRowBefore()){
455       get.setClosestRowBefore(true);
456     }
457     return get;
458   }
459 
460   /**
461    * Convert a protocol buffer Mutate to a Put.
462    *
463    * @param proto The protocol buffer MutationProto to convert
464    * @return A client Put.
465    * @throws IOException
466    */
467   public static Put toPut(final MutationProto proto)
468   throws IOException {
469     return toPut(proto, null);
470   }
471 
472   /**
473    * Convert a protocol buffer Mutate to a Put.
474    *
475    * @param proto The protocol buffer MutationProto to convert
476    * @param cellScanner If non-null, the Cell data that goes with this proto.
477    * @return A client Put.
478    * @throws IOException
479    */
480   public static Put toPut(final MutationProto proto, final CellScanner cellScanner)
481   throws IOException {
482     // TODO: Server-side at least why do we convert back to the Client types?  Why not just pb it?
483     MutationType type = proto.getMutateType();
484     assert type == MutationType.PUT: type.name();
485     long timestamp = proto.hasTimestamp()? proto.getTimestamp(): HConstants.LATEST_TIMESTAMP;
486     Put put = null;
487     int cellCount = proto.hasAssociatedCellCount()? proto.getAssociatedCellCount(): 0;
488     if (cellCount > 0) {
489       // The proto has metadata only and the data is separate to be found in the cellScanner.
490       if (cellScanner == null) {
491         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: " +
492             toShortString(proto));
493       }
494       for (int i = 0; i < cellCount; i++) {
495         if (!cellScanner.advance()) {
496           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i +
497             " no cell returned: " + toShortString(proto));
498         }
499         Cell cell = cellScanner.current();
500         if (put == null) {
501           put = new Put(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), timestamp);
502         }
503         put.add(cell);
504       }
505     } else {
506       if (proto.hasRow()) {
507         put = new Put(proto.getRow().asReadOnlyByteBuffer(), timestamp);
508       } else {
509         throw new IllegalArgumentException("row cannot be null");
510       }
511       // The proto has the metadata and the data itself
512       for (ColumnValue column: proto.getColumnValueList()) {
513         byte[] family = column.getFamily().toByteArray();
514         for (QualifierValue qv: column.getQualifierValueList()) {
515           if (!qv.hasValue()) {
516             throw new DoNotRetryIOException(
517                 "Missing required field: qualifier value");
518           }
519           ByteBuffer qualifier =
520               qv.hasQualifier() ? qv.getQualifier().asReadOnlyByteBuffer() : null;
521           ByteBuffer value =
522               qv.hasValue() ? qv.getValue().asReadOnlyByteBuffer() : null;
523           long ts = timestamp;
524           if (qv.hasTimestamp()) {
525             ts = qv.getTimestamp();
526           }
527           put.addImmutable(family, qualifier, ts, value);
528         }
529       }
530     }
531     put.setDurability(toDurability(proto.getDurability()));
532     for (NameBytesPair attribute: proto.getAttributeList()) {
533       put.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
534     }
535     return put;
536   }
537 
538   /**
539    * Convert a protocol buffer Mutate to a Delete
540    *
541    * @param proto the protocol buffer Mutate to convert
542    * @return the converted client Delete
543    * @throws IOException
544    */
545   public static Delete toDelete(final MutationProto proto)
546   throws IOException {
547     return toDelete(proto, null);
548   }
549 
550   /**
551    * Convert a protocol buffer Mutate to a Delete
552    *
553    * @param proto the protocol buffer Mutate to convert
554    * @param cellScanner if non-null, the data that goes with this delete.
555    * @return the converted client Delete
556    * @throws IOException
557    */
558   public static Delete toDelete(final MutationProto proto, final CellScanner cellScanner)
559   throws IOException {
560     MutationType type = proto.getMutateType();
561     assert type == MutationType.DELETE : type.name();
562     byte [] row = proto.hasRow()? proto.getRow().toByteArray(): null;
563     long timestamp = HConstants.LATEST_TIMESTAMP;
564     if (proto.hasTimestamp()) {
565       timestamp = proto.getTimestamp();
566     }
567     Delete delete = null;
568     int cellCount = proto.hasAssociatedCellCount()? proto.getAssociatedCellCount(): 0;
569     if (cellCount > 0) {
570       // The proto has metadata only and the data is separate to be found in the cellScanner.
571       if (cellScanner == null) {
572         // TextFormat should be fine for a Delete since it carries no data, just coordinates.
573         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: " +
574           TextFormat.shortDebugString(proto));
575       }
576       for (int i = 0; i < cellCount; i++) {
577         if (!cellScanner.advance()) {
578           // TextFormat should be fine for a Delete since it carries no data, just coordinates.
579           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i +
580             " no cell returned: " + TextFormat.shortDebugString(proto));
581         }
582         Cell cell = cellScanner.current();
583         if (delete == null) {
584           delete =
585             new Delete(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), timestamp);
586         }
587         delete.addDeleteMarker(KeyValueUtil.ensureKeyValue(cell));
588       }
589     } else {
590       delete = new Delete(row, timestamp);
591       for (ColumnValue column: proto.getColumnValueList()) {
592         byte[] family = column.getFamily().toByteArray();
593         for (QualifierValue qv: column.getQualifierValueList()) {
594           DeleteType deleteType = qv.getDeleteType();
595           byte[] qualifier = null;
596           if (qv.hasQualifier()) {
597             qualifier = qv.getQualifier().toByteArray();
598           }
599           long ts = HConstants.LATEST_TIMESTAMP;
600           if (qv.hasTimestamp()) {
601             ts = qv.getTimestamp();
602           }
603           if (deleteType == DeleteType.DELETE_ONE_VERSION) {
604             delete.deleteColumn(family, qualifier, ts);
605           } else if (deleteType == DeleteType.DELETE_MULTIPLE_VERSIONS) {
606             delete.deleteColumns(family, qualifier, ts);
607           } else if (deleteType == DeleteType.DELETE_FAMILY_VERSION) {
608             delete.deleteFamilyVersion(family, ts);
609           } else {
610             delete.deleteFamily(family, ts);
611           }
612         }
613       }
614     }
615     delete.setDurability(toDurability(proto.getDurability()));
616     for (NameBytesPair attribute: proto.getAttributeList()) {
617       delete.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
618     }
619     return delete;
620   }
621 
622   /**
623    * Convert a protocol buffer Mutate to an Append
624    * @param cellScanner
625    * @param proto the protocol buffer Mutate to convert
626    * @return the converted client Append
627    * @throws IOException 
628    */
629   public static Append toAppend(final MutationProto proto, final CellScanner cellScanner)
630   throws IOException {
631     MutationType type = proto.getMutateType();
632     assert type == MutationType.APPEND : type.name();
633     byte [] row = proto.hasRow()? proto.getRow().toByteArray(): null;
634     Append append = null;
635     int cellCount = proto.hasAssociatedCellCount()? proto.getAssociatedCellCount(): 0;
636     if (cellCount > 0) {
637       // The proto has metadata only and the data is separate to be found in the cellScanner.
638       if (cellScanner == null) {
639         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: " +
640           toShortString(proto));
641       }
642       for (int i = 0; i < cellCount; i++) {
643         if (!cellScanner.advance()) {
644           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i +
645             " no cell returned: " + toShortString(proto));
646         }
647         Cell cell = cellScanner.current();
648         if (append == null) {
649           append = new Append(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
650         }
651         append.add(KeyValueUtil.ensureKeyValue(cell));
652       }
653     } else {
654       append = new Append(row);
655       for (ColumnValue column: proto.getColumnValueList()) {
656         byte[] family = column.getFamily().toByteArray();
657         for (QualifierValue qv: column.getQualifierValueList()) {
658           byte[] qualifier = qv.getQualifier().toByteArray();
659           if (!qv.hasValue()) {
660             throw new DoNotRetryIOException(
661               "Missing required field: qualifer value");
662           }
663           byte[] value = qv.getValue().toByteArray();
664           append.add(family, qualifier, value);
665         }
666       }
667     }
668     append.setDurability(toDurability(proto.getDurability()));
669     for (NameBytesPair attribute: proto.getAttributeList()) {
670       append.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
671     }
672     return append;
673   }
674 
675   /**
676    * Convert a MutateRequest to Mutation
677    *
678    * @param proto the protocol buffer Mutate to convert
679    * @return the converted Mutation
680    * @throws IOException
681    */
682   public static Mutation toMutation(final MutationProto proto) throws IOException {
683     MutationType type = proto.getMutateType();
684     if (type == MutationType.APPEND) {
685       return toAppend(proto, null);
686     }
687     if (type == MutationType.DELETE) {
688       return toDelete(proto, null);
689     }
690     if (type == MutationType.PUT) {
691       return toPut(proto, null);
692     }
693     throw new IOException("Unknown mutation type " + type);
694   }
695 
696   /**
697    * Convert a protocol buffer Mutate to an Increment
698    *
699    * @param proto the protocol buffer Mutate to convert
700    * @return the converted client Increment
701    * @throws IOException
702    */
703   public static Increment toIncrement(final MutationProto proto, final CellScanner cellScanner)
704   throws IOException {
705     MutationType type = proto.getMutateType();
706     assert type == MutationType.INCREMENT : type.name();
707     byte [] row = proto.hasRow()? proto.getRow().toByteArray(): null;
708     Increment increment = null;
709     int cellCount = proto.hasAssociatedCellCount()? proto.getAssociatedCellCount(): 0;
710     if (cellCount > 0) {
711       // The proto has metadata only and the data is separate to be found in the cellScanner.
712       if (cellScanner == null) {
713         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: " +
714           TextFormat.shortDebugString(proto));
715       }
716       for (int i = 0; i < cellCount; i++) {
717         if (!cellScanner.advance()) {
718           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i +
719             " no cell returned: " + TextFormat.shortDebugString(proto));
720         }
721         Cell cell = cellScanner.current();
722         if (increment == null) {
723           increment = new Increment(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
724         }
725         increment.add(KeyValueUtil.ensureKeyValue(cell));
726       }
727     } else {
728       increment = new Increment(row);
729       for (ColumnValue column: proto.getColumnValueList()) {
730         byte[] family = column.getFamily().toByteArray();
731         for (QualifierValue qv: column.getQualifierValueList()) {
732           byte[] qualifier = qv.getQualifier().toByteArray();
733           if (!qv.hasValue()) {
734             throw new DoNotRetryIOException("Missing required field: qualifer value");
735           }
736           long value = Bytes.toLong(qv.getValue().toByteArray());
737           increment.addColumn(family, qualifier, value);
738         }
739       }
740     }
741     if (proto.hasTimeRange()) {
742       HBaseProtos.TimeRange timeRange = proto.getTimeRange();
743       long minStamp = 0;
744       long maxStamp = Long.MAX_VALUE;
745       if (timeRange.hasFrom()) {
746         minStamp = timeRange.getFrom();
747       }
748       if (timeRange.hasTo()) {
749         maxStamp = timeRange.getTo();
750       }
751       increment.setTimeRange(minStamp, maxStamp);
752     }
753     increment.setDurability(toDurability(proto.getDurability()));
754     for (NameBytesPair attribute : proto.getAttributeList()) {
755       increment.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
756     }
757     return increment;
758   }
759 
760   /**
761    * Convert a client Scan to a protocol buffer Scan
762    *
763    * @param scan the client Scan to convert
764    * @return the converted protocol buffer Scan
765    * @throws IOException
766    */
767   public static ClientProtos.Scan toScan(
768       final Scan scan) throws IOException {
769     ClientProtos.Scan.Builder scanBuilder =
770       ClientProtos.Scan.newBuilder();
771     scanBuilder.setCacheBlocks(scan.getCacheBlocks());
772     if (scan.getBatch() > 0) {
773       scanBuilder.setBatchSize(scan.getBatch());
774     }
775     if (scan.getMaxResultSize() > 0) {
776       scanBuilder.setMaxResultSize(scan.getMaxResultSize());
777     }
778     if (scan.isSmall()) {
779       scanBuilder.setSmall(scan.isSmall());
780     }
781     Boolean loadColumnFamiliesOnDemand = scan.getLoadColumnFamiliesOnDemandValue();
782     if (loadColumnFamiliesOnDemand != null) {
783       scanBuilder.setLoadColumnFamiliesOnDemand(loadColumnFamiliesOnDemand.booleanValue());
784     }
785     scanBuilder.setMaxVersions(scan.getMaxVersions());
786     TimeRange timeRange = scan.getTimeRange();
787     if (!timeRange.isAllTime()) {
788       HBaseProtos.TimeRange.Builder timeRangeBuilder =
789         HBaseProtos.TimeRange.newBuilder();
790       timeRangeBuilder.setFrom(timeRange.getMin());
791       timeRangeBuilder.setTo(timeRange.getMax());
792       scanBuilder.setTimeRange(timeRangeBuilder.build());
793     }
794     Map<String, byte[]> attributes = scan.getAttributesMap();
795     if (!attributes.isEmpty()) {
796       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
797       for (Map.Entry<String, byte[]> attribute: attributes.entrySet()) {
798         attributeBuilder.setName(attribute.getKey());
799         attributeBuilder.setValue(ZeroCopyLiteralByteString.wrap(attribute.getValue()));
800         scanBuilder.addAttribute(attributeBuilder.build());
801       }
802     }
803     byte[] startRow = scan.getStartRow();
804     if (startRow != null && startRow.length > 0) {
805       scanBuilder.setStartRow(ZeroCopyLiteralByteString.wrap(startRow));
806     }
807     byte[] stopRow = scan.getStopRow();
808     if (stopRow != null && stopRow.length > 0) {
809       scanBuilder.setStopRow(ZeroCopyLiteralByteString.wrap(stopRow));
810     }
811     if (scan.hasFilter()) {
812       scanBuilder.setFilter(ProtobufUtil.toFilter(scan.getFilter()));
813     }
814     if (scan.hasFamilies()) {
815       Column.Builder columnBuilder = Column.newBuilder();
816       for (Map.Entry<byte[],NavigableSet<byte []>>
817           family: scan.getFamilyMap().entrySet()) {
818         columnBuilder.setFamily(ZeroCopyLiteralByteString.wrap(family.getKey()));
819         NavigableSet<byte []> qualifiers = family.getValue();
820         columnBuilder.clearQualifier();
821         if (qualifiers != null && qualifiers.size() > 0) {
822           for (byte [] qualifier: qualifiers) {
823             columnBuilder.addQualifier(ZeroCopyLiteralByteString.wrap(qualifier));
824           }
825         }
826         scanBuilder.addColumn(columnBuilder.build());
827       }
828     }
829     if (scan.getMaxResultsPerColumnFamily() >= 0) {
830       scanBuilder.setStoreLimit(scan.getMaxResultsPerColumnFamily());
831     }
832     if (scan.getRowOffsetPerColumnFamily() > 0) {
833       scanBuilder.setStoreOffset(scan.getRowOffsetPerColumnFamily());
834     }
835     return scanBuilder.build();
836   }
837 
838   /**
839    * Convert a protocol buffer Scan to a client Scan
840    *
841    * @param proto the protocol buffer Scan to convert
842    * @return the converted client Scan
843    * @throws IOException
844    */
845   public static Scan toScan(
846       final ClientProtos.Scan proto) throws IOException {
847     byte [] startRow = HConstants.EMPTY_START_ROW;
848     byte [] stopRow  = HConstants.EMPTY_END_ROW;
849     if (proto.hasStartRow()) {
850       startRow = proto.getStartRow().toByteArray();
851     }
852     if (proto.hasStopRow()) {
853       stopRow = proto.getStopRow().toByteArray();
854     }
855     Scan scan = new Scan(startRow, stopRow);
856     if (proto.hasCacheBlocks()) {
857       scan.setCacheBlocks(proto.getCacheBlocks());
858     }
859     if (proto.hasMaxVersions()) {
860       scan.setMaxVersions(proto.getMaxVersions());
861     }
862     if (proto.hasStoreLimit()) {
863       scan.setMaxResultsPerColumnFamily(proto.getStoreLimit());
864     }
865     if (proto.hasStoreOffset()) {
866       scan.setRowOffsetPerColumnFamily(proto.getStoreOffset());
867     }
868     if (proto.hasLoadColumnFamiliesOnDemand()) {
869       scan.setLoadColumnFamiliesOnDemand(proto.getLoadColumnFamiliesOnDemand());
870     }
871     if (proto.hasTimeRange()) {
872       HBaseProtos.TimeRange timeRange = proto.getTimeRange();
873       long minStamp = 0;
874       long maxStamp = Long.MAX_VALUE;
875       if (timeRange.hasFrom()) {
876         minStamp = timeRange.getFrom();
877       }
878       if (timeRange.hasTo()) {
879         maxStamp = timeRange.getTo();
880       }
881       scan.setTimeRange(minStamp, maxStamp);
882     }
883     if (proto.hasFilter()) {
884       FilterProtos.Filter filter = proto.getFilter();
885       scan.setFilter(ProtobufUtil.toFilter(filter));
886     }
887     if (proto.hasBatchSize()) {
888       scan.setBatch(proto.getBatchSize());
889     }
890     if (proto.hasMaxResultSize()) {
891       scan.setMaxResultSize(proto.getMaxResultSize());
892     }
893     if (proto.hasSmall()) {
894       scan.setSmall(proto.getSmall());
895     }
896     for (NameBytesPair attribute: proto.getAttributeList()) {
897       scan.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
898     }
899     if (proto.getColumnCount() > 0) {
900       for (Column column: proto.getColumnList()) {
901         byte[] family = column.getFamily().toByteArray();
902         if (column.getQualifierCount() > 0) {
903           for (ByteString qualifier: column.getQualifierList()) {
904             scan.addColumn(family, qualifier.toByteArray());
905           }
906         } else {
907           scan.addFamily(family);
908         }
909       }
910     }
911     return scan;
912   }
913 
914   /**
915    * Create a protocol buffer Get based on a client Get.
916    *
917    * @param get the client Get
918    * @return a protocol buffer Get
919    * @throws IOException
920    */
921   public static ClientProtos.Get toGet(
922       final Get get) throws IOException {
923     ClientProtos.Get.Builder builder =
924       ClientProtos.Get.newBuilder();
925     builder.setRow(ZeroCopyLiteralByteString.wrap(get.getRow()));
926     builder.setCacheBlocks(get.getCacheBlocks());
927     builder.setMaxVersions(get.getMaxVersions());
928     if (get.getFilter() != null) {
929       builder.setFilter(ProtobufUtil.toFilter(get.getFilter()));
930     }
931     TimeRange timeRange = get.getTimeRange();
932     if (!timeRange.isAllTime()) {
933       HBaseProtos.TimeRange.Builder timeRangeBuilder =
934         HBaseProtos.TimeRange.newBuilder();
935       timeRangeBuilder.setFrom(timeRange.getMin());
936       timeRangeBuilder.setTo(timeRange.getMax());
937       builder.setTimeRange(timeRangeBuilder.build());
938     }
939     Map<String, byte[]> attributes = get.getAttributesMap();
940     if (!attributes.isEmpty()) {
941       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
942       for (Map.Entry<String, byte[]> attribute: attributes.entrySet()) {
943         attributeBuilder.setName(attribute.getKey());
944         attributeBuilder.setValue(ZeroCopyLiteralByteString.wrap(attribute.getValue()));
945         builder.addAttribute(attributeBuilder.build());
946       }
947     }
948     if (get.hasFamilies()) {
949       Column.Builder columnBuilder = Column.newBuilder();
950       Map<byte[], NavigableSet<byte[]>> families = get.getFamilyMap();
951       for (Map.Entry<byte[], NavigableSet<byte[]>> family: families.entrySet()) {
952         NavigableSet<byte[]> qualifiers = family.getValue();
953         columnBuilder.setFamily(ZeroCopyLiteralByteString.wrap(family.getKey()));
954         columnBuilder.clearQualifier();
955         if (qualifiers != null && qualifiers.size() > 0) {
956           for (byte[] qualifier: qualifiers) {
957             columnBuilder.addQualifier(ZeroCopyLiteralByteString.wrap(qualifier));
958           }
959         }
960         builder.addColumn(columnBuilder.build());
961       }
962     }
963     if (get.getMaxResultsPerColumnFamily() >= 0) {
964       builder.setStoreLimit(get.getMaxResultsPerColumnFamily());
965     }
966     if (get.getRowOffsetPerColumnFamily() > 0) {
967       builder.setStoreOffset(get.getRowOffsetPerColumnFamily());
968     }
969     if (get.isCheckExistenceOnly()){
970       builder.setExistenceOnly(true);
971     }
972     if (get.isClosestRowBefore()){
973       builder.setClosestRowBefore(true);
974     }
975     return builder.build();
976   }
977 
978   /**
979    * Convert a client Increment to a protobuf Mutate.
980    *
981    * @param increment
982    * @return the converted mutate
983    */
984   public static MutationProto toMutation(final Increment increment,
985       final MutationProto.Builder builder) {
986     builder.setRow(ZeroCopyLiteralByteString.wrap(increment.getRow()));
987     builder.setMutateType(MutationType.INCREMENT);
988     builder.setDurability(toDurability(increment.getDurability()));
989     TimeRange timeRange = increment.getTimeRange();
990     if (!timeRange.isAllTime()) {
991       HBaseProtos.TimeRange.Builder timeRangeBuilder =
992         HBaseProtos.TimeRange.newBuilder();
993       timeRangeBuilder.setFrom(timeRange.getMin());
994       timeRangeBuilder.setTo(timeRange.getMax());
995       builder.setTimeRange(timeRangeBuilder.build());
996     }
997     ColumnValue.Builder columnBuilder = ColumnValue.newBuilder();
998     QualifierValue.Builder valueBuilder = QualifierValue.newBuilder();
999     for (Map.Entry<byte[], List<Cell>> family: increment.getFamilyCellMap().entrySet()) {
1000       columnBuilder.setFamily(ZeroCopyLiteralByteString.wrap(family.getKey()));
1001       columnBuilder.clearQualifierValue();
1002       List<Cell> values = family.getValue();
1003       if (values != null && values.size() > 0) {
1004         for (Cell cell: values) {
1005           KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
1006           valueBuilder.setQualifier(ZeroCopyLiteralByteString.wrap(
1007               kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength()));
1008           valueBuilder.setValue(ZeroCopyLiteralByteString.wrap(
1009               kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()));
1010           columnBuilder.addQualifierValue(valueBuilder.build());
1011         }
1012       }
1013       builder.addColumnValue(columnBuilder.build());
1014     }
1015     Map<String, byte[]> attributes = increment.getAttributesMap();
1016     if (!attributes.isEmpty()) {
1017       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
1018       for (Map.Entry<String, byte[]> attribute : attributes.entrySet()) {
1019         attributeBuilder.setName(attribute.getKey());
1020         attributeBuilder.setValue(ZeroCopyLiteralByteString.wrap(attribute.getValue()));
1021         builder.addAttribute(attributeBuilder.build());
1022       }
1023     }
1024     return builder.build();
1025   }
1026 
1027   /**
1028    * Create a protocol buffer Mutate based on a client Mutation
1029    *
1030    * @param type
1031    * @param mutation
1032    * @return a protobuf'd Mutation
1033    * @throws IOException
1034    */
1035   public static MutationProto toMutation(final MutationType type, final Mutation mutation)
1036   throws IOException {
1037     return toMutation(type, mutation, MutationProto.newBuilder());
1038   }
1039 
1040   public static MutationProto toMutation(final MutationType type, final Mutation mutation,
1041       MutationProto.Builder builder)
1042   throws IOException {
1043     builder = getMutationBuilderAndSetCommonFields(type, mutation, builder);
1044     ColumnValue.Builder columnBuilder = ColumnValue.newBuilder();
1045     QualifierValue.Builder valueBuilder = QualifierValue.newBuilder();
1046     for (Map.Entry<byte[],List<Cell>> family: mutation.getFamilyCellMap().entrySet()) {
1047       columnBuilder.clear();
1048       columnBuilder.setFamily(ZeroCopyLiteralByteString.wrap(family.getKey()));
1049       for (Cell cell: family.getValue()) {
1050         KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
1051         valueBuilder.setQualifier(ZeroCopyLiteralByteString.wrap(
1052             kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength()));
1053         valueBuilder.setValue(ZeroCopyLiteralByteString.wrap(
1054             kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()));
1055         valueBuilder.setTimestamp(kv.getTimestamp());
1056         if (type == MutationType.DELETE) {
1057           KeyValue.Type keyValueType = KeyValue.Type.codeToType(kv.getType());
1058           valueBuilder.setDeleteType(toDeleteType(keyValueType));
1059         }
1060         columnBuilder.addQualifierValue(valueBuilder.build());
1061       }
1062       builder.addColumnValue(columnBuilder.build());
1063     }
1064     return builder.build();
1065   }
1066 
1067   /**
1068    * Create a protocol buffer MutationProto based on a client Mutation. Does NOT include data.
1069    * Understanding is that the Cell will be transported other than via protobuf.
1070    * @param type
1071    * @param mutation
1072    * @param builder
1073    * @return a protobuf'd Mutation
1074    * @throws IOException
1075    */
1076   public static MutationProto toMutationNoData(final MutationType type, final Mutation mutation,
1077       final MutationProto.Builder builder)
1078   throws IOException {
1079     getMutationBuilderAndSetCommonFields(type, mutation, builder);
1080     builder.setAssociatedCellCount(mutation.size());
1081     return builder.build();
1082   }
1083 
1084   /**
1085    * Create a protocol buffer MutationProto based on a client Mutation.  Does NOT include data.
1086    * Understanding is that the Cell will be transported other than via protobuf.
1087    * @param type
1088    * @param mutation
1089    * @return a protobuf'd Mutation
1090    * @throws IOException
1091    */
1092   public static MutationProto toMutationNoData(final MutationType type, final Mutation mutation)
1093   throws IOException {
1094     MutationProto.Builder builder =  MutationProto.newBuilder();
1095     return toMutationNoData(type, mutation, builder);
1096   }
1097 
1098   /**
1099    * Code shared by {@link #toMutation(MutationType, Mutation)} and
1100    * {@link #toMutationNoData(MutationType, Mutation)}
1101    * @param type
1102    * @param mutation
1103    * @return A partly-filled out protobuf'd Mutation.
1104    */
1105   private static MutationProto.Builder getMutationBuilderAndSetCommonFields(final MutationType type,
1106       final Mutation mutation, MutationProto.Builder builder) {
1107     builder.setRow(ZeroCopyLiteralByteString.wrap(mutation.getRow()));
1108     builder.setMutateType(type);
1109     builder.setDurability(toDurability(mutation.getDurability()));
1110     builder.setTimestamp(mutation.getTimeStamp());
1111     Map<String, byte[]> attributes = mutation.getAttributesMap();
1112     if (!attributes.isEmpty()) {
1113       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
1114       for (Map.Entry<String, byte[]> attribute: attributes.entrySet()) {
1115         attributeBuilder.setName(attribute.getKey());
1116         attributeBuilder.setValue(ZeroCopyLiteralByteString.wrap(attribute.getValue()));
1117         builder.addAttribute(attributeBuilder.build());
1118       }
1119     }
1120     return builder;
1121   }
1122 
1123   /**
1124    * Convert a client Result to a protocol buffer Result
1125    *
1126    * @param result the client Result to convert
1127    * @return the converted protocol buffer Result
1128    */
1129   public static ClientProtos.Result toResult(final Result result) {
1130     if (result.getExists() != null) {
1131       return toResult(result.getExists());
1132     }
1133 
1134     Cell[] cells = result.rawCells();
1135     if (cells == null || cells.length == 0) {
1136       return EMPTY_RESULT_PB;
1137     }
1138 
1139     ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder();
1140     for (Cell c : cells) {
1141       builder.addCell(toCell(c));
1142     }
1143 
1144     return builder.build();
1145   }
1146 
1147   /**
1148    * Convert a client Result to a protocol buffer Result
1149    *
1150    * @param existence the client existence to send
1151    * @return the converted protocol buffer Result
1152    */
1153   public static ClientProtos.Result toResult(final boolean existence) {
1154     return existence ? EMPTY_RESULT_PB_EXISTS_TRUE : EMPTY_RESULT_PB_EXISTS_FALSE;
1155   }
1156 
1157   /**
1158    * Convert a client Result to a protocol buffer Result.
1159    * The pb Result does not include the Cell data.  That is for transport otherwise.
1160    *
1161    * @param result the client Result to convert
1162    * @return the converted protocol buffer Result
1163    */
1164   public static ClientProtos.Result toResultNoData(final Result result) {
1165     if (result.getExists() != null) return toResult(result.getExists());
1166     int size = result.size();
1167     if (size == 0) return EMPTY_RESULT_PB;
1168     ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder();
1169     builder.setAssociatedCellCount(size);
1170     return builder.build();
1171   }
1172 
1173   /**
1174    * Convert a protocol buffer Result to a client Result
1175    *
1176    * @param proto the protocol buffer Result to convert
1177    * @return the converted client Result
1178    */
1179   public static Result toResult(final ClientProtos.Result proto) {
1180     if (proto.hasExists()) {
1181       return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE : EMPTY_RESULT_EXISTS_FALSE;
1182     }
1183 
1184     List<CellProtos.Cell> values = proto.getCellList();
1185     if (values.isEmpty()){
1186       return EMPTY_RESULT;
1187     }
1188 
1189     List<Cell> cells = new ArrayList<Cell>(values.size());
1190     for (CellProtos.Cell c : values) {
1191       cells.add(toCell(c));
1192     }
1193     return Result.create(cells, null);
1194   }
1195 
1196   /**
1197    * Convert a protocol buffer Result to a client Result
1198    *
1199    * @param proto the protocol buffer Result to convert
1200    * @param scanner Optional cell scanner.
1201    * @return the converted client Result
1202    * @throws IOException
1203    */
1204   public static Result toResult(final ClientProtos.Result proto, final CellScanner scanner)
1205   throws IOException {
1206     List<CellProtos.Cell> values = proto.getCellList();
1207 
1208     if (proto.hasExists()) {
1209       if ((values != null && !values.isEmpty()) ||
1210           (proto.hasAssociatedCellCount() && proto.getAssociatedCellCount() > 0)) {
1211         throw new IllegalArgumentException("bad proto: exists with cells is no allowed " + proto);
1212       }
1213       return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE : EMPTY_RESULT_EXISTS_FALSE;
1214     }
1215 
1216     // TODO: Unit test that has some Cells in scanner and some in the proto.
1217     List<Cell> cells = null;
1218     if (proto.hasAssociatedCellCount()) {
1219       int count = proto.getAssociatedCellCount();
1220       cells = new ArrayList<Cell>(count + values.size());
1221       for (int i = 0; i < count; i++) {
1222         if (!scanner.advance()) throw new IOException("Failed get " + i + " of " + count);
1223         cells.add(scanner.current());
1224       }
1225     }
1226 
1227     if (!values.isEmpty()){
1228       if (cells == null) cells = new ArrayList<Cell>(values.size());
1229       for (CellProtos.Cell c: values) {
1230         cells.add(toCell(c));
1231       }
1232     }
1233 
1234     return (cells == null || cells.isEmpty()) ? EMPTY_RESULT : Result.create(cells, null);
1235   }
1236 
1237 
1238   /**
1239    * Convert a ByteArrayComparable to a protocol buffer Comparator
1240    *
1241    * @param comparator the ByteArrayComparable to convert
1242    * @return the converted protocol buffer Comparator
1243    */
1244   public static ComparatorProtos.Comparator toComparator(ByteArrayComparable comparator) {
1245     ComparatorProtos.Comparator.Builder builder = ComparatorProtos.Comparator.newBuilder();
1246     builder.setName(comparator.getClass().getName());
1247     builder.setSerializedComparator(ZeroCopyLiteralByteString.wrap(comparator.toByteArray()));
1248     return builder.build();
1249   }
1250 
1251   /**
1252    * Convert a protocol buffer Comparator to a ByteArrayComparable
1253    *
1254    * @param proto the protocol buffer Comparator to convert
1255    * @return the converted ByteArrayComparable
1256    */
1257   @SuppressWarnings("unchecked")
1258   public static ByteArrayComparable toComparator(ComparatorProtos.Comparator proto)
1259   throws IOException {
1260     String type = proto.getName();
1261     String funcName = "parseFrom";
1262     byte [] value = proto.getSerializedComparator().toByteArray();
1263     try {
1264       Class<? extends ByteArrayComparable> c =
1265         (Class<? extends ByteArrayComparable>)Class.forName(type, true, CLASS_LOADER);
1266       Method parseFrom = c.getMethod(funcName, byte[].class);
1267       if (parseFrom == null) {
1268         throw new IOException("Unable to locate function: " + funcName + " in type: " + type);
1269       }
1270       return (ByteArrayComparable)parseFrom.invoke(null, value);
1271     } catch (Exception e) {
1272       throw new IOException(e);
1273     }
1274   }
1275 
1276   /**
1277    * Convert a protocol buffer Filter to a client Filter
1278    *
1279    * @param proto the protocol buffer Filter to convert
1280    * @return the converted Filter
1281    */
1282   @SuppressWarnings("unchecked")
1283   public static Filter toFilter(FilterProtos.Filter proto) throws IOException {
1284     String type = proto.getName();
1285     final byte [] value = proto.getSerializedFilter().toByteArray();
1286     String funcName = "parseFrom";
1287     try {
1288       Class<? extends Filter> c =
1289         (Class<? extends Filter>)Class.forName(type, true, CLASS_LOADER);
1290       Method parseFrom = c.getMethod(funcName, byte[].class);
1291       if (parseFrom == null) {
1292         throw new IOException("Unable to locate function: " + funcName + " in type: " + type);
1293       }
1294       return (Filter)parseFrom.invoke(c, value);
1295     } catch (Exception e) {
1296       throw new IOException(e);
1297     }
1298   }
1299 
1300   /**
1301    * Convert a client Filter to a protocol buffer Filter
1302    *
1303    * @param filter the Filter to convert
1304    * @return the converted protocol buffer Filter
1305    */
1306   public static FilterProtos.Filter toFilter(Filter filter) throws IOException {
1307     FilterProtos.Filter.Builder builder = FilterProtos.Filter.newBuilder();
1308     builder.setName(filter.getClass().getName());
1309     builder.setSerializedFilter(ZeroCopyLiteralByteString.wrap(filter.toByteArray()));
1310     return builder.build();
1311   }
1312 
1313   /**
1314    * Convert a delete KeyValue type to protocol buffer DeleteType.
1315    *
1316    * @param type
1317    * @return protocol buffer DeleteType
1318    * @throws IOException
1319    */
1320   public static DeleteType toDeleteType(
1321       KeyValue.Type type) throws IOException {
1322     switch (type) {
1323     case Delete:
1324       return DeleteType.DELETE_ONE_VERSION;
1325     case DeleteColumn:
1326       return DeleteType.DELETE_MULTIPLE_VERSIONS;
1327     case DeleteFamily:
1328       return DeleteType.DELETE_FAMILY;
1329     case DeleteFamilyVersion:
1330       return DeleteType.DELETE_FAMILY_VERSION;
1331     default:
1332         throw new IOException("Unknown delete type: " + type);
1333     }
1334   }
1335 
1336   /**
1337    * Convert a stringified protocol buffer exception Parameter to a Java Exception
1338    *
1339    * @param parameter the protocol buffer Parameter to convert
1340    * @return the converted Exception
1341    * @throws IOException if failed to deserialize the parameter
1342    */
1343   @SuppressWarnings("unchecked")
1344   public static Throwable toException(final NameBytesPair parameter) throws IOException {
1345     if (parameter == null || !parameter.hasValue()) return null;
1346     String desc = parameter.getValue().toStringUtf8();
1347     String type = parameter.getName();
1348     try {
1349       Class<? extends Throwable> c =
1350         (Class<? extends Throwable>)Class.forName(type, true, CLASS_LOADER);
1351       Constructor<? extends Throwable> cn = null;
1352       try {
1353         cn = c.getDeclaredConstructor(String.class);
1354         return cn.newInstance(desc);
1355       } catch (NoSuchMethodException e) {
1356         // Could be a raw RemoteException. See HBASE-8987.
1357         cn = c.getDeclaredConstructor(String.class, String.class);
1358         return cn.newInstance(type, desc);
1359       }
1360     } catch (Exception e) {
1361       throw new IOException(e);
1362     }
1363   }
1364 
1365 // Start helpers for Client
1366 
1367   /**
1368    * A helper to invoke a Get using client protocol.
1369    *
1370    * @param client
1371    * @param regionName
1372    * @param get
1373    * @return the result of the Get
1374    * @throws IOException
1375    */
1376   public static Result get(final ClientService.BlockingInterface client,
1377       final byte[] regionName, final Get get) throws IOException {
1378     GetRequest request =
1379       RequestConverter.buildGetRequest(regionName, get);
1380     try {
1381       GetResponse response = client.get(null, request);
1382       if (response == null) return null;
1383       return toResult(response.getResult());
1384     } catch (ServiceException se) {
1385       throw getRemoteException(se);
1386     }
1387   }
1388 
1389   /**
1390    * A helper to get a row of the closet one before using client protocol.
1391    *
1392    * @param client
1393    * @param regionName
1394    * @param row
1395    * @param family
1396    * @return the row or the closestRowBefore if it doesn't exist
1397    * @throws IOException
1398    */
1399   public static Result getRowOrBefore(final ClientService.BlockingInterface client,
1400       final byte[] regionName, final byte[] row,
1401       final byte[] family) throws IOException {
1402     GetRequest request =
1403       RequestConverter.buildGetRowOrBeforeRequest(
1404         regionName, row, family);
1405     try {
1406       GetResponse response = client.get(null, request);
1407       if (!response.hasResult()) return null;
1408       return toResult(response.getResult());
1409     } catch (ServiceException se) {
1410       throw getRemoteException(se);
1411     }
1412   }
1413 
1414   /**
1415    * A helper to bulk load a list of HFiles using client protocol.
1416    *
1417    * @param client
1418    * @param familyPaths
1419    * @param regionName
1420    * @param assignSeqNum
1421    * @return true if all are loaded
1422    * @throws IOException
1423    */
1424   public static boolean bulkLoadHFile(final ClientService.BlockingInterface client,
1425       final List<Pair<byte[], String>> familyPaths,
1426       final byte[] regionName, boolean assignSeqNum) throws IOException {
1427     BulkLoadHFileRequest request =
1428       RequestConverter.buildBulkLoadHFileRequest(familyPaths, regionName, assignSeqNum);
1429     try {
1430       BulkLoadHFileResponse response =
1431         client.bulkLoadHFile(null, request);
1432       return response.getLoaded();
1433     } catch (ServiceException se) {
1434       throw getRemoteException(se);
1435     }
1436   }
1437 
1438   public static CoprocessorServiceResponse execService(final ClientService.BlockingInterface client,
1439       final CoprocessorServiceCall call, final byte[] regionName) throws IOException {
1440     CoprocessorServiceRequest request = CoprocessorServiceRequest.newBuilder()
1441         .setCall(call).setRegion(
1442             RequestConverter.buildRegionSpecifier(REGION_NAME, regionName)).build();
1443     try {
1444       CoprocessorServiceResponse response =
1445           client.execService(null, request);
1446       return response;
1447     } catch (ServiceException se) {
1448       throw getRemoteException(se);
1449     }
1450   }
1451 
1452   public static CoprocessorServiceResponse execService(
1453     final MasterService.BlockingInterface client, final CoprocessorServiceCall call)
1454   throws IOException {
1455     CoprocessorServiceRequest request = CoprocessorServiceRequest.newBuilder()
1456         .setCall(call).setRegion(
1457             RequestConverter.buildRegionSpecifier(REGION_NAME, HConstants.EMPTY_BYTE_ARRAY)).build();
1458     try {
1459       CoprocessorServiceResponse response =
1460           client.execMasterService(null, request);
1461       return response;
1462     } catch (ServiceException se) {
1463       throw getRemoteException(se);
1464     }
1465   }
1466 
1467   @SuppressWarnings("unchecked")
1468   public static <T extends Service> T newServiceStub(Class<T> service, RpcChannel channel)
1469       throws Exception {
1470     return (T)Methods.call(service, null, "newStub",
1471         new Class[]{ RpcChannel.class }, new Object[]{ channel });
1472   }
1473 
1474 // End helpers for Client
1475 // Start helpers for Admin
1476 
1477   /**
1478    * A helper to retrieve region info given a region name
1479    * using admin protocol.
1480    *
1481    * @param admin
1482    * @param regionName
1483    * @return the retrieved region info
1484    * @throws IOException
1485    */
1486   public static HRegionInfo getRegionInfo(final AdminService.BlockingInterface admin,
1487       final byte[] regionName) throws IOException {
1488     try {
1489       GetRegionInfoRequest request =
1490         RequestConverter.buildGetRegionInfoRequest(regionName);
1491       GetRegionInfoResponse response =
1492         admin.getRegionInfo(null, request);
1493       return HRegionInfo.convert(response.getRegionInfo());
1494     } catch (ServiceException se) {
1495       throw getRemoteException(se);
1496     }
1497   }
1498 
1499   /**
1500    * A helper to close a region given a region name
1501    * using admin protocol.
1502    *
1503    * @param admin
1504    * @param regionName
1505    * @param transitionInZK
1506    * @throws IOException
1507    */
1508   public static void closeRegion(final AdminService.BlockingInterface admin,
1509       final byte[] regionName, final boolean transitionInZK) throws IOException {
1510     CloseRegionRequest closeRegionRequest =
1511       RequestConverter.buildCloseRegionRequest(regionName, transitionInZK);
1512     try {
1513       admin.closeRegion(null, closeRegionRequest);
1514     } catch (ServiceException se) {
1515       throw getRemoteException(se);
1516     }
1517   }
1518 
1519   /**
1520    * A helper to close a region given a region name
1521    * using admin protocol.
1522    *
1523    * @param admin
1524    * @param regionName
1525    * @param versionOfClosingNode
1526    * @return true if the region is closed
1527    * @throws IOException
1528    */
1529   public static boolean closeRegion(final AdminService.BlockingInterface admin,
1530       final byte[] regionName,
1531       final int versionOfClosingNode, final ServerName destinationServer,
1532       final boolean transitionInZK) throws IOException {
1533     CloseRegionRequest closeRegionRequest =
1534       RequestConverter.buildCloseRegionRequest(
1535         regionName, versionOfClosingNode, destinationServer, transitionInZK);
1536     try {
1537       CloseRegionResponse response = admin.closeRegion(null, closeRegionRequest);
1538       return ResponseConverter.isClosed(response);
1539     } catch (ServiceException se) {
1540       throw getRemoteException(se);
1541     }
1542   }
1543 
1544 
1545   /**
1546    * A helper to open a region using admin protocol.
1547    * @param admin
1548    * @param region
1549    * @throws IOException
1550    */
1551   public static void openRegion(final AdminService.BlockingInterface admin,
1552       final HRegionInfo region) throws IOException {
1553     OpenRegionRequest request =
1554       RequestConverter.buildOpenRegionRequest(region, -1, null);
1555     try {
1556       admin.openRegion(null, request);
1557     } catch (ServiceException se) {
1558       throw ProtobufUtil.getRemoteException(se);
1559     }
1560   }
1561 
1562   /**
1563    * A helper to get the all the online regions on a region
1564    * server using admin protocol.
1565    *
1566    * @param admin
1567    * @return a list of online region info
1568    * @throws IOException
1569    */
1570   public static List<HRegionInfo> getOnlineRegions(final AdminService.BlockingInterface admin)
1571   throws IOException {
1572     GetOnlineRegionRequest request = RequestConverter.buildGetOnlineRegionRequest();
1573     GetOnlineRegionResponse response = null;
1574     try {
1575       response = admin.getOnlineRegion(null, request);
1576     } catch (ServiceException se) {
1577       throw getRemoteException(se);
1578     }
1579     return getRegionInfos(response);
1580   }
1581 
1582   /**
1583    * Get the list of region info from a GetOnlineRegionResponse
1584    *
1585    * @param proto the GetOnlineRegionResponse
1586    * @return the list of region info or null if <code>proto</code> is null
1587    */
1588   static List<HRegionInfo> getRegionInfos(final GetOnlineRegionResponse proto) {
1589     if (proto == null) return null;
1590     List<HRegionInfo> regionInfos = new ArrayList<HRegionInfo>();
1591     for (RegionInfo regionInfo: proto.getRegionInfoList()) {
1592       regionInfos.add(HRegionInfo.convert(regionInfo));
1593     }
1594     return regionInfos;
1595   }
1596 
1597   /**
1598    * A helper to get the info of a region server using admin protocol.
1599    *
1600    * @param admin
1601    * @return the server name
1602    * @throws IOException
1603    */
1604   public static ServerInfo getServerInfo(final AdminService.BlockingInterface admin)
1605   throws IOException {
1606     GetServerInfoRequest request = RequestConverter.buildGetServerInfoRequest();
1607     try {
1608       GetServerInfoResponse response = admin.getServerInfo(null, request);
1609       return response.getServerInfo();
1610     } catch (ServiceException se) {
1611       throw getRemoteException(se);
1612     }
1613   }
1614 
1615   /**
1616    * A helper to get the list of files of a column family
1617    * on a given region using admin protocol.
1618    *
1619    * @param admin
1620    * @param regionName
1621    * @param family
1622    * @return the list of store files
1623    * @throws IOException
1624    */
1625   public static List<String> getStoreFiles(final AdminService.BlockingInterface admin,
1626       final byte[] regionName, final byte[] family)
1627   throws IOException {
1628     GetStoreFileRequest request =
1629       RequestConverter.buildGetStoreFileRequest(regionName, family);
1630     try {
1631       GetStoreFileResponse response = admin.getStoreFile(null, request);
1632       return response.getStoreFileList();
1633     } catch (ServiceException se) {
1634       throw ProtobufUtil.getRemoteException(se);
1635     }
1636   }
1637 
1638   /**
1639    * A helper to split a region using admin protocol.
1640    *
1641    * @param admin
1642    * @param hri
1643    * @param splitPoint
1644    * @throws IOException
1645    */
1646   public static void split(final AdminService.BlockingInterface admin,
1647       final HRegionInfo hri, byte[] splitPoint) throws IOException {
1648     SplitRegionRequest request =
1649       RequestConverter.buildSplitRegionRequest(hri.getRegionName(), splitPoint);
1650     try {
1651       admin.splitRegion(null, request);
1652     } catch (ServiceException se) {
1653       throw ProtobufUtil.getRemoteException(se);
1654     }
1655   }
1656 
1657   /**
1658    * A helper to merge regions using admin protocol. Send request to
1659    * regionserver.
1660    * @param admin
1661    * @param region_a
1662    * @param region_b
1663    * @param forcible true if do a compulsory merge, otherwise we will only merge
1664    *          two adjacent regions
1665    * @throws IOException
1666    */
1667   public static void mergeRegions(final AdminService.BlockingInterface admin,
1668       final HRegionInfo region_a, final HRegionInfo region_b,
1669       final boolean forcible) throws IOException {
1670     MergeRegionsRequest request = RequestConverter.buildMergeRegionsRequest(
1671         region_a.getRegionName(), region_b.getRegionName(),forcible);
1672     try {
1673       admin.mergeRegions(null, request);
1674     } catch (ServiceException se) {
1675       throw ProtobufUtil.getRemoteException(se);
1676     }
1677   }
1678 
1679 // End helpers for Admin
1680 
1681   /*
1682    * Get the total (read + write) requests from a RegionLoad pb
1683    * @param rl - RegionLoad pb
1684    * @return total (read + write) requests
1685    */
1686   public static long getTotalRequestsCount(RegionLoad rl) {
1687     if (rl == null) {
1688       return 0;
1689     }
1690 
1691     return rl.getReadRequestsCount() + rl.getWriteRequestsCount();
1692   }
1693 
1694 
1695   /**
1696    * @param m Message to get delimited pb serialization of (with pb magic prefix)
1697    */
1698   public static byte [] toDelimitedByteArray(final Message m) throws IOException {
1699     // Allocate arbitrary big size so we avoid resizing.
1700     ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
1701     baos.write(PB_MAGIC);
1702     m.writeDelimitedTo(baos);
1703     return baos.toByteArray();
1704   }
1705 
1706   /**
1707    * Converts a Permission proto to a client Permission object.
1708    *
1709    * @param proto the protobuf Permission
1710    * @return the converted Permission
1711    */
1712   public static Permission toPermission(AccessControlProtos.Permission proto) {
1713     if (proto.getType() != AccessControlProtos.Permission.Type.Global) {
1714       return toTablePermission(proto);
1715     } else {
1716       List<Permission.Action> actions = toPermissionActions(proto.getGlobalPermission().getActionList());
1717       return new Permission(actions.toArray(new Permission.Action[actions.size()]));
1718     }
1719   }
1720 
1721   /**
1722    * Converts a Permission proto to a client TablePermission object.
1723    *
1724    * @param proto the protobuf Permission
1725    * @return the converted TablePermission
1726    */
1727   public static TablePermission toTablePermission(AccessControlProtos.Permission proto) {
1728     if(proto.getType() == AccessControlProtos.Permission.Type.Global) {
1729       AccessControlProtos.GlobalPermission perm = proto.getGlobalPermission();
1730       List<Permission.Action> actions = toPermissionActions(perm.getActionList());
1731 
1732       return new TablePermission(null, null, null,
1733           actions.toArray(new Permission.Action[actions.size()]));
1734     }
1735     if(proto.getType() == AccessControlProtos.Permission.Type.Namespace) {
1736       AccessControlProtos.NamespacePermission perm = proto.getNamespacePermission();
1737       List<Permission.Action> actions = toPermissionActions(perm.getActionList());
1738 
1739       if(!proto.hasNamespacePermission()) {
1740         throw new IllegalStateException("Namespace must not be empty in NamespacePermission");
1741       }
1742       String namespace = perm.getNamespaceName().toStringUtf8();
1743       return new TablePermission(namespace, actions.toArray(new Permission.Action[actions.size()]));
1744     }
1745     if(proto.getType() == AccessControlProtos.Permission.Type.Table) {
1746       AccessControlProtos.TablePermission perm = proto.getTablePermission();
1747       List<Permission.Action> actions = toPermissionActions(perm.getActionList());
1748 
1749       byte[] qualifier = null;
1750       byte[] family = null;
1751       TableName table = null;
1752 
1753       if (!perm.hasTableName()) {
1754         throw new IllegalStateException("TableName cannot be empty");
1755       }
1756       table = ProtobufUtil.toTableName(perm.getTableName());
1757 
1758       if (perm.hasFamily()) family = perm.getFamily().toByteArray();
1759       if (perm.hasQualifier()) qualifier = perm.getQualifier().toByteArray();
1760 
1761       return new TablePermission(table, family, qualifier,
1762           actions.toArray(new Permission.Action[actions.size()]));
1763     }
1764     throw new IllegalStateException("Unrecognize Perm Type: "+proto.getType());
1765   }
1766 
1767   /**
1768    * Convert a client Permission to a Permission proto
1769    *
1770    * @param perm the client Permission
1771    * @return the protobuf Permission
1772    */
1773   public static AccessControlProtos.Permission toPermission(Permission perm) {
1774     AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
1775     if (perm instanceof TablePermission) {
1776       TablePermission tablePerm = (TablePermission)perm;
1777       if(tablePerm.hasNamespace()) {
1778         ret.setType(AccessControlProtos.Permission.Type.Namespace);
1779 
1780         AccessControlProtos.NamespacePermission.Builder builder =
1781             AccessControlProtos.NamespacePermission.newBuilder();
1782         builder.setNamespaceName(ByteString.copyFromUtf8(tablePerm.getNamespace()));
1783         for (Permission.Action a : perm.getActions()) {
1784           builder.addAction(toPermissionAction(a));
1785         }
1786         ret.setNamespacePermission(builder);
1787       } else if (tablePerm.hasTable()) {
1788         ret.setType(AccessControlProtos.Permission.Type.Table);
1789 
1790         AccessControlProtos.TablePermission.Builder builder =
1791             AccessControlProtos.TablePermission.newBuilder();
1792         builder.setTableName(ProtobufUtil.toProtoTableName(tablePerm.getTableName()));
1793         if (tablePerm.hasFamily()) {
1794           builder.setFamily(ZeroCopyLiteralByteString.wrap(tablePerm.getFamily()));
1795         }
1796         if (tablePerm.hasQualifier()) {
1797           builder.setQualifier(ZeroCopyLiteralByteString.wrap(tablePerm.getQualifier()));
1798         }
1799         for (Permission.Action a : perm.getActions()) {
1800           builder.addAction(toPermissionAction(a));
1801         }
1802         ret.setTablePermission(builder);
1803       }
1804     } else {
1805       ret.setType(AccessControlProtos.Permission.Type.Global);
1806 
1807       AccessControlProtos.GlobalPermission.Builder builder =
1808           AccessControlProtos.GlobalPermission.newBuilder();
1809       for (Permission.Action a : perm.getActions()) {
1810         builder.addAction(toPermissionAction(a));
1811       }
1812       ret.setGlobalPermission(builder);
1813     }
1814     return ret.build();
1815   }
1816 
1817   /**
1818    * Converts a list of Permission.Action proto to a list of client Permission.Action objects.
1819    *
1820    * @param protoActions the list of protobuf Actions
1821    * @return the converted list of Actions
1822    */
1823   public static List<Permission.Action> toPermissionActions(
1824       List<AccessControlProtos.Permission.Action> protoActions) {
1825     List<Permission.Action> actions = new ArrayList<Permission.Action>(protoActions.size());
1826     for (AccessControlProtos.Permission.Action a : protoActions) {
1827       actions.add(toPermissionAction(a));
1828     }
1829     return actions;
1830   }
1831 
1832   /**
1833    * Converts a Permission.Action proto to a client Permission.Action object.
1834    *
1835    * @param action the protobuf Action
1836    * @return the converted Action
1837    */
1838   public static Permission.Action toPermissionAction(
1839       AccessControlProtos.Permission.Action action) {
1840     switch (action) {
1841       case READ:
1842         return Permission.Action.READ;
1843       case WRITE:
1844         return Permission.Action.WRITE;
1845       case EXEC:
1846         return Permission.Action.EXEC;
1847       case CREATE:
1848         return Permission.Action.CREATE;
1849       case ADMIN:
1850         return Permission.Action.ADMIN;
1851     }
1852     throw new IllegalArgumentException("Unknown action value "+action.name());
1853   }
1854 
1855   /**
1856    * Convert a client Permission.Action to a Permission.Action proto
1857    *
1858    * @param action the client Action
1859    * @return the protobuf Action
1860    */
1861   public static AccessControlProtos.Permission.Action toPermissionAction(
1862       Permission.Action action) {
1863     switch (action) {
1864       case READ:
1865         return AccessControlProtos.Permission.Action.READ;
1866       case WRITE:
1867         return AccessControlProtos.Permission.Action.WRITE;
1868       case EXEC:
1869         return AccessControlProtos.Permission.Action.EXEC;
1870       case CREATE:
1871         return AccessControlProtos.Permission.Action.CREATE;
1872       case ADMIN:
1873         return AccessControlProtos.Permission.Action.ADMIN;
1874     }
1875     throw new IllegalArgumentException("Unknown action value "+action.name());
1876   }
1877 
1878   /**
1879    * Convert a client user permission to a user permission proto
1880    *
1881    * @param perm the client UserPermission
1882    * @return the protobuf UserPermission
1883    */
1884   public static AccessControlProtos.UserPermission toUserPermission(UserPermission perm) {
1885     return AccessControlProtos.UserPermission.newBuilder()
1886         .setUser(ZeroCopyLiteralByteString.wrap(perm.getUser()))
1887         .setPermission(toPermission(perm))
1888         .build();
1889   }
1890 
1891   /**
1892    * Converts a user permission proto to a client user permission object.
1893    *
1894    * @param proto the protobuf UserPermission
1895    * @return the converted UserPermission
1896    */
1897   public static UserPermission toUserPermission(AccessControlProtos.UserPermission proto) {
1898     return new UserPermission(proto.getUser().toByteArray(),
1899         toTablePermission(proto.getPermission()));
1900   }
1901 
1902   /**
1903    * Convert a ListMultimap<String, TablePermission> where key is username
1904    * to a protobuf UserPermission
1905    *
1906    * @param perm the list of user and table permissions
1907    * @return the protobuf UserTablePermissions
1908    */
1909   public static AccessControlProtos.UsersAndPermissions toUserTablePermissions(
1910       ListMultimap<String, TablePermission> perm) {
1911     AccessControlProtos.UsersAndPermissions.Builder builder =
1912                   AccessControlProtos.UsersAndPermissions.newBuilder();
1913     for (Map.Entry<String, Collection<TablePermission>> entry : perm.asMap().entrySet()) {
1914       AccessControlProtos.UsersAndPermissions.UserPermissions.Builder userPermBuilder =
1915                   AccessControlProtos.UsersAndPermissions.UserPermissions.newBuilder();
1916       userPermBuilder.setUser(ByteString.copyFromUtf8(entry.getKey()));
1917       for (TablePermission tablePerm: entry.getValue()) {
1918         userPermBuilder.addPermissions(toPermission(tablePerm));
1919       }
1920       builder.addUserPermissions(userPermBuilder.build());
1921     }
1922     return builder.build();
1923   }
1924 
1925   /**
1926    * A utility used to grant a user global permissions.
1927    * <p>
1928    * It's also called by the shell, in case you want to find references.
1929    *
1930    * @param protocol the AccessControlService protocol proxy
1931    * @param userShortName the short name of the user to grant permissions
1932    * @param actions the permissions to be granted
1933    * @throws ServiceException
1934    */
1935   public static void grant(AccessControlService.BlockingInterface protocol,
1936       String userShortName, Permission.Action... actions) throws ServiceException {
1937     List<AccessControlProtos.Permission.Action> permActions =
1938         Lists.newArrayListWithCapacity(actions.length);
1939     for (Permission.Action a : actions) {
1940       permActions.add(ProtobufUtil.toPermissionAction(a));
1941     }
1942     AccessControlProtos.GrantRequest request = RequestConverter.
1943       buildGrantRequest(userShortName, permActions.toArray(
1944         new AccessControlProtos.Permission.Action[actions.length]));
1945     protocol.grant(null, request);
1946   }
1947 
1948   /**
1949    * A utility used to grant a user table permissions. The permissions will
1950    * be for a table table/column family/qualifier.
1951    * <p>
1952    * It's also called by the shell, in case you want to find references.
1953    *
1954    * @param protocol the AccessControlService protocol proxy
1955    * @param userShortName the short name of the user to grant permissions
1956    * @param tableName optional table name
1957    * @param f optional column family
1958    * @param q optional qualifier
1959    * @param actions the permissions to be granted
1960    * @throws ServiceException
1961    */
1962   public static void grant(AccessControlService.BlockingInterface protocol,
1963       String userShortName, TableName tableName, byte[] f, byte[] q,
1964       Permission.Action... actions) throws ServiceException {
1965     List<AccessControlProtos.Permission.Action> permActions =
1966         Lists.newArrayListWithCapacity(actions.length);
1967     for (Permission.Action a : actions) {
1968       permActions.add(ProtobufUtil.toPermissionAction(a));
1969     }
1970     AccessControlProtos.GrantRequest request = RequestConverter.
1971       buildGrantRequest(userShortName, tableName, f, q, permActions.toArray(
1972         new AccessControlProtos.Permission.Action[actions.length]));
1973     protocol.grant(null, request);
1974   }
1975 
1976   /**
1977    * A utility used to grant a user namespace permissions.
1978    * <p>
1979    * It's also called by the shell, in case you want to find references.
1980    *
1981    * @param protocol the AccessControlService protocol proxy
1982    * @param namespace the short name of the user to grant permissions
1983    * @param actions the permissions to be granted
1984    * @throws ServiceException
1985    */
1986   public static void grant(AccessControlService.BlockingInterface protocol,
1987       String userShortName, String namespace,
1988       Permission.Action... actions) throws ServiceException {
1989     List<AccessControlProtos.Permission.Action> permActions =
1990         Lists.newArrayListWithCapacity(actions.length);
1991     for (Permission.Action a : actions) {
1992       permActions.add(ProtobufUtil.toPermissionAction(a));
1993     }
1994     AccessControlProtos.GrantRequest request = RequestConverter.
1995       buildGrantRequest(userShortName, namespace, permActions.toArray(
1996         new AccessControlProtos.Permission.Action[actions.length]));
1997     protocol.grant(null, request);
1998   }
1999 
2000   /**
2001    * A utility used to revoke a user's global permissions.
2002    * <p>
2003    * It's also called by the shell, in case you want to find references.
2004    *
2005    * @param protocol the AccessControlService protocol proxy
2006    * @param userShortName the short name of the user to revoke permissions
2007    * @param actions the permissions to be revoked
2008    * @throws ServiceException
2009    */
2010   public static void revoke(AccessControlService.BlockingInterface protocol,
2011       String userShortName, Permission.Action... actions) throws ServiceException {
2012     List<AccessControlProtos.Permission.Action> permActions =
2013         Lists.newArrayListWithCapacity(actions.length);
2014     for (Permission.Action a : actions) {
2015       permActions.add(ProtobufUtil.toPermissionAction(a));
2016     }
2017     AccessControlProtos.RevokeRequest request = RequestConverter.
2018       buildRevokeRequest(userShortName, permActions.toArray(
2019         new AccessControlProtos.Permission.Action[actions.length]));
2020     protocol.revoke(null, request);
2021   }
2022 
2023   /**
2024    * A utility used to revoke a user's table permissions. The permissions will
2025    * be for a table/column family/qualifier.
2026    * <p>
2027    * It's also called by the shell, in case you want to find references.
2028    *
2029    * @param protocol the AccessControlService protocol proxy
2030    * @param userShortName the short name of the user to revoke permissions
2031    * @param tableName optional table name
2032    * @param f optional column family
2033    * @param q optional qualifier
2034    * @param actions the permissions to be revoked
2035    * @throws ServiceException
2036    */
2037   public static void revoke(AccessControlService.BlockingInterface protocol,
2038       String userShortName, TableName tableName, byte[] f, byte[] q,
2039       Permission.Action... actions) throws ServiceException {
2040     List<AccessControlProtos.Permission.Action> permActions =
2041         Lists.newArrayListWithCapacity(actions.length);
2042     for (Permission.Action a : actions) {
2043       permActions.add(ProtobufUtil.toPermissionAction(a));
2044     }
2045     AccessControlProtos.RevokeRequest request = RequestConverter.
2046       buildRevokeRequest(userShortName, tableName, f, q, permActions.toArray(
2047         new AccessControlProtos.Permission.Action[actions.length]));
2048     protocol.revoke(null, request);
2049   }
2050 
2051   /**
2052    * A utility used to revoke a user's namespace permissions.
2053    * <p>
2054    * It's also called by the shell, in case you want to find references.
2055    *
2056    * @param protocol the AccessControlService protocol proxy
2057    * @param userShortName the short name of the user to revoke permissions
2058    * @param namespace optional table name
2059    * @param actions the permissions to be revoked
2060    * @throws ServiceException
2061    */
2062   public static void revoke(AccessControlService.BlockingInterface protocol,
2063       String userShortName, String namespace,
2064       Permission.Action... actions) throws ServiceException {
2065     List<AccessControlProtos.Permission.Action> permActions =
2066         Lists.newArrayListWithCapacity(actions.length);
2067     for (Permission.Action a : actions) {
2068       permActions.add(ProtobufUtil.toPermissionAction(a));
2069     }
2070     AccessControlProtos.RevokeRequest request = RequestConverter.
2071       buildRevokeRequest(userShortName, namespace, permActions.toArray(
2072         new AccessControlProtos.Permission.Action[actions.length]));
2073     protocol.revoke(null, request);
2074   }
2075 
2076   /**
2077    * A utility used to get user's global permissions.
2078    * <p>
2079    * It's also called by the shell, in case you want to find references.
2080    *
2081    * @param protocol the AccessControlService protocol proxy
2082    * @throws ServiceException
2083    */
2084   public static List<UserPermission> getUserPermissions(
2085       AccessControlService.BlockingInterface protocol) throws ServiceException {
2086     AccessControlProtos.GetUserPermissionsRequest.Builder builder =
2087       AccessControlProtos.GetUserPermissionsRequest.newBuilder();
2088     builder.setType(AccessControlProtos.Permission.Type.Global);
2089     AccessControlProtos.GetUserPermissionsRequest request = builder.build();
2090     AccessControlProtos.GetUserPermissionsResponse response =
2091       protocol.getUserPermissions(null, request);
2092     List<UserPermission> perms = new ArrayList<UserPermission>();
2093     for (AccessControlProtos.UserPermission perm: response.getUserPermissionList()) {
2094       perms.add(ProtobufUtil.toUserPermission(perm));
2095     }
2096     return perms;
2097   }
2098 
2099   /**
2100    * A utility used to get user table permissions.
2101    * <p>
2102    * It's also called by the shell, in case you want to find references.
2103    *
2104    * @param protocol the AccessControlService protocol proxy
2105    * @param t optional table name
2106    * @throws ServiceException
2107    */
2108   public static List<UserPermission> getUserPermissions(
2109       AccessControlService.BlockingInterface protocol,
2110       TableName t) throws ServiceException {
2111     AccessControlProtos.GetUserPermissionsRequest.Builder builder =
2112       AccessControlProtos.GetUserPermissionsRequest.newBuilder();
2113     if (t != null) {
2114       builder.setTableName(ProtobufUtil.toProtoTableName(t));
2115     }
2116     builder.setType(AccessControlProtos.Permission.Type.Table);
2117     AccessControlProtos.GetUserPermissionsRequest request = builder.build();
2118     AccessControlProtos.GetUserPermissionsResponse response =
2119       protocol.getUserPermissions(null, request);
2120     List<UserPermission> perms = new ArrayList<UserPermission>();
2121     for (AccessControlProtos.UserPermission perm: response.getUserPermissionList()) {
2122       perms.add(ProtobufUtil.toUserPermission(perm));
2123     }
2124     return perms;
2125   }
2126 
2127   /**
2128    * Convert a protobuf UserTablePermissions to a
2129    * ListMultimap<String, TablePermission> where key is username.
2130    *
2131    * @param proto the protobuf UserPermission
2132    * @return the converted UserPermission
2133    */
2134   public static ListMultimap<String, TablePermission> toUserTablePermissions(
2135       AccessControlProtos.UsersAndPermissions proto) {
2136     ListMultimap<String, TablePermission> perms = ArrayListMultimap.create();
2137     AccessControlProtos.UsersAndPermissions.UserPermissions userPerm;
2138 
2139     for (int i = 0; i < proto.getUserPermissionsCount(); i++) {
2140       userPerm = proto.getUserPermissions(i);
2141       for (int j = 0; j < userPerm.getPermissionsCount(); j++) {
2142         TablePermission tablePerm = toTablePermission(userPerm.getPermissions(j));
2143         perms.put(userPerm.getUser().toStringUtf8(), tablePerm);
2144       }
2145     }
2146 
2147     return perms;
2148   }
2149 
2150   /**
2151    * Converts a Token instance (with embedded identifier) to the protobuf representation.
2152    *
2153    * @param token the Token instance to copy
2154    * @return the protobuf Token message
2155    */
2156   public static AuthenticationProtos.Token toToken(Token<AuthenticationTokenIdentifier> token) {
2157     AuthenticationProtos.Token.Builder builder = AuthenticationProtos.Token.newBuilder();
2158     builder.setIdentifier(ZeroCopyLiteralByteString.wrap(token.getIdentifier()));
2159     builder.setPassword(ZeroCopyLiteralByteString.wrap(token.getPassword()));
2160     if (token.getService() != null) {
2161       builder.setService(ByteString.copyFromUtf8(token.getService().toString()));
2162     }
2163     return builder.build();
2164   }
2165 
2166   /**
2167    * Converts a protobuf Token message back into a Token instance.
2168    *
2169    * @param proto the protobuf Token message
2170    * @return the Token instance
2171    */
2172   public static Token<AuthenticationTokenIdentifier> toToken(AuthenticationProtos.Token proto) {
2173     return new Token<AuthenticationTokenIdentifier>(
2174         proto.hasIdentifier() ? proto.getIdentifier().toByteArray() : null,
2175         proto.hasPassword() ? proto.getPassword().toByteArray() : null,
2176         AuthenticationTokenIdentifier.AUTH_TOKEN_TYPE,
2177         proto.hasService() ? new Text(proto.getService().toStringUtf8()) : null);
2178   }
2179 
2180   /**
2181    * Find the HRegion encoded name based on a region specifier
2182    *
2183    * @param regionSpecifier the region specifier
2184    * @return the corresponding region's encoded name
2185    * @throws DoNotRetryIOException if the specifier type is unsupported
2186    */
2187   public static String getRegionEncodedName(
2188       final RegionSpecifier regionSpecifier) throws DoNotRetryIOException {
2189     byte[] value = regionSpecifier.getValue().toByteArray();
2190     RegionSpecifierType type = regionSpecifier.getType();
2191     switch (type) {
2192       case REGION_NAME:
2193         return HRegionInfo.encodeRegionName(value);
2194       case ENCODED_REGION_NAME:
2195         return Bytes.toString(value);
2196       default:
2197         throw new DoNotRetryIOException(
2198           "Unsupported region specifier type: " + type);
2199     }
2200   }
2201 
2202   public static ScanMetrics toScanMetrics(final byte[] bytes) {
2203     Parser<MapReduceProtos.ScanMetrics> parser = MapReduceProtos.ScanMetrics.PARSER;
2204     MapReduceProtos.ScanMetrics pScanMetrics = null;
2205     try {
2206       pScanMetrics = parser.parseFrom(bytes);
2207     } catch (InvalidProtocolBufferException e) {
2208       //Ignored there are just no key values to add.
2209     }
2210     ScanMetrics scanMetrics = new ScanMetrics();
2211     if (pScanMetrics != null) {
2212       for (HBaseProtos.NameInt64Pair pair : pScanMetrics.getMetricsList()) {
2213         if (pair.hasName() && pair.hasValue()) {
2214           scanMetrics.setCounter(pair.getName(), pair.getValue());
2215         }
2216       }
2217     }
2218     return scanMetrics;
2219   }
2220 
2221   public static MapReduceProtos.ScanMetrics toScanMetrics(ScanMetrics scanMetrics) {
2222     MapReduceProtos.ScanMetrics.Builder builder = MapReduceProtos.ScanMetrics.newBuilder();
2223     Map<String, Long> metrics = scanMetrics.getMetricsMap();
2224     for (Entry<String, Long> e : metrics.entrySet()) {
2225       HBaseProtos.NameInt64Pair nameInt64Pair =
2226           HBaseProtos.NameInt64Pair.newBuilder()
2227               .setName(e.getKey())
2228               .setValue(e.getValue())
2229               .build();
2230       builder.addMetrics(nameInt64Pair);
2231     }
2232     return builder.build();
2233   }
2234 
2235   /**
2236    * Unwraps an exception from a protobuf service into the underlying (expected) IOException.
2237    * This method will <strong>always</strong> throw an exception.
2238    * @param se the {@code ServiceException} instance to convert into an {@code IOException}
2239    */
2240   public static void toIOException(ServiceException se) throws IOException {
2241     if (se == null) {
2242       throw new NullPointerException("Null service exception passed!");
2243     }
2244 
2245     Throwable cause = se.getCause();
2246     if (cause != null && cause instanceof IOException) {
2247       throw (IOException)cause;
2248     }
2249     throw new IOException(se);
2250   }
2251 
2252   public static CellProtos.Cell toCell(final Cell kv) {
2253     // Doing this is going to kill us if we do it for all data passed.
2254     // St.Ack 20121205
2255     CellProtos.Cell.Builder kvbuilder = CellProtos.Cell.newBuilder();
2256     kvbuilder.setRow(ZeroCopyLiteralByteString.wrap(kv.getRowArray(), kv.getRowOffset(),
2257       kv.getRowLength()));
2258     kvbuilder.setFamily(ZeroCopyLiteralByteString.wrap(kv.getFamilyArray(),
2259       kv.getFamilyOffset(), kv.getFamilyLength()));
2260     kvbuilder.setQualifier(ZeroCopyLiteralByteString.wrap(kv.getQualifierArray(),
2261       kv.getQualifierOffset(), kv.getQualifierLength()));
2262     kvbuilder.setCellType(CellProtos.CellType.valueOf(kv.getTypeByte()));
2263     kvbuilder.setTimestamp(kv.getTimestamp());
2264     kvbuilder.setValue(ZeroCopyLiteralByteString.wrap(kv.getValueArray(), kv.getValueOffset(),
2265       kv.getValueLength()));
2266     return kvbuilder.build();
2267   }
2268 
2269   public static Cell toCell(final CellProtos.Cell cell) {
2270     // Doing this is going to kill us if we do it for all data passed.
2271     // St.Ack 20121205
2272     return CellUtil.createCell(cell.getRow().toByteArray(),
2273       cell.getFamily().toByteArray(),
2274       cell.getQualifier().toByteArray(),
2275       cell.getTimestamp(),
2276       (byte)cell.getCellType().getNumber(),
2277       cell.getValue().toByteArray());
2278   }
2279 
2280   public static HBaseProtos.NamespaceDescriptor toProtoNamespaceDescriptor(NamespaceDescriptor ns) {
2281     HBaseProtos.NamespaceDescriptor.Builder b =
2282         HBaseProtos.NamespaceDescriptor.newBuilder()
2283             .setName(ByteString.copyFromUtf8(ns.getName()));
2284     for(Map.Entry<String, String> entry: ns.getConfiguration().entrySet()) {
2285       b.addConfiguration(HBaseProtos.NameStringPair.newBuilder()
2286           .setName(entry.getKey())
2287           .setValue(entry.getValue()));
2288     }
2289     return b.build();
2290   }
2291 
2292   public static NamespaceDescriptor toNamespaceDescriptor(
2293       HBaseProtos.NamespaceDescriptor desc) throws IOException {
2294     NamespaceDescriptor.Builder b =
2295       NamespaceDescriptor.create(desc.getName().toStringUtf8());
2296     for(HBaseProtos.NameStringPair prop : desc.getConfigurationList()) {
2297       b.addConfiguration(prop.getName(), prop.getValue());
2298     }
2299     return b.build();
2300   }
2301 
2302   /**
2303    * Get an instance of the argument type declared in a class's signature. The
2304    * argument type is assumed to be a PB Message subclass, and the instance is
2305    * created using parseFrom method on the passed ByteString.
2306    * @param runtimeClass the runtime type of the class
2307    * @param position the position of the argument in the class declaration
2308    * @param b the ByteString which should be parsed to get the instance created
2309    * @return the instance
2310    * @throws IOException
2311    */
2312   @SuppressWarnings("unchecked")
2313   public static <T extends Message>
2314   T getParsedGenericInstance(Class<?> runtimeClass, int position, ByteString b)
2315       throws IOException {
2316     Type type = runtimeClass.getGenericSuperclass();
2317     Type argType = ((ParameterizedType)type).getActualTypeArguments()[position];
2318     Class<T> classType = (Class<T>)argType;
2319     T inst;
2320     try {
2321       Method m = classType.getMethod("parseFrom", ByteString.class);
2322       inst = (T)m.invoke(null, b);
2323       return inst;
2324     } catch (SecurityException e) {
2325       throw new IOException(e);
2326     } catch (NoSuchMethodException e) {
2327       throw new IOException(e);
2328     } catch (IllegalArgumentException e) {
2329       throw new IOException(e);
2330     } catch (InvocationTargetException e) {
2331       throw new IOException(e);
2332     } catch (IllegalAccessException e) {
2333       throw new IOException(e);
2334     }
2335   }
2336 
2337   public static CompactionDescriptor toCompactionDescriptor(HRegionInfo info, byte[] family,
2338       List<Path> inputPaths, List<Path> outputPaths, Path storeDir) {
2339     // compaction descriptor contains relative paths.
2340     // input / output paths are relative to the store dir
2341     // store dir is relative to region dir
2342     CompactionDescriptor.Builder builder = CompactionDescriptor.newBuilder()
2343         .setTableName(ZeroCopyLiteralByteString.wrap(info.getTableName()))
2344         .setEncodedRegionName(ZeroCopyLiteralByteString.wrap(info.getEncodedNameAsBytes()))
2345         .setFamilyName(ZeroCopyLiteralByteString.wrap(family))
2346         .setStoreHomeDir(storeDir.getName()); //make relative
2347     for (Path inputPath : inputPaths) {
2348       builder.addCompactionInput(inputPath.getName()); //relative path
2349     }
2350     for (Path outputPath : outputPaths) {
2351       builder.addCompactionOutput(outputPath.getName());
2352     }
2353     return builder.build();
2354   }
2355 
2356   /**
2357    * Return short version of Message toString'd, shorter than TextFormat#shortDebugString.
2358    * Tries to NOT print out data both because it can be big but also so we do not have data in our
2359    * logs. Use judiciously.
2360    * @param m
2361    * @return toString of passed <code>m</code>
2362    */
2363   public static String getShortTextFormat(Message m) {
2364     if (m == null) return "null";
2365     if (m instanceof ScanRequest) {
2366       // This should be small and safe to output.  No data.
2367       return TextFormat.shortDebugString(m);
2368     } else if (m instanceof RegionServerReportRequest) {
2369       // Print a short message only, just the servername and the requests, not the full load.
2370       RegionServerReportRequest r = (RegionServerReportRequest)m;
2371       return "server " + TextFormat.shortDebugString(r.getServer()) +
2372         " load { numberOfRequests: " + r.getLoad().getNumberOfRequests() + " }";
2373     } else if (m instanceof RegionServerStartupRequest) {
2374       // Should be small enough.
2375       return TextFormat.shortDebugString(m);
2376     } else if (m instanceof MutationProto) {
2377       return toShortString((MutationProto)m);
2378     } else if (m instanceof GetRequest) {
2379       GetRequest r = (GetRequest) m;
2380       return "region= " + getStringForByteString(r.getRegion().getValue()) +
2381           ", row=" + getStringForByteString(r.getGet().getRow());
2382     } else if (m instanceof ClientProtos.MultiRequest) {
2383       ClientProtos.MultiRequest r = (ClientProtos.MultiRequest) m;
2384       // Get first set of Actions.
2385       ClientProtos.RegionAction actions = r.getRegionActionList().get(0);
2386       String row = actions.getActionCount() <= 0? "":
2387         getStringForByteString(actions.getAction(0).hasGet()?
2388           actions.getAction(0).getGet().getRow():
2389           actions.getAction(0).getMutation().getRow());
2390       return "region= " + getStringForByteString(actions.getRegion().getValue()) +
2391           ", for " + r.getRegionActionCount() +
2392           " actions and 1st row key=" + row;
2393     } else if (m instanceof ClientProtos.MutateRequest) {
2394       ClientProtos.MutateRequest r = (ClientProtos.MutateRequest) m;
2395       return "region= " + getStringForByteString(r.getRegion().getValue()) +
2396           ", row=" + getStringForByteString(r.getMutation().getRow());
2397     }
2398     return "TODO: " + m.getClass().toString();
2399   }
2400 
2401   private static String getStringForByteString(ByteString bs) {
2402     return Bytes.toStringBinary(bs.toByteArray());
2403   }
2404 
2405   /**
2406    * Print out some subset of a MutationProto rather than all of it and its data
2407    * @param proto Protobuf to print out
2408    * @return Short String of mutation proto
2409    */
2410   static String toShortString(final MutationProto proto) {
2411     return "row=" + Bytes.toString(proto.getRow().toByteArray()) +
2412         ", type=" + proto.getMutateType().toString();
2413   }
2414 
2415   public static TableName toTableName(HBaseProtos.TableName tableNamePB) {
2416     return TableName.valueOf(tableNamePB.getNamespace().asReadOnlyByteBuffer(),
2417         tableNamePB.getQualifier().asReadOnlyByteBuffer());
2418   }
2419 
2420   public static HBaseProtos.TableName toProtoTableName(TableName tableName) {
2421     return HBaseProtos.TableName.newBuilder()
2422         .setNamespace(ZeroCopyLiteralByteString.wrap(tableName.getNamespace()))
2423         .setQualifier(ZeroCopyLiteralByteString.wrap(tableName.getQualifier())).build();
2424   }
2425 
2426   public static TableName[] getTableNameArray(List<HBaseProtos.TableName> tableNamesList) {
2427     if (tableNamesList == null) {
2428       return new TableName[0];
2429     }
2430     TableName[] tableNames = new TableName[tableNamesList.size()];
2431     for (int i = 0; i < tableNamesList.size(); i++) {
2432       tableNames[i] = toTableName(tableNamesList.get(i));
2433     }
2434     return tableNames;
2435   }
2436 
2437 }