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 com.google.protobuf.HBaseZeroCopyByteString;
40  import org.apache.hadoop.conf.Configuration;
41  import org.apache.hadoop.fs.Path;
42  import org.apache.hadoop.hbase.Cell;
43  import org.apache.hadoop.hbase.CellScanner;
44  import org.apache.hadoop.hbase.CellUtil;
45  import org.apache.hadoop.hbase.TableName;
46  import org.apache.hadoop.hbase.DoNotRetryIOException;
47  import org.apache.hadoop.hbase.HBaseConfiguration;
48  import org.apache.hadoop.hbase.HConstants;
49  import org.apache.hadoop.hbase.HRegionInfo;
50  import org.apache.hadoop.hbase.HTableDescriptor;
51  import org.apache.hadoop.hbase.KeyValue;
52  import org.apache.hadoop.hbase.KeyValueUtil;
53  import org.apache.hadoop.hbase.NamespaceDescriptor;
54  import org.apache.hadoop.hbase.ServerName;
55  import org.apache.hadoop.hbase.client.Append;
56  import org.apache.hadoop.hbase.client.Delete;
57  import org.apache.hadoop.hbase.client.Durability;
58  import org.apache.hadoop.hbase.client.Get;
59  import org.apache.hadoop.hbase.client.Increment;
60  import org.apache.hadoop.hbase.client.Mutation;
61  import org.apache.hadoop.hbase.client.Put;
62  import org.apache.hadoop.hbase.client.Result;
63  import org.apache.hadoop.hbase.client.Scan;
64  import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
65  import org.apache.hadoop.hbase.exceptions.DeserializationException;
66  import org.apache.hadoop.hbase.filter.ByteArrayComparable;
67  import org.apache.hadoop.hbase.filter.Filter;
68  import org.apache.hadoop.hbase.io.TimeRange;
69  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
70  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
71  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService;
72  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionRequest;
73  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionResponse;
74  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetOnlineRegionRequest;
75  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetOnlineRegionResponse;
76  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoRequest;
77  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoResponse;
78  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetServerInfoRequest;
79  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetServerInfoResponse;
80  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileRequest;
81  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileResponse;
82  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.MergeRegionsRequest;
83  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionRequest;
84  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.ServerInfo;
85  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.SplitRegionRequest;
86  import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos;
87  import org.apache.hadoop.hbase.protobuf.generated.CellProtos;
88  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
89  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.BulkLoadHFileRequest;
90  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.BulkLoadHFileResponse;
91  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ClientService;
92  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.Column;
93  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall;
94  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceRequest;
95  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceResponse;
96  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest;
97  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetResponse;
98  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
99  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.ColumnValue;
100 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.ColumnValue.QualifierValue;
101 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.DeleteType;
102 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType;
103 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
104 import org.apache.hadoop.hbase.protobuf.generated.ComparatorProtos;
105 import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
106 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
107 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameBytesPair;
108 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo;
109 import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionLoad;
110 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
111 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
112 import org.apache.hadoop.hbase.protobuf.generated.MapReduceProtos;
113 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.CreateTableRequest;
114 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsResponse;
115 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MasterService;
116 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerReportRequest;
117 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
118 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.CompactionDescriptor;
119 import org.apache.hadoop.hbase.security.access.Permission;
120 import org.apache.hadoop.hbase.security.access.TablePermission;
121 import org.apache.hadoop.hbase.security.access.UserPermission;
122 import org.apache.hadoop.hbase.security.token.AuthenticationTokenIdentifier;
123 import org.apache.hadoop.hbase.util.Bytes;
124 import org.apache.hadoop.hbase.util.DynamicClassLoader;
125 import org.apache.hadoop.hbase.util.Methods;
126 import org.apache.hadoop.hbase.util.Pair;
127 import org.apache.hadoop.io.Text;
128 import org.apache.hadoop.ipc.RemoteException;
129 import org.apache.hadoop.security.token.Token;
130 
131 import com.google.common.collect.ArrayListMultimap;
132 import com.google.common.collect.ListMultimap;
133 import com.google.common.collect.Lists;
134 import com.google.protobuf.ByteString;
135 import com.google.protobuf.InvalidProtocolBufferException;
136 import com.google.protobuf.Message;
137 import com.google.protobuf.Parser;
138 import com.google.protobuf.RpcChannel;
139 import com.google.protobuf.Service;
140 import com.google.protobuf.ServiceException;
141 import com.google.protobuf.TextFormat;
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(CellUtil.createCell(row, family, qualifier, qv.getTimestamp(),
665             KeyValue.Type.Put.getCode(), value));
666         }
667       }
668     }
669     append.setDurability(toDurability(proto.getDurability()));
670     for (NameBytesPair attribute: proto.getAttributeList()) {
671       append.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
672     }
673     return append;
674   }
675 
676   /**
677    * Convert a MutateRequest to Mutation
678    *
679    * @param proto the protocol buffer Mutate to convert
680    * @return the converted Mutation
681    * @throws IOException
682    */
683   public static Mutation toMutation(final MutationProto proto) throws IOException {
684     MutationType type = proto.getMutateType();
685     if (type == MutationType.APPEND) {
686       return toAppend(proto, null);
687     }
688     if (type == MutationType.DELETE) {
689       return toDelete(proto, null);
690     }
691     if (type == MutationType.PUT) {
692       return toPut(proto, null);
693     }
694     throw new IOException("Unknown mutation type " + type);
695   }
696 
697   /**
698    * Convert a protocol buffer Mutate to an Increment
699    *
700    * @param proto the protocol buffer Mutate to convert
701    * @return the converted client Increment
702    * @throws IOException
703    */
704   public static Increment toIncrement(final MutationProto proto, final CellScanner cellScanner)
705   throws IOException {
706     MutationType type = proto.getMutateType();
707     assert type == MutationType.INCREMENT : type.name();
708     byte [] row = proto.hasRow()? proto.getRow().toByteArray(): null;
709     Increment increment = null;
710     int cellCount = proto.hasAssociatedCellCount()? proto.getAssociatedCellCount(): 0;
711     if (cellCount > 0) {
712       // The proto has metadata only and the data is separate to be found in the cellScanner.
713       if (cellScanner == null) {
714         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: " +
715           TextFormat.shortDebugString(proto));
716       }
717       for (int i = 0; i < cellCount; i++) {
718         if (!cellScanner.advance()) {
719           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i +
720             " no cell returned: " + TextFormat.shortDebugString(proto));
721         }
722         Cell cell = cellScanner.current();
723         if (increment == null) {
724           increment = new Increment(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
725         }
726         increment.add(KeyValueUtil.ensureKeyValue(cell));
727       }
728     } else {
729       increment = new Increment(row);
730       for (ColumnValue column: proto.getColumnValueList()) {
731         byte[] family = column.getFamily().toByteArray();
732         for (QualifierValue qv: column.getQualifierValueList()) {
733           byte[] qualifier = qv.getQualifier().toByteArray();
734           if (!qv.hasValue()) {
735             throw new DoNotRetryIOException("Missing required field: qualifer value");
736           }
737           increment.add(CellUtil.createCell(row, family, qualifier, qv.getTimestamp(),
738             KeyValue.Type.Put.getCode(), qv.getValue().toByteArray()));
739         }
740       }
741     }
742     if (proto.hasTimeRange()) {
743       HBaseProtos.TimeRange timeRange = proto.getTimeRange();
744       long minStamp = 0;
745       long maxStamp = Long.MAX_VALUE;
746       if (timeRange.hasFrom()) {
747         minStamp = timeRange.getFrom();
748       }
749       if (timeRange.hasTo()) {
750         maxStamp = timeRange.getTo();
751       }
752       increment.setTimeRange(minStamp, maxStamp);
753     }
754     increment.setDurability(toDurability(proto.getDurability()));
755     for (NameBytesPair attribute : proto.getAttributeList()) {
756       increment.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
757     }
758     return increment;
759   }
760 
761   /**
762    * Convert a client Scan to a protocol buffer Scan
763    *
764    * @param scan the client Scan to convert
765    * @return the converted protocol buffer Scan
766    * @throws IOException
767    */
768   public static ClientProtos.Scan toScan(
769       final Scan scan) throws IOException {
770     ClientProtos.Scan.Builder scanBuilder =
771       ClientProtos.Scan.newBuilder();
772     scanBuilder.setCacheBlocks(scan.getCacheBlocks());
773     if (scan.getBatch() > 0) {
774       scanBuilder.setBatchSize(scan.getBatch());
775     }
776     if (scan.getMaxResultSize() > 0) {
777       scanBuilder.setMaxResultSize(scan.getMaxResultSize());
778     }
779     if (scan.isSmall()) {
780       scanBuilder.setSmall(scan.isSmall());
781     }
782     Boolean loadColumnFamiliesOnDemand = scan.getLoadColumnFamiliesOnDemandValue();
783     if (loadColumnFamiliesOnDemand != null) {
784       scanBuilder.setLoadColumnFamiliesOnDemand(loadColumnFamiliesOnDemand.booleanValue());
785     }
786     scanBuilder.setMaxVersions(scan.getMaxVersions());
787     TimeRange timeRange = scan.getTimeRange();
788     if (!timeRange.isAllTime()) {
789       HBaseProtos.TimeRange.Builder timeRangeBuilder =
790         HBaseProtos.TimeRange.newBuilder();
791       timeRangeBuilder.setFrom(timeRange.getMin());
792       timeRangeBuilder.setTo(timeRange.getMax());
793       scanBuilder.setTimeRange(timeRangeBuilder.build());
794     }
795     Map<String, byte[]> attributes = scan.getAttributesMap();
796     if (!attributes.isEmpty()) {
797       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
798       for (Map.Entry<String, byte[]> attribute: attributes.entrySet()) {
799         attributeBuilder.setName(attribute.getKey());
800         attributeBuilder.setValue(HBaseZeroCopyByteString.wrap(attribute.getValue()));
801         scanBuilder.addAttribute(attributeBuilder.build());
802       }
803     }
804     byte[] startRow = scan.getStartRow();
805     if (startRow != null && startRow.length > 0) {
806       scanBuilder.setStartRow(HBaseZeroCopyByteString.wrap(startRow));
807     }
808     byte[] stopRow = scan.getStopRow();
809     if (stopRow != null && stopRow.length > 0) {
810       scanBuilder.setStopRow(HBaseZeroCopyByteString.wrap(stopRow));
811     }
812     if (scan.hasFilter()) {
813       scanBuilder.setFilter(ProtobufUtil.toFilter(scan.getFilter()));
814     }
815     if (scan.hasFamilies()) {
816       Column.Builder columnBuilder = Column.newBuilder();
817       for (Map.Entry<byte[],NavigableSet<byte []>>
818           family: scan.getFamilyMap().entrySet()) {
819         columnBuilder.setFamily(HBaseZeroCopyByteString.wrap(family.getKey()));
820         NavigableSet<byte []> qualifiers = family.getValue();
821         columnBuilder.clearQualifier();
822         if (qualifiers != null && qualifiers.size() > 0) {
823           for (byte [] qualifier: qualifiers) {
824             columnBuilder.addQualifier(HBaseZeroCopyByteString.wrap(qualifier));
825           }
826         }
827         scanBuilder.addColumn(columnBuilder.build());
828       }
829     }
830     if (scan.getMaxResultsPerColumnFamily() >= 0) {
831       scanBuilder.setStoreLimit(scan.getMaxResultsPerColumnFamily());
832     }
833     if (scan.getRowOffsetPerColumnFamily() > 0) {
834       scanBuilder.setStoreOffset(scan.getRowOffsetPerColumnFamily());
835     }
836     return scanBuilder.build();
837   }
838 
839   /**
840    * Convert a protocol buffer Scan to a client Scan
841    *
842    * @param proto the protocol buffer Scan to convert
843    * @return the converted client Scan
844    * @throws IOException
845    */
846   public static Scan toScan(
847       final ClientProtos.Scan proto) throws IOException {
848     byte [] startRow = HConstants.EMPTY_START_ROW;
849     byte [] stopRow  = HConstants.EMPTY_END_ROW;
850     if (proto.hasStartRow()) {
851       startRow = proto.getStartRow().toByteArray();
852     }
853     if (proto.hasStopRow()) {
854       stopRow = proto.getStopRow().toByteArray();
855     }
856     Scan scan = new Scan(startRow, stopRow);
857     if (proto.hasCacheBlocks()) {
858       scan.setCacheBlocks(proto.getCacheBlocks());
859     }
860     if (proto.hasMaxVersions()) {
861       scan.setMaxVersions(proto.getMaxVersions());
862     }
863     if (proto.hasStoreLimit()) {
864       scan.setMaxResultsPerColumnFamily(proto.getStoreLimit());
865     }
866     if (proto.hasStoreOffset()) {
867       scan.setRowOffsetPerColumnFamily(proto.getStoreOffset());
868     }
869     if (proto.hasLoadColumnFamiliesOnDemand()) {
870       scan.setLoadColumnFamiliesOnDemand(proto.getLoadColumnFamiliesOnDemand());
871     }
872     if (proto.hasTimeRange()) {
873       HBaseProtos.TimeRange timeRange = proto.getTimeRange();
874       long minStamp = 0;
875       long maxStamp = Long.MAX_VALUE;
876       if (timeRange.hasFrom()) {
877         minStamp = timeRange.getFrom();
878       }
879       if (timeRange.hasTo()) {
880         maxStamp = timeRange.getTo();
881       }
882       scan.setTimeRange(minStamp, maxStamp);
883     }
884     if (proto.hasFilter()) {
885       FilterProtos.Filter filter = proto.getFilter();
886       scan.setFilter(ProtobufUtil.toFilter(filter));
887     }
888     if (proto.hasBatchSize()) {
889       scan.setBatch(proto.getBatchSize());
890     }
891     if (proto.hasMaxResultSize()) {
892       scan.setMaxResultSize(proto.getMaxResultSize());
893     }
894     if (proto.hasSmall()) {
895       scan.setSmall(proto.getSmall());
896     }
897     for (NameBytesPair attribute: proto.getAttributeList()) {
898       scan.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
899     }
900     if (proto.getColumnCount() > 0) {
901       for (Column column: proto.getColumnList()) {
902         byte[] family = column.getFamily().toByteArray();
903         if (column.getQualifierCount() > 0) {
904           for (ByteString qualifier: column.getQualifierList()) {
905             scan.addColumn(family, qualifier.toByteArray());
906           }
907         } else {
908           scan.addFamily(family);
909         }
910       }
911     }
912     return scan;
913   }
914 
915   /**
916    * Create a protocol buffer Get based on a client Get.
917    *
918    * @param get the client Get
919    * @return a protocol buffer Get
920    * @throws IOException
921    */
922   public static ClientProtos.Get toGet(
923       final Get get) throws IOException {
924     ClientProtos.Get.Builder builder =
925       ClientProtos.Get.newBuilder();
926     builder.setRow(HBaseZeroCopyByteString.wrap(get.getRow()));
927     builder.setCacheBlocks(get.getCacheBlocks());
928     builder.setMaxVersions(get.getMaxVersions());
929     if (get.getFilter() != null) {
930       builder.setFilter(ProtobufUtil.toFilter(get.getFilter()));
931     }
932     TimeRange timeRange = get.getTimeRange();
933     if (!timeRange.isAllTime()) {
934       HBaseProtos.TimeRange.Builder timeRangeBuilder =
935         HBaseProtos.TimeRange.newBuilder();
936       timeRangeBuilder.setFrom(timeRange.getMin());
937       timeRangeBuilder.setTo(timeRange.getMax());
938       builder.setTimeRange(timeRangeBuilder.build());
939     }
940     Map<String, byte[]> attributes = get.getAttributesMap();
941     if (!attributes.isEmpty()) {
942       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
943       for (Map.Entry<String, byte[]> attribute: attributes.entrySet()) {
944         attributeBuilder.setName(attribute.getKey());
945         attributeBuilder.setValue(HBaseZeroCopyByteString.wrap(attribute.getValue()));
946         builder.addAttribute(attributeBuilder.build());
947       }
948     }
949     if (get.hasFamilies()) {
950       Column.Builder columnBuilder = Column.newBuilder();
951       Map<byte[], NavigableSet<byte[]>> families = get.getFamilyMap();
952       for (Map.Entry<byte[], NavigableSet<byte[]>> family: families.entrySet()) {
953         NavigableSet<byte[]> qualifiers = family.getValue();
954         columnBuilder.setFamily(HBaseZeroCopyByteString.wrap(family.getKey()));
955         columnBuilder.clearQualifier();
956         if (qualifiers != null && qualifiers.size() > 0) {
957           for (byte[] qualifier: qualifiers) {
958             columnBuilder.addQualifier(HBaseZeroCopyByteString.wrap(qualifier));
959           }
960         }
961         builder.addColumn(columnBuilder.build());
962       }
963     }
964     if (get.getMaxResultsPerColumnFamily() >= 0) {
965       builder.setStoreLimit(get.getMaxResultsPerColumnFamily());
966     }
967     if (get.getRowOffsetPerColumnFamily() > 0) {
968       builder.setStoreOffset(get.getRowOffsetPerColumnFamily());
969     }
970     if (get.isCheckExistenceOnly()){
971       builder.setExistenceOnly(true);
972     }
973     if (get.isClosestRowBefore()){
974       builder.setClosestRowBefore(true);
975     }
976     return builder.build();
977   }
978 
979   /**
980    * Convert a client Increment to a protobuf Mutate.
981    *
982    * @param increment
983    * @return the converted mutate
984    */
985   public static MutationProto toMutation(final Increment increment,
986       final MutationProto.Builder builder) {
987     builder.setRow(HBaseZeroCopyByteString.wrap(increment.getRow()));
988     builder.setMutateType(MutationType.INCREMENT);
989     builder.setDurability(toDurability(increment.getDurability()));
990     TimeRange timeRange = increment.getTimeRange();
991     if (!timeRange.isAllTime()) {
992       HBaseProtos.TimeRange.Builder timeRangeBuilder =
993         HBaseProtos.TimeRange.newBuilder();
994       timeRangeBuilder.setFrom(timeRange.getMin());
995       timeRangeBuilder.setTo(timeRange.getMax());
996       builder.setTimeRange(timeRangeBuilder.build());
997     }
998     ColumnValue.Builder columnBuilder = ColumnValue.newBuilder();
999     QualifierValue.Builder valueBuilder = QualifierValue.newBuilder();
1000     for (Map.Entry<byte[], List<Cell>> family: increment.getFamilyCellMap().entrySet()) {
1001       columnBuilder.setFamily(HBaseZeroCopyByteString.wrap(family.getKey()));
1002       columnBuilder.clearQualifierValue();
1003       List<Cell> values = family.getValue();
1004       if (values != null && values.size() > 0) {
1005         for (Cell cell: values) {
1006           KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
1007           valueBuilder.setQualifier(HBaseZeroCopyByteString.wrap(
1008               kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength()));
1009           valueBuilder.setValue(HBaseZeroCopyByteString.wrap(
1010               kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()));
1011           columnBuilder.addQualifierValue(valueBuilder.build());
1012         }
1013       }
1014       builder.addColumnValue(columnBuilder.build());
1015     }
1016     Map<String, byte[]> attributes = increment.getAttributesMap();
1017     if (!attributes.isEmpty()) {
1018       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
1019       for (Map.Entry<String, byte[]> attribute : attributes.entrySet()) {
1020         attributeBuilder.setName(attribute.getKey());
1021         attributeBuilder.setValue(HBaseZeroCopyByteString.wrap(attribute.getValue()));
1022         builder.addAttribute(attributeBuilder.build());
1023       }
1024     }
1025     return builder.build();
1026   }
1027 
1028   /**
1029    * Create a protocol buffer Mutate based on a client Mutation
1030    *
1031    * @param type
1032    * @param mutation
1033    * @return a protobuf'd Mutation
1034    * @throws IOException
1035    */
1036   public static MutationProto toMutation(final MutationType type, final Mutation mutation)
1037   throws IOException {
1038     return toMutation(type, mutation, MutationProto.newBuilder());
1039   }
1040 
1041   public static MutationProto toMutation(final MutationType type, final Mutation mutation,
1042       MutationProto.Builder builder)
1043   throws IOException {
1044     builder = getMutationBuilderAndSetCommonFields(type, mutation, builder);
1045     ColumnValue.Builder columnBuilder = ColumnValue.newBuilder();
1046     QualifierValue.Builder valueBuilder = QualifierValue.newBuilder();
1047     for (Map.Entry<byte[],List<Cell>> family: mutation.getFamilyCellMap().entrySet()) {
1048       columnBuilder.clear();
1049       columnBuilder.setFamily(HBaseZeroCopyByteString.wrap(family.getKey()));
1050       for (Cell cell: family.getValue()) {
1051         KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
1052         valueBuilder.setQualifier(HBaseZeroCopyByteString.wrap(
1053             kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength()));
1054         valueBuilder.setValue(HBaseZeroCopyByteString.wrap(
1055             kv.getValueArray(), kv.getValueOffset(), kv.getValueLength()));
1056         valueBuilder.setTimestamp(kv.getTimestamp());
1057         if (type == MutationType.DELETE) {
1058           KeyValue.Type keyValueType = KeyValue.Type.codeToType(kv.getType());
1059           valueBuilder.setDeleteType(toDeleteType(keyValueType));
1060         }
1061         columnBuilder.addQualifierValue(valueBuilder.build());
1062       }
1063       builder.addColumnValue(columnBuilder.build());
1064     }
1065     return builder.build();
1066   }
1067 
1068   /**
1069    * Create a protocol buffer MutationProto based on a client Mutation. Does NOT include data.
1070    * Understanding is that the Cell will be transported other than via protobuf.
1071    * @param type
1072    * @param mutation
1073    * @param builder
1074    * @return a protobuf'd Mutation
1075    * @throws IOException
1076    */
1077   public static MutationProto toMutationNoData(final MutationType type, final Mutation mutation,
1078       final MutationProto.Builder builder)
1079   throws IOException {
1080     getMutationBuilderAndSetCommonFields(type, mutation, builder);
1081     builder.setAssociatedCellCount(mutation.size());
1082     return builder.build();
1083   }
1084 
1085   /**
1086    * Create a protocol buffer MutationProto based on a client Mutation.  Does NOT include data.
1087    * Understanding is that the Cell will be transported other than via protobuf.
1088    * @param type
1089    * @param mutation
1090    * @return a protobuf'd Mutation
1091    * @throws IOException
1092    */
1093   public static MutationProto toMutationNoData(final MutationType type, final Mutation mutation)
1094   throws IOException {
1095     MutationProto.Builder builder =  MutationProto.newBuilder();
1096     return toMutationNoData(type, mutation, builder);
1097   }
1098 
1099   /**
1100    * Code shared by {@link #toMutation(MutationType, Mutation)} and
1101    * {@link #toMutationNoData(MutationType, Mutation)}
1102    * @param type
1103    * @param mutation
1104    * @return A partly-filled out protobuf'd Mutation.
1105    */
1106   private static MutationProto.Builder getMutationBuilderAndSetCommonFields(final MutationType type,
1107       final Mutation mutation, MutationProto.Builder builder) {
1108     builder.setRow(HBaseZeroCopyByteString.wrap(mutation.getRow()));
1109     builder.setMutateType(type);
1110     builder.setDurability(toDurability(mutation.getDurability()));
1111     builder.setTimestamp(mutation.getTimeStamp());
1112     Map<String, byte[]> attributes = mutation.getAttributesMap();
1113     if (!attributes.isEmpty()) {
1114       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
1115       for (Map.Entry<String, byte[]> attribute: attributes.entrySet()) {
1116         attributeBuilder.setName(attribute.getKey());
1117         attributeBuilder.setValue(HBaseZeroCopyByteString.wrap(attribute.getValue()));
1118         builder.addAttribute(attributeBuilder.build());
1119       }
1120     }
1121     return builder;
1122   }
1123 
1124   /**
1125    * Convert a client Result to a protocol buffer Result
1126    *
1127    * @param result the client Result to convert
1128    * @return the converted protocol buffer Result
1129    */
1130   public static ClientProtos.Result toResult(final Result result) {
1131     if (result.getExists() != null) {
1132       return toResult(result.getExists());
1133     }
1134 
1135     Cell[] cells = result.rawCells();
1136     if (cells == null || cells.length == 0) {
1137       return EMPTY_RESULT_PB;
1138     }
1139 
1140     ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder();
1141     for (Cell c : cells) {
1142       builder.addCell(toCell(c));
1143     }
1144 
1145     return builder.build();
1146   }
1147 
1148   /**
1149    * Convert a client Result to a protocol buffer Result
1150    *
1151    * @param existence the client existence to send
1152    * @return the converted protocol buffer Result
1153    */
1154   public static ClientProtos.Result toResult(final boolean existence) {
1155     return existence ? EMPTY_RESULT_PB_EXISTS_TRUE : EMPTY_RESULT_PB_EXISTS_FALSE;
1156   }
1157 
1158   /**
1159    * Convert a client Result to a protocol buffer Result.
1160    * The pb Result does not include the Cell data.  That is for transport otherwise.
1161    *
1162    * @param result the client Result to convert
1163    * @return the converted protocol buffer Result
1164    */
1165   public static ClientProtos.Result toResultNoData(final Result result) {
1166     if (result.getExists() != null) return toResult(result.getExists());
1167     int size = result.size();
1168     if (size == 0) return EMPTY_RESULT_PB;
1169     ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder();
1170     builder.setAssociatedCellCount(size);
1171     return builder.build();
1172   }
1173 
1174   /**
1175    * Convert a protocol buffer Result to a client Result
1176    *
1177    * @param proto the protocol buffer Result to convert
1178    * @return the converted client Result
1179    */
1180   public static Result toResult(final ClientProtos.Result proto) {
1181     if (proto.hasExists()) {
1182       return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE : EMPTY_RESULT_EXISTS_FALSE;
1183     }
1184 
1185     List<CellProtos.Cell> values = proto.getCellList();
1186     if (values.isEmpty()){
1187       return EMPTY_RESULT;
1188     }
1189 
1190     List<Cell> cells = new ArrayList<Cell>(values.size());
1191     for (CellProtos.Cell c : values) {
1192       cells.add(toCell(c));
1193     }
1194     return Result.create(cells, null);
1195   }
1196 
1197   /**
1198    * Convert a protocol buffer Result to a client Result
1199    *
1200    * @param proto the protocol buffer Result to convert
1201    * @param scanner Optional cell scanner.
1202    * @return the converted client Result
1203    * @throws IOException
1204    */
1205   public static Result toResult(final ClientProtos.Result proto, final CellScanner scanner)
1206   throws IOException {
1207     List<CellProtos.Cell> values = proto.getCellList();
1208 
1209     if (proto.hasExists()) {
1210       if ((values != null && !values.isEmpty()) ||
1211           (proto.hasAssociatedCellCount() && proto.getAssociatedCellCount() > 0)) {
1212         throw new IllegalArgumentException("bad proto: exists with cells is no allowed " + proto);
1213       }
1214       return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE : EMPTY_RESULT_EXISTS_FALSE;
1215     }
1216 
1217     // TODO: Unit test that has some Cells in scanner and some in the proto.
1218     List<Cell> cells = null;
1219     if (proto.hasAssociatedCellCount()) {
1220       int count = proto.getAssociatedCellCount();
1221       cells = new ArrayList<Cell>(count + values.size());
1222       for (int i = 0; i < count; i++) {
1223         if (!scanner.advance()) throw new IOException("Failed get " + i + " of " + count);
1224         cells.add(scanner.current());
1225       }
1226     }
1227 
1228     if (!values.isEmpty()){
1229       if (cells == null) cells = new ArrayList<Cell>(values.size());
1230       for (CellProtos.Cell c: values) {
1231         cells.add(toCell(c));
1232       }
1233     }
1234 
1235     return (cells == null || cells.isEmpty()) ? EMPTY_RESULT : Result.create(cells, null);
1236   }
1237 
1238 
1239   /**
1240    * Convert a ByteArrayComparable to a protocol buffer Comparator
1241    *
1242    * @param comparator the ByteArrayComparable to convert
1243    * @return the converted protocol buffer Comparator
1244    */
1245   public static ComparatorProtos.Comparator toComparator(ByteArrayComparable comparator) {
1246     ComparatorProtos.Comparator.Builder builder = ComparatorProtos.Comparator.newBuilder();
1247     builder.setName(comparator.getClass().getName());
1248     builder.setSerializedComparator(HBaseZeroCopyByteString.wrap(comparator.toByteArray()));
1249     return builder.build();
1250   }
1251 
1252   /**
1253    * Convert a protocol buffer Comparator to a ByteArrayComparable
1254    *
1255    * @param proto the protocol buffer Comparator to convert
1256    * @return the converted ByteArrayComparable
1257    */
1258   @SuppressWarnings("unchecked")
1259   public static ByteArrayComparable toComparator(ComparatorProtos.Comparator proto)
1260   throws IOException {
1261     String type = proto.getName();
1262     String funcName = "parseFrom";
1263     byte [] value = proto.getSerializedComparator().toByteArray();
1264     try {
1265       Class<? extends ByteArrayComparable> c =
1266         (Class<? extends ByteArrayComparable>)Class.forName(type, true, CLASS_LOADER);
1267       Method parseFrom = c.getMethod(funcName, byte[].class);
1268       if (parseFrom == null) {
1269         throw new IOException("Unable to locate function: " + funcName + " in type: " + type);
1270       }
1271       return (ByteArrayComparable)parseFrom.invoke(null, value);
1272     } catch (Exception e) {
1273       throw new IOException(e);
1274     }
1275   }
1276 
1277   /**
1278    * Convert a protocol buffer Filter to a client Filter
1279    *
1280    * @param proto the protocol buffer Filter to convert
1281    * @return the converted Filter
1282    */
1283   @SuppressWarnings("unchecked")
1284   public static Filter toFilter(FilterProtos.Filter proto) throws IOException {
1285     String type = proto.getName();
1286     final byte [] value = proto.getSerializedFilter().toByteArray();
1287     String funcName = "parseFrom";
1288     try {
1289       Class<? extends Filter> c =
1290         (Class<? extends Filter>)Class.forName(type, true, CLASS_LOADER);
1291       Method parseFrom = c.getMethod(funcName, byte[].class);
1292       if (parseFrom == null) {
1293         throw new IOException("Unable to locate function: " + funcName + " in type: " + type);
1294       }
1295       return (Filter)parseFrom.invoke(c, value);
1296     } catch (Exception e) {
1297       throw new IOException(e);
1298     }
1299   }
1300 
1301   /**
1302    * Convert a client Filter to a protocol buffer Filter
1303    *
1304    * @param filter the Filter to convert
1305    * @return the converted protocol buffer Filter
1306    */
1307   public static FilterProtos.Filter toFilter(Filter filter) throws IOException {
1308     FilterProtos.Filter.Builder builder = FilterProtos.Filter.newBuilder();
1309     builder.setName(filter.getClass().getName());
1310     builder.setSerializedFilter(HBaseZeroCopyByteString.wrap(filter.toByteArray()));
1311     return builder.build();
1312   }
1313 
1314   /**
1315    * Convert a delete KeyValue type to protocol buffer DeleteType.
1316    *
1317    * @param type
1318    * @return protocol buffer DeleteType
1319    * @throws IOException
1320    */
1321   public static DeleteType toDeleteType(
1322       KeyValue.Type type) throws IOException {
1323     switch (type) {
1324     case Delete:
1325       return DeleteType.DELETE_ONE_VERSION;
1326     case DeleteColumn:
1327       return DeleteType.DELETE_MULTIPLE_VERSIONS;
1328     case DeleteFamily:
1329       return DeleteType.DELETE_FAMILY;
1330     case DeleteFamilyVersion:
1331       return DeleteType.DELETE_FAMILY_VERSION;
1332     default:
1333         throw new IOException("Unknown delete type: " + type);
1334     }
1335   }
1336 
1337   /**
1338    * Convert a stringified protocol buffer exception Parameter to a Java Exception
1339    *
1340    * @param parameter the protocol buffer Parameter to convert
1341    * @return the converted Exception
1342    * @throws IOException if failed to deserialize the parameter
1343    */
1344   @SuppressWarnings("unchecked")
1345   public static Throwable toException(final NameBytesPair parameter) throws IOException {
1346     if (parameter == null || !parameter.hasValue()) return null;
1347     String desc = parameter.getValue().toStringUtf8();
1348     String type = parameter.getName();
1349     try {
1350       Class<? extends Throwable> c =
1351         (Class<? extends Throwable>)Class.forName(type, true, CLASS_LOADER);
1352       Constructor<? extends Throwable> cn = null;
1353       try {
1354         cn = c.getDeclaredConstructor(String.class);
1355         return cn.newInstance(desc);
1356       } catch (NoSuchMethodException e) {
1357         // Could be a raw RemoteException. See HBASE-8987.
1358         cn = c.getDeclaredConstructor(String.class, String.class);
1359         return cn.newInstance(type, desc);
1360       }
1361     } catch (Exception e) {
1362       throw new IOException(e);
1363     }
1364   }
1365 
1366 // Start helpers for Client
1367 
1368   /**
1369    * A helper to invoke a Get using client protocol.
1370    *
1371    * @param client
1372    * @param regionName
1373    * @param get
1374    * @return the result of the Get
1375    * @throws IOException
1376    */
1377   public static Result get(final ClientService.BlockingInterface client,
1378       final byte[] regionName, final Get get) throws IOException {
1379     GetRequest request =
1380       RequestConverter.buildGetRequest(regionName, get);
1381     try {
1382       GetResponse response = client.get(null, request);
1383       if (response == null) return null;
1384       return toResult(response.getResult());
1385     } catch (ServiceException se) {
1386       throw getRemoteException(se);
1387     }
1388   }
1389 
1390   /**
1391    * A helper to get a row of the closet one before using client protocol.
1392    *
1393    * @param client
1394    * @param regionName
1395    * @param row
1396    * @param family
1397    * @return the row or the closestRowBefore if it doesn't exist
1398    * @throws IOException
1399    */
1400   public static Result getRowOrBefore(final ClientService.BlockingInterface client,
1401       final byte[] regionName, final byte[] row,
1402       final byte[] family) throws IOException {
1403     GetRequest request =
1404       RequestConverter.buildGetRowOrBeforeRequest(
1405         regionName, row, family);
1406     try {
1407       GetResponse response = client.get(null, request);
1408       if (!response.hasResult()) return null;
1409       return toResult(response.getResult());
1410     } catch (ServiceException se) {
1411       throw getRemoteException(se);
1412     }
1413   }
1414 
1415   /**
1416    * A helper to bulk load a list of HFiles using client protocol.
1417    *
1418    * @param client
1419    * @param familyPaths
1420    * @param regionName
1421    * @param assignSeqNum
1422    * @return true if all are loaded
1423    * @throws IOException
1424    */
1425   public static boolean bulkLoadHFile(final ClientService.BlockingInterface client,
1426       final List<Pair<byte[], String>> familyPaths,
1427       final byte[] regionName, boolean assignSeqNum) throws IOException {
1428     BulkLoadHFileRequest request =
1429       RequestConverter.buildBulkLoadHFileRequest(familyPaths, regionName, assignSeqNum);
1430     try {
1431       BulkLoadHFileResponse response =
1432         client.bulkLoadHFile(null, request);
1433       return response.getLoaded();
1434     } catch (ServiceException se) {
1435       throw getRemoteException(se);
1436     }
1437   }
1438 
1439   public static CoprocessorServiceResponse execService(final ClientService.BlockingInterface client,
1440       final CoprocessorServiceCall call, final byte[] regionName) throws IOException {
1441     CoprocessorServiceRequest request = CoprocessorServiceRequest.newBuilder()
1442         .setCall(call).setRegion(
1443             RequestConverter.buildRegionSpecifier(REGION_NAME, regionName)).build();
1444     try {
1445       CoprocessorServiceResponse response =
1446           client.execService(null, request);
1447       return response;
1448     } catch (ServiceException se) {
1449       throw getRemoteException(se);
1450     }
1451   }
1452 
1453   public static CoprocessorServiceResponse execService(
1454     final MasterService.BlockingInterface client, final CoprocessorServiceCall call)
1455   throws IOException {
1456     CoprocessorServiceRequest request = CoprocessorServiceRequest.newBuilder()
1457         .setCall(call).setRegion(
1458             RequestConverter.buildRegionSpecifier(REGION_NAME, HConstants.EMPTY_BYTE_ARRAY)).build();
1459     try {
1460       CoprocessorServiceResponse response =
1461           client.execMasterService(null, request);
1462       return response;
1463     } catch (ServiceException se) {
1464       throw getRemoteException(se);
1465     }
1466   }
1467 
1468   @SuppressWarnings("unchecked")
1469   public static <T extends Service> T newServiceStub(Class<T> service, RpcChannel channel)
1470       throws Exception {
1471     return (T)Methods.call(service, null, "newStub",
1472         new Class[]{ RpcChannel.class }, new Object[]{ channel });
1473   }
1474 
1475 // End helpers for Client
1476 // Start helpers for Admin
1477 
1478   /**
1479    * A helper to retrieve region info given a region name
1480    * using admin protocol.
1481    *
1482    * @param admin
1483    * @param regionName
1484    * @return the retrieved region info
1485    * @throws IOException
1486    */
1487   public static HRegionInfo getRegionInfo(final AdminService.BlockingInterface admin,
1488       final byte[] regionName) throws IOException {
1489     try {
1490       GetRegionInfoRequest request =
1491         RequestConverter.buildGetRegionInfoRequest(regionName);
1492       GetRegionInfoResponse response =
1493         admin.getRegionInfo(null, request);
1494       return HRegionInfo.convert(response.getRegionInfo());
1495     } catch (ServiceException se) {
1496       throw getRemoteException(se);
1497     }
1498   }
1499 
1500   /**
1501    * A helper to close a region given a region name
1502    * using admin protocol.
1503    *
1504    * @param admin
1505    * @param regionName
1506    * @param transitionInZK
1507    * @throws IOException
1508    */
1509   public static void closeRegion(final AdminService.BlockingInterface admin,
1510       final ServerName server, final byte[] regionName, final boolean transitionInZK) throws IOException {
1511     CloseRegionRequest closeRegionRequest =
1512       RequestConverter.buildCloseRegionRequest(server, regionName, transitionInZK);
1513     try {
1514       admin.closeRegion(null, closeRegionRequest);
1515     } catch (ServiceException se) {
1516       throw getRemoteException(se);
1517     }
1518   }
1519 
1520   /**
1521    * A helper to close a region given a region name
1522    * using admin protocol.
1523    *
1524    * @param admin
1525    * @param regionName
1526    * @param versionOfClosingNode
1527    * @return true if the region is closed
1528    * @throws IOException
1529    */
1530   public static boolean closeRegion(final AdminService.BlockingInterface admin,
1531       final ServerName server,
1532       final byte[] regionName,
1533       final int versionOfClosingNode, final ServerName destinationServer,
1534       final boolean transitionInZK) throws IOException {
1535     CloseRegionRequest closeRegionRequest =
1536       RequestConverter.buildCloseRegionRequest(server,
1537         regionName, versionOfClosingNode, destinationServer, transitionInZK);
1538     try {
1539       CloseRegionResponse response = admin.closeRegion(null, closeRegionRequest);
1540       return ResponseConverter.isClosed(response);
1541     } catch (ServiceException se) {
1542       throw getRemoteException(se);
1543     }
1544   }
1545 
1546 
1547   /**
1548    * A helper to open a region using admin protocol.
1549    * @param admin
1550    * @param region
1551    * @throws IOException
1552    */
1553   public static void openRegion(final AdminService.BlockingInterface admin,
1554       ServerName server, final HRegionInfo region) throws IOException {
1555     OpenRegionRequest request =
1556       RequestConverter.buildOpenRegionRequest(server, region, -1, null);
1557     try {
1558       admin.openRegion(null, request);
1559     } catch (ServiceException se) {
1560       throw ProtobufUtil.getRemoteException(se);
1561     }
1562   }
1563 
1564   /**
1565    * A helper to get the all the online regions on a region
1566    * server using admin protocol.
1567    *
1568    * @param admin
1569    * @return a list of online region info
1570    * @throws IOException
1571    */
1572   public static List<HRegionInfo> getOnlineRegions(final AdminService.BlockingInterface admin)
1573   throws IOException {
1574     GetOnlineRegionRequest request = RequestConverter.buildGetOnlineRegionRequest();
1575     GetOnlineRegionResponse response = null;
1576     try {
1577       response = admin.getOnlineRegion(null, request);
1578     } catch (ServiceException se) {
1579       throw getRemoteException(se);
1580     }
1581     return getRegionInfos(response);
1582   }
1583 
1584   /**
1585    * Get the list of region info from a GetOnlineRegionResponse
1586    *
1587    * @param proto the GetOnlineRegionResponse
1588    * @return the list of region info or null if <code>proto</code> is null
1589    */
1590   static List<HRegionInfo> getRegionInfos(final GetOnlineRegionResponse proto) {
1591     if (proto == null) return null;
1592     List<HRegionInfo> regionInfos = new ArrayList<HRegionInfo>();
1593     for (RegionInfo regionInfo: proto.getRegionInfoList()) {
1594       regionInfos.add(HRegionInfo.convert(regionInfo));
1595     }
1596     return regionInfos;
1597   }
1598 
1599   /**
1600    * A helper to get the info of a region server using admin protocol.
1601    *
1602    * @param admin
1603    * @return the server name
1604    * @throws IOException
1605    */
1606   public static ServerInfo getServerInfo(final AdminService.BlockingInterface admin)
1607   throws IOException {
1608     GetServerInfoRequest request = RequestConverter.buildGetServerInfoRequest();
1609     try {
1610       GetServerInfoResponse response = admin.getServerInfo(null, request);
1611       return response.getServerInfo();
1612     } catch (ServiceException se) {
1613       throw getRemoteException(se);
1614     }
1615   }
1616 
1617   /**
1618    * A helper to get the list of files of a column family
1619    * on a given region using admin protocol.
1620    *
1621    * @param admin
1622    * @param regionName
1623    * @param family
1624    * @return the list of store files
1625    * @throws IOException
1626    */
1627   public static List<String> getStoreFiles(final AdminService.BlockingInterface admin,
1628       final byte[] regionName, final byte[] family)
1629   throws IOException {
1630     GetStoreFileRequest request =
1631       RequestConverter.buildGetStoreFileRequest(regionName, family);
1632     try {
1633       GetStoreFileResponse response = admin.getStoreFile(null, request);
1634       return response.getStoreFileList();
1635     } catch (ServiceException se) {
1636       throw ProtobufUtil.getRemoteException(se);
1637     }
1638   }
1639 
1640   /**
1641    * A helper to split a region using admin protocol.
1642    *
1643    * @param admin
1644    * @param hri
1645    * @param splitPoint
1646    * @throws IOException
1647    */
1648   public static void split(final AdminService.BlockingInterface admin,
1649       final HRegionInfo hri, byte[] splitPoint) throws IOException {
1650     SplitRegionRequest request =
1651       RequestConverter.buildSplitRegionRequest(hri.getRegionName(), splitPoint);
1652     try {
1653       admin.splitRegion(null, request);
1654     } catch (ServiceException se) {
1655       throw ProtobufUtil.getRemoteException(se);
1656     }
1657   }
1658 
1659   /**
1660    * A helper to merge regions using admin protocol. Send request to
1661    * regionserver.
1662    * @param admin
1663    * @param region_a
1664    * @param region_b
1665    * @param forcible true if do a compulsory merge, otherwise we will only merge
1666    *          two adjacent regions
1667    * @throws IOException
1668    */
1669   public static void mergeRegions(final AdminService.BlockingInterface admin,
1670       final HRegionInfo region_a, final HRegionInfo region_b,
1671       final boolean forcible) throws IOException {
1672     MergeRegionsRequest request = RequestConverter.buildMergeRegionsRequest(
1673         region_a.getRegionName(), region_b.getRegionName(),forcible);
1674     try {
1675       admin.mergeRegions(null, request);
1676     } catch (ServiceException se) {
1677       throw ProtobufUtil.getRemoteException(se);
1678     }
1679   }
1680 
1681 // End helpers for Admin
1682 
1683   /*
1684    * Get the total (read + write) requests from a RegionLoad pb
1685    * @param rl - RegionLoad pb
1686    * @return total (read + write) requests
1687    */
1688   public static long getTotalRequestsCount(RegionLoad rl) {
1689     if (rl == null) {
1690       return 0;
1691     }
1692 
1693     return rl.getReadRequestsCount() + rl.getWriteRequestsCount();
1694   }
1695 
1696 
1697   /**
1698    * @param m Message to get delimited pb serialization of (with pb magic prefix)
1699    */
1700   public static byte [] toDelimitedByteArray(final Message m) throws IOException {
1701     // Allocate arbitrary big size so we avoid resizing.
1702     ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
1703     baos.write(PB_MAGIC);
1704     m.writeDelimitedTo(baos);
1705     return baos.toByteArray();
1706   }
1707 
1708   /**
1709    * Converts a Permission proto to a client Permission object.
1710    *
1711    * @param proto the protobuf Permission
1712    * @return the converted Permission
1713    */
1714   public static Permission toPermission(AccessControlProtos.Permission proto) {
1715     if (proto.getType() != AccessControlProtos.Permission.Type.Global) {
1716       return toTablePermission(proto);
1717     } else {
1718       List<Permission.Action> actions = toPermissionActions(proto.getGlobalPermission().getActionList());
1719       return new Permission(actions.toArray(new Permission.Action[actions.size()]));
1720     }
1721   }
1722 
1723   /**
1724    * Converts a Permission proto to a client TablePermission object.
1725    *
1726    * @param proto the protobuf Permission
1727    * @return the converted TablePermission
1728    */
1729   public static TablePermission toTablePermission(AccessControlProtos.Permission proto) {
1730     if(proto.getType() == AccessControlProtos.Permission.Type.Global) {
1731       AccessControlProtos.GlobalPermission perm = proto.getGlobalPermission();
1732       List<Permission.Action> actions = toPermissionActions(perm.getActionList());
1733 
1734       return new TablePermission(null, null, null,
1735           actions.toArray(new Permission.Action[actions.size()]));
1736     }
1737     if(proto.getType() == AccessControlProtos.Permission.Type.Namespace) {
1738       AccessControlProtos.NamespacePermission perm = proto.getNamespacePermission();
1739       List<Permission.Action> actions = toPermissionActions(perm.getActionList());
1740 
1741       if(!proto.hasNamespacePermission()) {
1742         throw new IllegalStateException("Namespace must not be empty in NamespacePermission");
1743       }
1744       String namespace = perm.getNamespaceName().toStringUtf8();
1745       return new TablePermission(namespace, actions.toArray(new Permission.Action[actions.size()]));
1746     }
1747     if(proto.getType() == AccessControlProtos.Permission.Type.Table) {
1748       AccessControlProtos.TablePermission perm = proto.getTablePermission();
1749       List<Permission.Action> actions = toPermissionActions(perm.getActionList());
1750 
1751       byte[] qualifier = null;
1752       byte[] family = null;
1753       TableName table = null;
1754 
1755       if (!perm.hasTableName()) {
1756         throw new IllegalStateException("TableName cannot be empty");
1757       }
1758       table = ProtobufUtil.toTableName(perm.getTableName());
1759 
1760       if (perm.hasFamily()) family = perm.getFamily().toByteArray();
1761       if (perm.hasQualifier()) qualifier = perm.getQualifier().toByteArray();
1762 
1763       return new TablePermission(table, family, qualifier,
1764           actions.toArray(new Permission.Action[actions.size()]));
1765     }
1766     throw new IllegalStateException("Unrecognize Perm Type: "+proto.getType());
1767   }
1768 
1769   /**
1770    * Convert a client Permission to a Permission proto
1771    *
1772    * @param perm the client Permission
1773    * @return the protobuf Permission
1774    */
1775   public static AccessControlProtos.Permission toPermission(Permission perm) {
1776     AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
1777     if (perm instanceof TablePermission) {
1778       TablePermission tablePerm = (TablePermission)perm;
1779       if(tablePerm.hasNamespace()) {
1780         ret.setType(AccessControlProtos.Permission.Type.Namespace);
1781 
1782         AccessControlProtos.NamespacePermission.Builder builder =
1783             AccessControlProtos.NamespacePermission.newBuilder();
1784         builder.setNamespaceName(ByteString.copyFromUtf8(tablePerm.getNamespace()));
1785         for (Permission.Action a : perm.getActions()) {
1786           builder.addAction(toPermissionAction(a));
1787         }
1788         ret.setNamespacePermission(builder);
1789       } else if (tablePerm.hasTable()) {
1790         ret.setType(AccessControlProtos.Permission.Type.Table);
1791 
1792         AccessControlProtos.TablePermission.Builder builder =
1793             AccessControlProtos.TablePermission.newBuilder();
1794         builder.setTableName(ProtobufUtil.toProtoTableName(tablePerm.getTableName()));
1795         if (tablePerm.hasFamily()) {
1796           builder.setFamily(HBaseZeroCopyByteString.wrap(tablePerm.getFamily()));
1797         }
1798         if (tablePerm.hasQualifier()) {
1799           builder.setQualifier(HBaseZeroCopyByteString.wrap(tablePerm.getQualifier()));
1800         }
1801         for (Permission.Action a : perm.getActions()) {
1802           builder.addAction(toPermissionAction(a));
1803         }
1804         ret.setTablePermission(builder);
1805       }
1806     } else {
1807       ret.setType(AccessControlProtos.Permission.Type.Global);
1808 
1809       AccessControlProtos.GlobalPermission.Builder builder =
1810           AccessControlProtos.GlobalPermission.newBuilder();
1811       for (Permission.Action a : perm.getActions()) {
1812         builder.addAction(toPermissionAction(a));
1813       }
1814       ret.setGlobalPermission(builder);
1815     }
1816     return ret.build();
1817   }
1818 
1819   /**
1820    * Converts a list of Permission.Action proto to a list of client Permission.Action objects.
1821    *
1822    * @param protoActions the list of protobuf Actions
1823    * @return the converted list of Actions
1824    */
1825   public static List<Permission.Action> toPermissionActions(
1826       List<AccessControlProtos.Permission.Action> protoActions) {
1827     List<Permission.Action> actions = new ArrayList<Permission.Action>(protoActions.size());
1828     for (AccessControlProtos.Permission.Action a : protoActions) {
1829       actions.add(toPermissionAction(a));
1830     }
1831     return actions;
1832   }
1833 
1834   /**
1835    * Converts a Permission.Action proto to a client Permission.Action object.
1836    *
1837    * @param action the protobuf Action
1838    * @return the converted Action
1839    */
1840   public static Permission.Action toPermissionAction(
1841       AccessControlProtos.Permission.Action action) {
1842     switch (action) {
1843       case READ:
1844         return Permission.Action.READ;
1845       case WRITE:
1846         return Permission.Action.WRITE;
1847       case EXEC:
1848         return Permission.Action.EXEC;
1849       case CREATE:
1850         return Permission.Action.CREATE;
1851       case ADMIN:
1852         return Permission.Action.ADMIN;
1853     }
1854     throw new IllegalArgumentException("Unknown action value "+action.name());
1855   }
1856 
1857   /**
1858    * Convert a client Permission.Action to a Permission.Action proto
1859    *
1860    * @param action the client Action
1861    * @return the protobuf Action
1862    */
1863   public static AccessControlProtos.Permission.Action toPermissionAction(
1864       Permission.Action action) {
1865     switch (action) {
1866       case READ:
1867         return AccessControlProtos.Permission.Action.READ;
1868       case WRITE:
1869         return AccessControlProtos.Permission.Action.WRITE;
1870       case EXEC:
1871         return AccessControlProtos.Permission.Action.EXEC;
1872       case CREATE:
1873         return AccessControlProtos.Permission.Action.CREATE;
1874       case ADMIN:
1875         return AccessControlProtos.Permission.Action.ADMIN;
1876     }
1877     throw new IllegalArgumentException("Unknown action value "+action.name());
1878   }
1879 
1880   /**
1881    * Convert a client user permission to a user permission proto
1882    *
1883    * @param perm the client UserPermission
1884    * @return the protobuf UserPermission
1885    */
1886   public static AccessControlProtos.UserPermission toUserPermission(UserPermission perm) {
1887     return AccessControlProtos.UserPermission.newBuilder()
1888         .setUser(HBaseZeroCopyByteString.wrap(perm.getUser()))
1889         .setPermission(toPermission(perm))
1890         .build();
1891   }
1892 
1893   /**
1894    * Converts a user permission proto to a client user permission object.
1895    *
1896    * @param proto the protobuf UserPermission
1897    * @return the converted UserPermission
1898    */
1899   public static UserPermission toUserPermission(AccessControlProtos.UserPermission proto) {
1900     return new UserPermission(proto.getUser().toByteArray(),
1901         toTablePermission(proto.getPermission()));
1902   }
1903 
1904   /**
1905    * Convert a ListMultimap<String, TablePermission> where key is username
1906    * to a protobuf UserPermission
1907    *
1908    * @param perm the list of user and table permissions
1909    * @return the protobuf UserTablePermissions
1910    */
1911   public static AccessControlProtos.UsersAndPermissions toUserTablePermissions(
1912       ListMultimap<String, TablePermission> perm) {
1913     AccessControlProtos.UsersAndPermissions.Builder builder =
1914                   AccessControlProtos.UsersAndPermissions.newBuilder();
1915     for (Map.Entry<String, Collection<TablePermission>> entry : perm.asMap().entrySet()) {
1916       AccessControlProtos.UsersAndPermissions.UserPermissions.Builder userPermBuilder =
1917                   AccessControlProtos.UsersAndPermissions.UserPermissions.newBuilder();
1918       userPermBuilder.setUser(ByteString.copyFromUtf8(entry.getKey()));
1919       for (TablePermission tablePerm: entry.getValue()) {
1920         userPermBuilder.addPermissions(toPermission(tablePerm));
1921       }
1922       builder.addUserPermissions(userPermBuilder.build());
1923     }
1924     return builder.build();
1925   }
1926 
1927   /**
1928    * A utility used to grant a user global permissions.
1929    * <p>
1930    * It's also called by the shell, in case you want to find references.
1931    *
1932    * @param protocol the AccessControlService protocol proxy
1933    * @param userShortName the short name of the user to grant permissions
1934    * @param actions the permissions to be granted
1935    * @throws ServiceException
1936    */
1937   public static void grant(AccessControlService.BlockingInterface protocol,
1938       String userShortName, Permission.Action... actions) throws ServiceException {
1939     List<AccessControlProtos.Permission.Action> permActions =
1940         Lists.newArrayListWithCapacity(actions.length);
1941     for (Permission.Action a : actions) {
1942       permActions.add(ProtobufUtil.toPermissionAction(a));
1943     }
1944     AccessControlProtos.GrantRequest request = RequestConverter.
1945       buildGrantRequest(userShortName, permActions.toArray(
1946         new AccessControlProtos.Permission.Action[actions.length]));
1947     protocol.grant(null, request);
1948   }
1949 
1950   /**
1951    * A utility used to grant a user table permissions. The permissions will
1952    * be for a table table/column family/qualifier.
1953    * <p>
1954    * It's also called by the shell, in case you want to find references.
1955    *
1956    * @param protocol the AccessControlService protocol proxy
1957    * @param userShortName the short name of the user to grant permissions
1958    * @param tableName optional table name
1959    * @param f optional column family
1960    * @param q optional qualifier
1961    * @param actions the permissions to be granted
1962    * @throws ServiceException
1963    */
1964   public static void grant(AccessControlService.BlockingInterface protocol,
1965       String userShortName, TableName tableName, byte[] f, byte[] q,
1966       Permission.Action... actions) throws ServiceException {
1967     List<AccessControlProtos.Permission.Action> permActions =
1968         Lists.newArrayListWithCapacity(actions.length);
1969     for (Permission.Action a : actions) {
1970       permActions.add(ProtobufUtil.toPermissionAction(a));
1971     }
1972     AccessControlProtos.GrantRequest request = RequestConverter.
1973       buildGrantRequest(userShortName, tableName, f, q, permActions.toArray(
1974         new AccessControlProtos.Permission.Action[actions.length]));
1975     protocol.grant(null, request);
1976   }
1977 
1978   /**
1979    * A utility used to grant a user namespace permissions.
1980    * <p>
1981    * It's also called by the shell, in case you want to find references.
1982    *
1983    * @param protocol the AccessControlService protocol proxy
1984    * @param namespace the short name of the user to grant permissions
1985    * @param actions the permissions to be granted
1986    * @throws ServiceException
1987    */
1988   public static void grant(AccessControlService.BlockingInterface protocol,
1989       String userShortName, String namespace,
1990       Permission.Action... actions) throws ServiceException {
1991     List<AccessControlProtos.Permission.Action> permActions =
1992         Lists.newArrayListWithCapacity(actions.length);
1993     for (Permission.Action a : actions) {
1994       permActions.add(ProtobufUtil.toPermissionAction(a));
1995     }
1996     AccessControlProtos.GrantRequest request = RequestConverter.
1997       buildGrantRequest(userShortName, namespace, permActions.toArray(
1998         new AccessControlProtos.Permission.Action[actions.length]));
1999     protocol.grant(null, request);
2000   }
2001 
2002   /**
2003    * A utility used to revoke a user's global permissions.
2004    * <p>
2005    * It's also called by the shell, in case you want to find references.
2006    *
2007    * @param protocol the AccessControlService protocol proxy
2008    * @param userShortName the short name of the user to revoke permissions
2009    * @param actions the permissions to be revoked
2010    * @throws ServiceException
2011    */
2012   public static void revoke(AccessControlService.BlockingInterface protocol,
2013       String userShortName, Permission.Action... actions) throws ServiceException {
2014     List<AccessControlProtos.Permission.Action> permActions =
2015         Lists.newArrayListWithCapacity(actions.length);
2016     for (Permission.Action a : actions) {
2017       permActions.add(ProtobufUtil.toPermissionAction(a));
2018     }
2019     AccessControlProtos.RevokeRequest request = RequestConverter.
2020       buildRevokeRequest(userShortName, permActions.toArray(
2021         new AccessControlProtos.Permission.Action[actions.length]));
2022     protocol.revoke(null, request);
2023   }
2024 
2025   /**
2026    * A utility used to revoke a user's table permissions. The permissions will
2027    * be for a table/column family/qualifier.
2028    * <p>
2029    * It's also called by the shell, in case you want to find references.
2030    *
2031    * @param protocol the AccessControlService protocol proxy
2032    * @param userShortName the short name of the user to revoke permissions
2033    * @param tableName optional table name
2034    * @param f optional column family
2035    * @param q optional qualifier
2036    * @param actions the permissions to be revoked
2037    * @throws ServiceException
2038    */
2039   public static void revoke(AccessControlService.BlockingInterface protocol,
2040       String userShortName, TableName tableName, byte[] f, byte[] q,
2041       Permission.Action... actions) throws ServiceException {
2042     List<AccessControlProtos.Permission.Action> permActions =
2043         Lists.newArrayListWithCapacity(actions.length);
2044     for (Permission.Action a : actions) {
2045       permActions.add(ProtobufUtil.toPermissionAction(a));
2046     }
2047     AccessControlProtos.RevokeRequest request = RequestConverter.
2048       buildRevokeRequest(userShortName, tableName, f, q, permActions.toArray(
2049         new AccessControlProtos.Permission.Action[actions.length]));
2050     protocol.revoke(null, request);
2051   }
2052 
2053   /**
2054    * A utility used to revoke a user's namespace permissions.
2055    * <p>
2056    * It's also called by the shell, in case you want to find references.
2057    *
2058    * @param protocol the AccessControlService protocol proxy
2059    * @param userShortName the short name of the user to revoke permissions
2060    * @param namespace optional table name
2061    * @param actions the permissions to be revoked
2062    * @throws ServiceException
2063    */
2064   public static void revoke(AccessControlService.BlockingInterface protocol,
2065       String userShortName, String namespace,
2066       Permission.Action... actions) throws ServiceException {
2067     List<AccessControlProtos.Permission.Action> permActions =
2068         Lists.newArrayListWithCapacity(actions.length);
2069     for (Permission.Action a : actions) {
2070       permActions.add(ProtobufUtil.toPermissionAction(a));
2071     }
2072     AccessControlProtos.RevokeRequest request = RequestConverter.
2073       buildRevokeRequest(userShortName, namespace, permActions.toArray(
2074         new AccessControlProtos.Permission.Action[actions.length]));
2075     protocol.revoke(null, request);
2076   }
2077 
2078   /**
2079    * A utility used to get user's global permissions.
2080    * <p>
2081    * It's also called by the shell, in case you want to find references.
2082    *
2083    * @param protocol the AccessControlService protocol proxy
2084    * @throws ServiceException
2085    */
2086   public static List<UserPermission> getUserPermissions(
2087       AccessControlService.BlockingInterface protocol) throws ServiceException {
2088     AccessControlProtos.GetUserPermissionsRequest.Builder builder =
2089       AccessControlProtos.GetUserPermissionsRequest.newBuilder();
2090     builder.setType(AccessControlProtos.Permission.Type.Global);
2091     AccessControlProtos.GetUserPermissionsRequest request = builder.build();
2092     AccessControlProtos.GetUserPermissionsResponse response =
2093       protocol.getUserPermissions(null, request);
2094     List<UserPermission> perms = new ArrayList<UserPermission>();
2095     for (AccessControlProtos.UserPermission perm: response.getUserPermissionList()) {
2096       perms.add(ProtobufUtil.toUserPermission(perm));
2097     }
2098     return perms;
2099   }
2100 
2101   /**
2102    * A utility used to get user table permissions.
2103    * <p>
2104    * It's also called by the shell, in case you want to find references.
2105    *
2106    * @param protocol the AccessControlService protocol proxy
2107    * @param t optional table name
2108    * @throws ServiceException
2109    */
2110   public static List<UserPermission> getUserPermissions(
2111       AccessControlService.BlockingInterface protocol,
2112       TableName t) throws ServiceException {
2113     AccessControlProtos.GetUserPermissionsRequest.Builder builder =
2114       AccessControlProtos.GetUserPermissionsRequest.newBuilder();
2115     if (t != null) {
2116       builder.setTableName(ProtobufUtil.toProtoTableName(t));
2117     }
2118     builder.setType(AccessControlProtos.Permission.Type.Table);
2119     AccessControlProtos.GetUserPermissionsRequest request = builder.build();
2120     AccessControlProtos.GetUserPermissionsResponse response =
2121       protocol.getUserPermissions(null, request);
2122     List<UserPermission> perms = new ArrayList<UserPermission>();
2123     for (AccessControlProtos.UserPermission perm: response.getUserPermissionList()) {
2124       perms.add(ProtobufUtil.toUserPermission(perm));
2125     }
2126     return perms;
2127   }
2128 
2129   /**
2130    * Convert a protobuf UserTablePermissions to a
2131    * ListMultimap<String, TablePermission> where key is username.
2132    *
2133    * @param proto the protobuf UserPermission
2134    * @return the converted UserPermission
2135    */
2136   public static ListMultimap<String, TablePermission> toUserTablePermissions(
2137       AccessControlProtos.UsersAndPermissions proto) {
2138     ListMultimap<String, TablePermission> perms = ArrayListMultimap.create();
2139     AccessControlProtos.UsersAndPermissions.UserPermissions userPerm;
2140 
2141     for (int i = 0; i < proto.getUserPermissionsCount(); i++) {
2142       userPerm = proto.getUserPermissions(i);
2143       for (int j = 0; j < userPerm.getPermissionsCount(); j++) {
2144         TablePermission tablePerm = toTablePermission(userPerm.getPermissions(j));
2145         perms.put(userPerm.getUser().toStringUtf8(), tablePerm);
2146       }
2147     }
2148 
2149     return perms;
2150   }
2151 
2152   /**
2153    * Converts a Token instance (with embedded identifier) to the protobuf representation.
2154    *
2155    * @param token the Token instance to copy
2156    * @return the protobuf Token message
2157    */
2158   public static AuthenticationProtos.Token toToken(Token<AuthenticationTokenIdentifier> token) {
2159     AuthenticationProtos.Token.Builder builder = AuthenticationProtos.Token.newBuilder();
2160     builder.setIdentifier(HBaseZeroCopyByteString.wrap(token.getIdentifier()));
2161     builder.setPassword(HBaseZeroCopyByteString.wrap(token.getPassword()));
2162     if (token.getService() != null) {
2163       builder.setService(ByteString.copyFromUtf8(token.getService().toString()));
2164     }
2165     return builder.build();
2166   }
2167 
2168   /**
2169    * Converts a protobuf Token message back into a Token instance.
2170    *
2171    * @param proto the protobuf Token message
2172    * @return the Token instance
2173    */
2174   public static Token<AuthenticationTokenIdentifier> toToken(AuthenticationProtos.Token proto) {
2175     return new Token<AuthenticationTokenIdentifier>(
2176         proto.hasIdentifier() ? proto.getIdentifier().toByteArray() : null,
2177         proto.hasPassword() ? proto.getPassword().toByteArray() : null,
2178         AuthenticationTokenIdentifier.AUTH_TOKEN_TYPE,
2179         proto.hasService() ? new Text(proto.getService().toStringUtf8()) : null);
2180   }
2181 
2182   /**
2183    * Find the HRegion encoded name based on a region specifier
2184    *
2185    * @param regionSpecifier the region specifier
2186    * @return the corresponding region's encoded name
2187    * @throws DoNotRetryIOException if the specifier type is unsupported
2188    */
2189   public static String getRegionEncodedName(
2190       final RegionSpecifier regionSpecifier) throws DoNotRetryIOException {
2191     byte[] value = regionSpecifier.getValue().toByteArray();
2192     RegionSpecifierType type = regionSpecifier.getType();
2193     switch (type) {
2194       case REGION_NAME:
2195         return HRegionInfo.encodeRegionName(value);
2196       case ENCODED_REGION_NAME:
2197         return Bytes.toString(value);
2198       default:
2199         throw new DoNotRetryIOException(
2200           "Unsupported region specifier type: " + type);
2201     }
2202   }
2203 
2204   public static ScanMetrics toScanMetrics(final byte[] bytes) {
2205     Parser<MapReduceProtos.ScanMetrics> parser = MapReduceProtos.ScanMetrics.PARSER;
2206     MapReduceProtos.ScanMetrics pScanMetrics = null;
2207     try {
2208       pScanMetrics = parser.parseFrom(bytes);
2209     } catch (InvalidProtocolBufferException e) {
2210       //Ignored there are just no key values to add.
2211     }
2212     ScanMetrics scanMetrics = new ScanMetrics();
2213     if (pScanMetrics != null) {
2214       for (HBaseProtos.NameInt64Pair pair : pScanMetrics.getMetricsList()) {
2215         if (pair.hasName() && pair.hasValue()) {
2216           scanMetrics.setCounter(pair.getName(), pair.getValue());
2217         }
2218       }
2219     }
2220     return scanMetrics;
2221   }
2222 
2223   public static MapReduceProtos.ScanMetrics toScanMetrics(ScanMetrics scanMetrics) {
2224     MapReduceProtos.ScanMetrics.Builder builder = MapReduceProtos.ScanMetrics.newBuilder();
2225     Map<String, Long> metrics = scanMetrics.getMetricsMap();
2226     for (Entry<String, Long> e : metrics.entrySet()) {
2227       HBaseProtos.NameInt64Pair nameInt64Pair =
2228           HBaseProtos.NameInt64Pair.newBuilder()
2229               .setName(e.getKey())
2230               .setValue(e.getValue())
2231               .build();
2232       builder.addMetrics(nameInt64Pair);
2233     }
2234     return builder.build();
2235   }
2236 
2237   /**
2238    * Unwraps an exception from a protobuf service into the underlying (expected) IOException.
2239    * This method will <strong>always</strong> throw an exception.
2240    * @param se the {@code ServiceException} instance to convert into an {@code IOException}
2241    */
2242   public static void toIOException(ServiceException se) throws IOException {
2243     if (se == null) {
2244       throw new NullPointerException("Null service exception passed!");
2245     }
2246 
2247     Throwable cause = se.getCause();
2248     if (cause != null && cause instanceof IOException) {
2249       throw (IOException)cause;
2250     }
2251     throw new IOException(se);
2252   }
2253 
2254   public static CellProtos.Cell toCell(final Cell kv) {
2255     // Doing this is going to kill us if we do it for all data passed.
2256     // St.Ack 20121205
2257     CellProtos.Cell.Builder kvbuilder = CellProtos.Cell.newBuilder();
2258     kvbuilder.setRow(HBaseZeroCopyByteString.wrap(kv.getRowArray(), kv.getRowOffset(),
2259         kv.getRowLength()));
2260     kvbuilder.setFamily(HBaseZeroCopyByteString.wrap(kv.getFamilyArray(),
2261         kv.getFamilyOffset(), kv.getFamilyLength()));
2262     kvbuilder.setQualifier(HBaseZeroCopyByteString.wrap(kv.getQualifierArray(),
2263         kv.getQualifierOffset(), kv.getQualifierLength()));
2264     kvbuilder.setCellType(CellProtos.CellType.valueOf(kv.getTypeByte()));
2265     kvbuilder.setTimestamp(kv.getTimestamp());
2266     kvbuilder.setValue(HBaseZeroCopyByteString.wrap(kv.getValueArray(), kv.getValueOffset(),
2267         kv.getValueLength()));
2268     return kvbuilder.build();
2269   }
2270 
2271   public static Cell toCell(final CellProtos.Cell cell) {
2272     // Doing this is going to kill us if we do it for all data passed.
2273     // St.Ack 20121205
2274     return CellUtil.createCell(cell.getRow().toByteArray(),
2275       cell.getFamily().toByteArray(),
2276       cell.getQualifier().toByteArray(),
2277       cell.getTimestamp(),
2278       (byte)cell.getCellType().getNumber(),
2279       cell.getValue().toByteArray());
2280   }
2281 
2282   public static HBaseProtos.NamespaceDescriptor toProtoNamespaceDescriptor(NamespaceDescriptor ns) {
2283     HBaseProtos.NamespaceDescriptor.Builder b =
2284         HBaseProtos.NamespaceDescriptor.newBuilder()
2285             .setName(ByteString.copyFromUtf8(ns.getName()));
2286     for(Map.Entry<String, String> entry: ns.getConfiguration().entrySet()) {
2287       b.addConfiguration(HBaseProtos.NameStringPair.newBuilder()
2288           .setName(entry.getKey())
2289           .setValue(entry.getValue()));
2290     }
2291     return b.build();
2292   }
2293 
2294   public static NamespaceDescriptor toNamespaceDescriptor(
2295       HBaseProtos.NamespaceDescriptor desc) throws IOException {
2296     NamespaceDescriptor.Builder b =
2297       NamespaceDescriptor.create(desc.getName().toStringUtf8());
2298     for(HBaseProtos.NameStringPair prop : desc.getConfigurationList()) {
2299       b.addConfiguration(prop.getName(), prop.getValue());
2300     }
2301     return b.build();
2302   }
2303 
2304   /**
2305    * Get an instance of the argument type declared in a class's signature. The
2306    * argument type is assumed to be a PB Message subclass, and the instance is
2307    * created using parseFrom method on the passed ByteString.
2308    * @param runtimeClass the runtime type of the class
2309    * @param position the position of the argument in the class declaration
2310    * @param b the ByteString which should be parsed to get the instance created
2311    * @return the instance
2312    * @throws IOException
2313    */
2314   @SuppressWarnings("unchecked")
2315   public static <T extends Message>
2316   T getParsedGenericInstance(Class<?> runtimeClass, int position, ByteString b)
2317       throws IOException {
2318     Type type = runtimeClass.getGenericSuperclass();
2319     Type argType = ((ParameterizedType)type).getActualTypeArguments()[position];
2320     Class<T> classType = (Class<T>)argType;
2321     T inst;
2322     try {
2323       Method m = classType.getMethod("parseFrom", ByteString.class);
2324       inst = (T)m.invoke(null, b);
2325       return inst;
2326     } catch (SecurityException e) {
2327       throw new IOException(e);
2328     } catch (NoSuchMethodException e) {
2329       throw new IOException(e);
2330     } catch (IllegalArgumentException e) {
2331       throw new IOException(e);
2332     } catch (InvocationTargetException e) {
2333       throw new IOException(e);
2334     } catch (IllegalAccessException e) {
2335       throw new IOException(e);
2336     }
2337   }
2338 
2339   public static CompactionDescriptor toCompactionDescriptor(HRegionInfo info, byte[] family,
2340       List<Path> inputPaths, List<Path> outputPaths, Path storeDir) {
2341     // compaction descriptor contains relative paths.
2342     // input / output paths are relative to the store dir
2343     // store dir is relative to region dir
2344     CompactionDescriptor.Builder builder = CompactionDescriptor.newBuilder()
2345         .setTableName(HBaseZeroCopyByteString.wrap(info.getTableName()))
2346         .setEncodedRegionName(HBaseZeroCopyByteString.wrap(info.getEncodedNameAsBytes()))
2347         .setFamilyName(HBaseZeroCopyByteString.wrap(family))
2348         .setStoreHomeDir(storeDir.getName()); //make relative
2349     for (Path inputPath : inputPaths) {
2350       builder.addCompactionInput(inputPath.getName()); //relative path
2351     }
2352     for (Path outputPath : outputPaths) {
2353       builder.addCompactionOutput(outputPath.getName());
2354     }
2355     return builder.build();
2356   }
2357 
2358   /**
2359    * Return short version of Message toString'd, shorter than TextFormat#shortDebugString.
2360    * Tries to NOT print out data both because it can be big but also so we do not have data in our
2361    * logs. Use judiciously.
2362    * @param m
2363    * @return toString of passed <code>m</code>
2364    */
2365   public static String getShortTextFormat(Message m) {
2366     if (m == null) return "null";
2367     if (m instanceof ScanRequest) {
2368       // This should be small and safe to output.  No data.
2369       return TextFormat.shortDebugString(m);
2370     } else if (m instanceof RegionServerReportRequest) {
2371       // Print a short message only, just the servername and the requests, not the full load.
2372       RegionServerReportRequest r = (RegionServerReportRequest)m;
2373       return "server " + TextFormat.shortDebugString(r.getServer()) +
2374         " load { numberOfRequests: " + r.getLoad().getNumberOfRequests() + " }";
2375     } else if (m instanceof RegionServerStartupRequest) {
2376       // Should be small enough.
2377       return TextFormat.shortDebugString(m);
2378     } else if (m instanceof MutationProto) {
2379       return toShortString((MutationProto)m);
2380     } else if (m instanceof GetRequest) {
2381       GetRequest r = (GetRequest) m;
2382       return "region= " + getStringForByteString(r.getRegion().getValue()) +
2383           ", row=" + getStringForByteString(r.getGet().getRow());
2384     } else if (m instanceof ClientProtos.MultiRequest) {
2385       ClientProtos.MultiRequest r = (ClientProtos.MultiRequest) m;
2386       // Get first set of Actions.
2387       ClientProtos.RegionAction actions = r.getRegionActionList().get(0);
2388       String row = actions.getActionCount() <= 0? "":
2389         getStringForByteString(actions.getAction(0).hasGet()?
2390           actions.getAction(0).getGet().getRow():
2391           actions.getAction(0).getMutation().getRow());
2392       return "region= " + getStringForByteString(actions.getRegion().getValue()) +
2393           ", for " + r.getRegionActionCount() +
2394           " actions and 1st row key=" + row;
2395     } else if (m instanceof ClientProtos.MutateRequest) {
2396       ClientProtos.MutateRequest r = (ClientProtos.MutateRequest) m;
2397       return "region= " + getStringForByteString(r.getRegion().getValue()) +
2398           ", row=" + getStringForByteString(r.getMutation().getRow());
2399     }
2400     return "TODO: " + m.getClass().toString();
2401   }
2402 
2403   private static String getStringForByteString(ByteString bs) {
2404     return Bytes.toStringBinary(bs.toByteArray());
2405   }
2406 
2407   /**
2408    * Print out some subset of a MutationProto rather than all of it and its data
2409    * @param proto Protobuf to print out
2410    * @return Short String of mutation proto
2411    */
2412   static String toShortString(final MutationProto proto) {
2413     return "row=" + Bytes.toString(proto.getRow().toByteArray()) +
2414         ", type=" + proto.getMutateType().toString();
2415   }
2416 
2417   public static TableName toTableName(HBaseProtos.TableName tableNamePB) {
2418     return TableName.valueOf(tableNamePB.getNamespace().asReadOnlyByteBuffer(),
2419         tableNamePB.getQualifier().asReadOnlyByteBuffer());
2420   }
2421 
2422   public static HBaseProtos.TableName toProtoTableName(TableName tableName) {
2423     return HBaseProtos.TableName.newBuilder()
2424         .setNamespace(HBaseZeroCopyByteString.wrap(tableName.getNamespace()))
2425         .setQualifier(HBaseZeroCopyByteString.wrap(tableName.getQualifier())).build();
2426   }
2427 
2428   public static TableName[] getTableNameArray(List<HBaseProtos.TableName> tableNamesList) {
2429     if (tableNamesList == null) {
2430       return new TableName[0];
2431     }
2432     TableName[] tableNames = new TableName[tableNamesList.size()];
2433     for (int i = 0; i < tableNamesList.size(); i++) {
2434       tableNames[i] = toTableName(tableNamesList.get(i));
2435     }
2436     return tableNames;
2437   }
2438 
2439 }