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 distributed 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 com.google.protobuf.HBaseZeroCopyByteString.zeroCopyGetBytes;
22  import static org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType.REGION_NAME;
23  
24  import com.google.common.collect.ArrayListMultimap;
25  import com.google.common.collect.ListMultimap;
26  import com.google.common.collect.Lists;
27  import com.google.protobuf.ByteString;
28  import com.google.protobuf.CodedInputStream;
29  import com.google.protobuf.InvalidProtocolBufferException;
30  import com.google.protobuf.Message;
31  import com.google.protobuf.Parser;
32  import com.google.protobuf.RpcChannel;
33  import com.google.protobuf.RpcController;
34  import com.google.protobuf.Service;
35  import com.google.protobuf.ServiceException;
36  import com.google.protobuf.TextFormat;
37  
38  import java.io.ByteArrayOutputStream;
39  import java.io.IOException;
40  import java.io.InputStream;
41  import java.io.InterruptedIOException;
42  import java.lang.reflect.Constructor;
43  import java.lang.reflect.InvocationTargetException;
44  import java.lang.reflect.Method;
45  import java.lang.reflect.ParameterizedType;
46  import java.lang.reflect.Type;
47  import java.nio.ByteBuffer;
48  import java.security.PrivilegedExceptionAction;
49  import java.util.ArrayList;
50  import java.util.Collection;
51  import java.util.HashMap;
52  import java.util.List;
53  import java.util.Map;
54  import java.util.Map.Entry;
55  import java.util.NavigableSet;
56  import java.util.concurrent.TimeUnit;
57  
58  import org.apache.hadoop.conf.Configuration;
59  import org.apache.hadoop.fs.Path;
60  import org.apache.hadoop.hbase.Cell;
61  import org.apache.hadoop.hbase.CellScanner;
62  import org.apache.hadoop.hbase.CellUtil;
63  import org.apache.hadoop.hbase.DoNotRetryIOException;
64  import org.apache.hadoop.hbase.HBaseConfiguration;
65  import org.apache.hadoop.hbase.HBaseIOException;
66  import org.apache.hadoop.hbase.HConstants;
67  import org.apache.hadoop.hbase.HRegionInfo;
68  import org.apache.hadoop.hbase.HTableDescriptor;
69  import org.apache.hadoop.hbase.KeyValue;
70  import org.apache.hadoop.hbase.NamespaceDescriptor;
71  import org.apache.hadoop.hbase.ServerName;
72  import org.apache.hadoop.hbase.TableName;
73  import org.apache.hadoop.hbase.Tag;
74  import org.apache.hadoop.hbase.classification.InterfaceAudience;
75  import org.apache.hadoop.hbase.client.Append;
76  import org.apache.hadoop.hbase.client.ClientUtil;
77  import org.apache.hadoop.hbase.client.Consistency;
78  import org.apache.hadoop.hbase.client.Cursor;
79  import org.apache.hadoop.hbase.client.Delete;
80  import org.apache.hadoop.hbase.client.Durability;
81  import org.apache.hadoop.hbase.client.Get;
82  import org.apache.hadoop.hbase.client.Increment;
83  import org.apache.hadoop.hbase.client.Mutation;
84  import org.apache.hadoop.hbase.client.PackagePrivateFieldAccessor;
85  import org.apache.hadoop.hbase.client.Put;
86  import org.apache.hadoop.hbase.client.Result;
87  import org.apache.hadoop.hbase.client.Scan;
88  import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
89  import org.apache.hadoop.hbase.client.security.SecurityCapability;
90  import org.apache.hadoop.hbase.exceptions.DeserializationException;
91  import org.apache.hadoop.hbase.filter.ByteArrayComparable;
92  import org.apache.hadoop.hbase.filter.Filter;
93  import org.apache.hadoop.hbase.io.LimitInputStream;
94  import org.apache.hadoop.hbase.io.TimeRange;
95  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
96  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
97  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService;
98  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionRequest;
99  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionResponse;
100 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetOnlineRegionRequest;
101 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetOnlineRegionResponse;
102 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoRequest;
103 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoResponse;
104 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetServerInfoRequest;
105 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetServerInfoResponse;
106 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileRequest;
107 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileResponse;
108 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.MergeRegionsRequest;
109 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionRequest;
110 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.ServerInfo;
111 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.SplitRegionRequest;
112 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.WarmupRegionRequest;
113 import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos;
114 import org.apache.hadoop.hbase.protobuf.generated.CellProtos;
115 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
116 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.BulkLoadHFileRequest;
117 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.BulkLoadHFileResponse;
118 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ClientService;
119 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.Column;
120 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceCall;
121 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceRequest;
122 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceResponse;
123 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest;
124 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetResponse;
125 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
126 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.ColumnValue;
127 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.ColumnValue.QualifierValue;
128 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.DeleteType;
129 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType;
130 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
131 import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos;
132 import org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionLoad;
133 import org.apache.hadoop.hbase.protobuf.generated.ComparatorProtos;
134 import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
135 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
136 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameBytesPair;
137 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo;
138 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
139 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
140 import org.apache.hadoop.hbase.protobuf.generated.MapReduceProtos;
141 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos;
142 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.CreateTableRequest;
143 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsResponse;
144 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MasterService;
145 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos;
146 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerReportRequest;
147 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
148 import org.apache.hadoop.hbase.protobuf.generated.TableProtos;
149 import org.apache.hadoop.hbase.protobuf.generated.WALProtos;
150 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.BulkLoadDescriptor;
151 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.CompactionDescriptor;
152 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.FlushDescriptor;
153 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.FlushDescriptor.FlushAction;
154 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.RegionEventDescriptor;
155 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.RegionEventDescriptor.EventType;
156 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.StoreDescriptor;
157 import org.apache.hadoop.hbase.quotas.QuotaScope;
158 import org.apache.hadoop.hbase.quotas.QuotaType;
159 import org.apache.hadoop.hbase.quotas.ThrottleType;
160 import org.apache.hadoop.hbase.replication.ReplicationLoadSink;
161 import org.apache.hadoop.hbase.replication.ReplicationLoadSource;
162 import org.apache.hadoop.hbase.security.User;
163 import org.apache.hadoop.hbase.security.access.Permission;
164 import org.apache.hadoop.hbase.security.access.TablePermission;
165 import org.apache.hadoop.hbase.security.access.UserPermission;
166 import org.apache.hadoop.hbase.security.token.AuthenticationTokenIdentifier;
167 import org.apache.hadoop.hbase.security.visibility.Authorizations;
168 import org.apache.hadoop.hbase.security.visibility.CellVisibility;
169 import org.apache.hadoop.hbase.util.ByteStringer;
170 import org.apache.hadoop.hbase.util.Bytes;
171 import org.apache.hadoop.hbase.util.DynamicClassLoader;
172 import org.apache.hadoop.hbase.util.ExceptionUtil;
173 import org.apache.hadoop.hbase.util.Methods;
174 import org.apache.hadoop.hbase.util.Pair;
175 import org.apache.hadoop.hbase.util.VersionInfo;
176 import org.apache.hadoop.io.Text;
177 import org.apache.hadoop.ipc.RemoteException;
178 import org.apache.hadoop.security.token.Token;
179 
180 /**
181  * Protobufs utility.
182  */
183 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED",
184   justification="None. Address sometime.")
185 @InterfaceAudience.Private // TODO: some clients (Hive, etc) use this class
186 public final class ProtobufUtil {
187 
188   private ProtobufUtil() {
189   }
190 
191   /**
192    * Primitive type to class mapping.
193    */
194   private final static Map<String, Class<?>>
195     PRIMITIVES = new HashMap<String, Class<?>>();
196 
197 
198   /**
199    * Many results are simple: no cell, exists true or false. To save on object creations,
200    *  we reuse them across calls.
201    */
202   private final static Cell[] EMPTY_CELL_ARRAY = new Cell[]{};
203   private final static Result EMPTY_RESULT = Result.create(EMPTY_CELL_ARRAY);
204   final static Result EMPTY_RESULT_EXISTS_TRUE = Result.create(null, true);
205   final static Result EMPTY_RESULT_EXISTS_FALSE = Result.create(null, false);
206   private final static Result EMPTY_RESULT_STALE = Result.create(EMPTY_CELL_ARRAY, null, true);
207   private final static Result EMPTY_RESULT_EXISTS_TRUE_STALE
208     = Result.create((Cell[])null, true, true);
209   private final static Result EMPTY_RESULT_EXISTS_FALSE_STALE
210     = Result.create((Cell[])null, false, true);
211 
212   private final static ClientProtos.Result EMPTY_RESULT_PB;
213   private final static ClientProtos.Result EMPTY_RESULT_PB_EXISTS_TRUE;
214   private final static ClientProtos.Result EMPTY_RESULT_PB_EXISTS_FALSE;
215   private final static ClientProtos.Result EMPTY_RESULT_PB_STALE;
216   private final static ClientProtos.Result EMPTY_RESULT_PB_EXISTS_TRUE_STALE;
217   private final static ClientProtos.Result EMPTY_RESULT_PB_EXISTS_FALSE_STALE;
218 
219 
220   static {
221     ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder();
222 
223     builder.setExists(true);
224     builder.setAssociatedCellCount(0);
225     EMPTY_RESULT_PB_EXISTS_TRUE =  builder.build();
226 
227     builder.setStale(true);
228     EMPTY_RESULT_PB_EXISTS_TRUE_STALE = builder.build();
229     builder.clear();
230 
231     builder.setExists(false);
232     builder.setAssociatedCellCount(0);
233     EMPTY_RESULT_PB_EXISTS_FALSE =  builder.build();
234     builder.setStale(true);
235     EMPTY_RESULT_PB_EXISTS_FALSE_STALE = builder.build();
236 
237     builder.clear();
238     builder.setAssociatedCellCount(0);
239     EMPTY_RESULT_PB =  builder.build();
240     builder.setStale(true);
241     EMPTY_RESULT_PB_STALE = builder.build();
242   }
243 
244   /**
245    * Dynamic class loader to load filter/comparators
246    */
247   private final static ClassLoader CLASS_LOADER;
248 
249   static {
250     ClassLoader parent = ProtobufUtil.class.getClassLoader();
251     Configuration conf = HBaseConfiguration.create();
252     CLASS_LOADER = new DynamicClassLoader(conf, parent);
253 
254     PRIMITIVES.put(Boolean.TYPE.getName(), Boolean.TYPE);
255     PRIMITIVES.put(Byte.TYPE.getName(), Byte.TYPE);
256     PRIMITIVES.put(Character.TYPE.getName(), Character.TYPE);
257     PRIMITIVES.put(Short.TYPE.getName(), Short.TYPE);
258     PRIMITIVES.put(Integer.TYPE.getName(), Integer.TYPE);
259     PRIMITIVES.put(Long.TYPE.getName(), Long.TYPE);
260     PRIMITIVES.put(Float.TYPE.getName(), Float.TYPE);
261     PRIMITIVES.put(Double.TYPE.getName(), Double.TYPE);
262     PRIMITIVES.put(Void.TYPE.getName(), Void.TYPE);
263   }
264 
265   /**
266    * Magic we put ahead of a serialized protobuf message.
267    * For example, all znode content is protobuf messages with the below magic
268    * for preamble.
269    */
270   public static final byte [] PB_MAGIC = new byte [] {'P', 'B', 'U', 'F'};
271   private static final String PB_MAGIC_STR = Bytes.toString(PB_MAGIC);
272 
273   /**
274    * Prepend the passed bytes with four bytes of magic, {@link #PB_MAGIC}, to flag what
275    * follows as a protobuf in hbase.  Prepend these bytes to all content written to znodes, etc.
276    * @param bytes Bytes to decorate
277    * @return The passed <code>bytes</code> with magic prepended (Creates a new
278    * byte array that is <code>bytes.length</code> plus {@link #PB_MAGIC}.length.
279    */
280   public static byte [] prependPBMagic(final byte [] bytes) {
281     return Bytes.add(PB_MAGIC, bytes);
282   }
283 
284   /**
285    * @param bytes Bytes to check.
286    * @return True if passed <code>bytes</code> has {@link #PB_MAGIC} for a prefix.
287    */
288   public static boolean isPBMagicPrefix(final byte [] bytes) {
289     if (bytes == null) return false;
290     return isPBMagicPrefix(bytes, 0, bytes.length);
291   }
292 
293   /**
294    * @param bytes Bytes to check.
295    * @param offset offset to start at
296    * @param len length to use
297    * @return True if passed <code>bytes</code> has {@link #PB_MAGIC} for a prefix.
298    */
299   public static boolean isPBMagicPrefix(final byte [] bytes, int offset, int len) {
300     if (bytes == null || len < PB_MAGIC.length) return false;
301     return Bytes.compareTo(PB_MAGIC, 0, PB_MAGIC.length, bytes, offset, PB_MAGIC.length) == 0;
302   }
303 
304   /**
305    * @param bytes bytes to check
306    * @throws DeserializationException if we are missing the pb magic prefix
307    */
308   public static void expectPBMagicPrefix(final byte [] bytes) throws DeserializationException {
309     if (!isPBMagicPrefix(bytes)) {
310       throw new DeserializationException("Missing pb magic " + PB_MAGIC_STR + " prefix");
311     }
312   }
313 
314   /**
315    * @return Length of {@link #PB_MAGIC}
316    */
317   public static int lengthOfPBMagic() {
318     return PB_MAGIC.length;
319   }
320 
321   /**
322    * Return the IOException thrown by the remote server wrapped in
323    * ServiceException as cause.
324    *
325    * @param se ServiceException that wraps IO exception thrown by the server
326    * @return Exception wrapped in ServiceException or
327    *   a new IOException that wraps the unexpected ServiceException.
328    */
329   public static IOException getRemoteException(ServiceException se) {
330     return makeIOExceptionOfException(se);
331   }
332 
333   /**
334    * Return the Exception thrown by the remote server wrapped in
335    * ServiceException as cause. RemoteException are left untouched.
336    *
337    * @param se ServiceException that wraps IO exception thrown by the server
338    * @return Exception wrapped in ServiceException.
339    */
340   public static IOException getServiceException(ServiceException se) {
341     Throwable t = se.getCause();
342     if (ExceptionUtil.isInterrupt(t)) {
343       return ExceptionUtil.asInterrupt(t);
344     }
345     return t instanceof IOException ? (IOException) t : new HBaseIOException(t);
346   }
347 
348   /**
349    * Like {@link #getRemoteException(ServiceException)} but more generic, able to handle more than
350    * just {@link ServiceException}. Prefer this method to
351    * {@link #getRemoteException(ServiceException)} because trying to
352    * contain direct protobuf references.
353    * @param e
354    */
355   public static IOException handleRemoteException(Exception e) {
356     return makeIOExceptionOfException(e);
357   }
358 
359   private static IOException makeIOExceptionOfException(Exception e) {
360     Throwable t = e;
361     if (e instanceof ServiceException) {
362       t = e.getCause();
363     }
364     if (ExceptionUtil.isInterrupt(t)) {
365       return ExceptionUtil.asInterrupt(t);
366     }
367     if (t instanceof RemoteException) {
368       t = ((RemoteException) t).unwrapRemoteException();
369     }
370     return t instanceof IOException ? (IOException) t : new HBaseIOException(t);
371   }
372 
373   /**
374    * Convert a ServerName to a protocol buffer ServerName
375    *
376    * @param serverName the ServerName to convert
377    * @return the converted protocol buffer ServerName
378    * @see #toServerName(org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ServerName)
379    */
380   public static HBaseProtos.ServerName
381       toServerName(final ServerName serverName) {
382     if (serverName == null) return null;
383     HBaseProtos.ServerName.Builder builder =
384       HBaseProtos.ServerName.newBuilder();
385     builder.setHostName(serverName.getHostname());
386     if (serverName.getPort() >= 0) {
387       builder.setPort(serverName.getPort());
388     }
389     if (serverName.getStartcode() >= 0) {
390       builder.setStartCode(serverName.getStartcode());
391     }
392     return builder.build();
393   }
394 
395   /**
396    * Convert a protocol buffer ServerName to a ServerName
397    *
398    * @param proto the protocol buffer ServerName to convert
399    * @return the converted ServerName
400    */
401   public static ServerName toServerName(final HBaseProtos.ServerName proto) {
402     if (proto == null) return null;
403     String hostName = proto.getHostName();
404     long startCode = -1;
405     int port = -1;
406     if (proto.hasPort()) {
407       port = proto.getPort();
408     }
409     if (proto.hasStartCode()) {
410       startCode = proto.getStartCode();
411     }
412     return ServerName.valueOf(hostName, port, startCode);
413   }
414   /**
415    * Convert a list of protocol buffer ServerName to a list of ServerName
416    * @param proto protocol buffer ServerNameList
417    * @return a list of ServerName
418    */
419   public static List<ServerName> toServerNameList(
420       List<HBaseProtos.ServerName> proto) {
421     List<ServerName> servers = new ArrayList<ServerName>();
422     for (HBaseProtos.ServerName pbServer : proto) {
423       servers.add(toServerName(pbServer));
424     }
425     return servers;
426   }
427 
428 
429   /**
430    * Get HTableDescriptor[] from GetTableDescriptorsResponse protobuf
431    *
432    * @param proto the GetTableDescriptorsResponse
433    * @return HTableDescriptor[]
434    */
435   public static HTableDescriptor[] getHTableDescriptorArray(GetTableDescriptorsResponse proto) {
436     if (proto == null) return null;
437 
438     HTableDescriptor[] ret = new HTableDescriptor[proto.getTableSchemaCount()];
439     for (int i = 0; i < proto.getTableSchemaCount(); ++i) {
440       ret[i] = HTableDescriptor.convert(proto.getTableSchema(i));
441     }
442     return ret;
443   }
444 
445   /**
446    * get the split keys in form "byte [][]" from a CreateTableRequest proto
447    *
448    * @param proto the CreateTableRequest
449    * @return the split keys
450    */
451   public static byte [][] getSplitKeysArray(final CreateTableRequest proto) {
452     byte [][] splitKeys = new byte[proto.getSplitKeysCount()][];
453     for (int i = 0; i < proto.getSplitKeysCount(); ++i) {
454       splitKeys[i] = proto.getSplitKeys(i).toByteArray();
455     }
456     return splitKeys;
457   }
458 
459   /**
460    * Convert a protobuf Durability into a client Durability
461    */
462   public static Durability toDurability(
463       final ClientProtos.MutationProto.Durability proto) {
464     switch(proto) {
465     case USE_DEFAULT:
466       return Durability.USE_DEFAULT;
467     case SKIP_WAL:
468       return Durability.SKIP_WAL;
469     case ASYNC_WAL:
470       return Durability.ASYNC_WAL;
471     case SYNC_WAL:
472       return Durability.SYNC_WAL;
473     case FSYNC_WAL:
474       return Durability.FSYNC_WAL;
475     default:
476       return Durability.USE_DEFAULT;
477     }
478   }
479 
480   /**
481    * Convert a client Durability into a protbuf Durability
482    */
483   public static ClientProtos.MutationProto.Durability toDurability(
484       final Durability d) {
485     switch(d) {
486     case USE_DEFAULT:
487       return ClientProtos.MutationProto.Durability.USE_DEFAULT;
488     case SKIP_WAL:
489       return ClientProtos.MutationProto.Durability.SKIP_WAL;
490     case ASYNC_WAL:
491       return ClientProtos.MutationProto.Durability.ASYNC_WAL;
492     case SYNC_WAL:
493       return ClientProtos.MutationProto.Durability.SYNC_WAL;
494     case FSYNC_WAL:
495       return ClientProtos.MutationProto.Durability.FSYNC_WAL;
496     default:
497       return ClientProtos.MutationProto.Durability.USE_DEFAULT;
498     }
499   }
500 
501   /**
502    * Convert a protocol buffer Get to a client Get
503    *
504    * @param proto the protocol buffer Get to convert
505    * @return the converted client Get
506    * @throws IOException
507    */
508   public static Get toGet(
509       final ClientProtos.Get proto) throws IOException {
510     if (proto == null) return null;
511     byte[] row = zeroCopyGetBytes(proto.getRow());
512     Get get = new Get(row);
513     if (proto.hasCacheBlocks()) {
514       get.setCacheBlocks(proto.getCacheBlocks());
515     }
516     if (proto.hasMaxVersions()) {
517       get.setMaxVersions(proto.getMaxVersions());
518     }
519     if (proto.hasStoreLimit()) {
520       get.setMaxResultsPerColumnFamily(proto.getStoreLimit());
521     }
522     if (proto.hasStoreOffset()) {
523       get.setRowOffsetPerColumnFamily(proto.getStoreOffset());
524     }
525     if (proto.getCfTimeRangeCount() > 0) {
526       for (HBaseProtos.ColumnFamilyTimeRange cftr : proto.getCfTimeRangeList()) {
527         TimeRange timeRange = protoToTimeRange(cftr.getTimeRange());
528         get.setColumnFamilyTimeRange(cftr.getColumnFamily().toByteArray(),
529             timeRange.getMin(), timeRange.getMax());
530       }
531     }
532     if (proto.hasTimeRange()) {
533       TimeRange timeRange = protoToTimeRange(proto.getTimeRange());
534       get.setTimeRange(timeRange.getMin(), timeRange.getMax());
535     }
536     if (proto.hasFilter()) {
537       FilterProtos.Filter filter = proto.getFilter();
538       get.setFilter(ProtobufUtil.toFilter(filter));
539     }
540     for (NameBytesPair attribute: proto.getAttributeList()) {
541       get.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
542     }
543     if (proto.getColumnCount() > 0) {
544       for (Column column: proto.getColumnList()) {
545         byte[] family = column.getFamily().toByteArray();
546         if (column.getQualifierCount() > 0) {
547           for (ByteString qualifier: column.getQualifierList()) {
548             get.addColumn(family, qualifier.toByteArray());
549           }
550         } else {
551           get.addFamily(family);
552         }
553       }
554     }
555     if (proto.hasExistenceOnly() && proto.getExistenceOnly()){
556       get.setCheckExistenceOnly(true);
557     }
558     if (proto.hasClosestRowBefore() && proto.getClosestRowBefore()){
559       get.setClosestRowBefore(true);
560     }
561     if (proto.hasConsistency()) {
562       get.setConsistency(toConsistency(proto.getConsistency()));
563     }
564     if (proto.hasLoadColumnFamiliesOnDemand()) {
565       get.setLoadColumnFamiliesOnDemand(proto.getLoadColumnFamiliesOnDemand());
566     }
567     return get;
568   }
569 
570   public static Consistency toConsistency(ClientProtos.Consistency consistency) {
571     switch (consistency) {
572       case STRONG : return Consistency.STRONG;
573       case TIMELINE : return Consistency.TIMELINE;
574       default : return Consistency.STRONG;
575     }
576   }
577 
578   public static ClientProtos.Consistency toConsistency(Consistency consistency) {
579     switch (consistency) {
580       case STRONG : return ClientProtos.Consistency.STRONG;
581       case TIMELINE : return ClientProtos.Consistency.TIMELINE;
582       default : return ClientProtos.Consistency.STRONG;
583     }
584   }
585 
586   /**
587    * Convert a protocol buffer Mutate to a Put.
588    *
589    * @param proto The protocol buffer MutationProto to convert
590    * @return A client Put.
591    * @throws IOException
592    */
593   public static Put toPut(final MutationProto proto)
594   throws IOException {
595     return toPut(proto, null);
596   }
597 
598   /**
599    * Convert a protocol buffer Mutate to a Put.
600    *
601    * @param proto The protocol buffer MutationProto to convert
602    * @param cellScanner If non-null, the Cell data that goes with this proto.
603    * @return A client Put.
604    * @throws IOException
605    */
606   public static Put toPut(final MutationProto proto, final CellScanner cellScanner)
607   throws IOException {
608     // TODO: Server-side at least why do we convert back to the Client types?  Why not just pb it?
609     MutationType type = proto.getMutateType();
610     assert type == MutationType.PUT: type.name();
611     long timestamp = proto.hasTimestamp()? proto.getTimestamp(): HConstants.LATEST_TIMESTAMP;
612     Put put = proto.hasRow() ? new Put(zeroCopyGetBytes(proto.getRow()), timestamp) : null;
613     int cellCount = proto.hasAssociatedCellCount()? proto.getAssociatedCellCount(): 0;
614     if (cellCount > 0) {
615       // The proto has metadata only and the data is separate to be found in the cellScanner.
616       if (cellScanner == null) {
617         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: " +
618             toShortString(proto));
619       }
620       for (int i = 0; i < cellCount; i++) {
621         if (!cellScanner.advance()) {
622           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i +
623             " no cell returned: " + toShortString(proto));
624         }
625         Cell cell = cellScanner.current();
626         if (put == null) {
627           put = new Put(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), timestamp);
628         }
629         put.add(cell);
630       }
631     } else {
632       if (put == null) {
633         throw new IllegalArgumentException("row cannot be null");
634       }
635       // The proto has the metadata and the data itself
636       for (ColumnValue column: proto.getColumnValueList()) {
637         byte[] family = zeroCopyGetBytes(column.getFamily());
638         for (QualifierValue qv: column.getQualifierValueList()) {
639           if (!qv.hasValue()) {
640             throw new DoNotRetryIOException(
641                 "Missing required field: qualifier value");
642           }
643           ByteBuffer qualifier =
644               qv.hasQualifier() ? qv.getQualifier().asReadOnlyByteBuffer() : null;
645           ByteBuffer value =
646               qv.hasValue() ? qv.getValue().asReadOnlyByteBuffer() : null;
647           long ts = timestamp;
648           if (qv.hasTimestamp()) {
649             ts = qv.getTimestamp();
650           }
651           byte[] tags;
652           if (qv.hasTags()) {
653             tags = zeroCopyGetBytes(qv.getTags());
654             Object[] array = Tag.asList(tags, 0, (short)tags.length).toArray();
655             Tag[] tagArray = new Tag[array.length];
656             for(int i = 0; i< array.length; i++) {
657               tagArray[i] = (Tag)array[i];
658             }
659             if(qv.hasDeleteType()) {
660               byte[] qual = qv.hasQualifier() ? zeroCopyGetBytes(qv.getQualifier()) : null;
661               put.add(new KeyValue(zeroCopyGetBytes(proto.getRow()), family, qual, ts,
662                   fromDeleteType(qv.getDeleteType()), null, tags));
663             } else {
664               put.addImmutable(family, qualifier, ts, value, tagArray);
665             }
666           } else {
667             if(qv.hasDeleteType()) {
668               byte[] qual = qv.hasQualifier() ? zeroCopyGetBytes(qv.getQualifier()) : null;
669               put.add(new KeyValue(zeroCopyGetBytes(proto.getRow()), family, qual, ts,
670                   fromDeleteType(qv.getDeleteType())));
671             } else{
672               put.addImmutable(family, qualifier, ts, value);
673             }
674           }
675         }
676       }
677     }
678     put.setDurability(toDurability(proto.getDurability()));
679     for (NameBytesPair attribute: proto.getAttributeList()) {
680       put.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
681     }
682     return put;
683   }
684 
685   /**
686    * Convert a protocol buffer Mutate to a Delete
687    *
688    * @param proto the protocol buffer Mutate to convert
689    * @return the converted client Delete
690    * @throws IOException
691    */
692   public static Delete toDelete(final MutationProto proto)
693   throws IOException {
694     return toDelete(proto, null);
695   }
696 
697   /**
698    * Convert a protocol buffer Mutate to a Delete
699    *
700    * @param proto the protocol buffer Mutate to convert
701    * @param cellScanner if non-null, the data that goes with this delete.
702    * @return the converted client Delete
703    * @throws IOException
704    */
705   public static Delete toDelete(final MutationProto proto, final CellScanner cellScanner)
706   throws IOException {
707     MutationType type = proto.getMutateType();
708     assert type == MutationType.DELETE : type.name();
709     long timestamp = proto.hasTimestamp() ? proto.getTimestamp() : HConstants.LATEST_TIMESTAMP;
710     Delete delete = proto.hasRow() ? new Delete(zeroCopyGetBytes(proto.getRow()), timestamp) : null;
711     int cellCount = proto.hasAssociatedCellCount()? proto.getAssociatedCellCount(): 0;
712     if (cellCount > 0) {
713       // The proto has metadata only and the data is separate to be found in the cellScanner.
714       if (cellScanner == null) {
715         // TextFormat should be fine for a Delete since it carries no data, just coordinates.
716         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: " +
717           TextFormat.shortDebugString(proto));
718       }
719       for (int i = 0; i < cellCount; i++) {
720         if (!cellScanner.advance()) {
721           // TextFormat should be fine for a Delete since it carries no data, just coordinates.
722           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i +
723             " no cell returned: " + TextFormat.shortDebugString(proto));
724         }
725         Cell cell = cellScanner.current();
726         if (delete == null) {
727           delete =
728             new Delete(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), timestamp);
729         }
730         delete.addDeleteMarker(cell);
731       }
732     } else {
733       if (delete == null) {
734         throw new IllegalArgumentException("row cannot be null");
735       }
736       for (ColumnValue column: proto.getColumnValueList()) {
737         byte[] family = column.getFamily().toByteArray();
738         for (QualifierValue qv: column.getQualifierValueList()) {
739           DeleteType deleteType = qv.getDeleteType();
740           byte[] qualifier = null;
741           if (qv.hasQualifier()) {
742             qualifier = qv.getQualifier().toByteArray();
743           }
744           long ts = HConstants.LATEST_TIMESTAMP;
745           if (qv.hasTimestamp()) {
746             ts = qv.getTimestamp();
747           }
748           if (deleteType == DeleteType.DELETE_ONE_VERSION) {
749             delete.deleteColumn(family, qualifier, ts);
750           } else if (deleteType == DeleteType.DELETE_MULTIPLE_VERSIONS) {
751             delete.deleteColumns(family, qualifier, ts);
752           } else if (deleteType == DeleteType.DELETE_FAMILY_VERSION) {
753             delete.deleteFamilyVersion(family, ts);
754           } else {
755             delete.deleteFamily(family, ts);
756           }
757         }
758       }
759     }
760     delete.setDurability(toDurability(proto.getDurability()));
761     for (NameBytesPair attribute: proto.getAttributeList()) {
762       delete.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
763     }
764     return delete;
765   }
766 
767   /**
768    * Convert a protocol buffer Mutate to an Append
769    * @param cellScanner
770    * @param proto the protocol buffer Mutate to convert
771    * @return the converted client Append
772    * @throws IOException
773    */
774   public static Append toAppend(final MutationProto proto, final CellScanner cellScanner)
775   throws IOException {
776     MutationType type = proto.getMutateType();
777     assert type == MutationType.APPEND : type.name();
778     byte [] row = proto.hasRow()? zeroCopyGetBytes(proto.getRow()): null;
779     Append append = null;
780     int cellCount = proto.hasAssociatedCellCount()? proto.getAssociatedCellCount(): 0;
781     if (cellCount > 0) {
782       // The proto has metadata only and the data is separate to be found in the cellScanner.
783       if (cellScanner == null) {
784         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: " +
785           toShortString(proto));
786       }
787       for (int i = 0; i < cellCount; i++) {
788         if (!cellScanner.advance()) {
789           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i +
790             " no cell returned: " + toShortString(proto));
791         }
792         Cell cell = cellScanner.current();
793         if (append == null) {
794           append = new Append(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
795         }
796         append.add(cell);
797       }
798     } else {
799       append = new Append(row);
800       for (ColumnValue column: proto.getColumnValueList()) {
801         byte[] family = zeroCopyGetBytes(column.getFamily());
802         for (QualifierValue qv: column.getQualifierValueList()) {
803           byte[] qualifier = zeroCopyGetBytes(qv.getQualifier());
804           if (!qv.hasValue()) {
805             throw new DoNotRetryIOException(
806               "Missing required field: qualifier value");
807           }
808           byte[] value = zeroCopyGetBytes(qv.getValue());
809           byte[] tags = null;
810           if (qv.hasTags()) {
811             tags = zeroCopyGetBytes(qv.getTags());
812           }
813           append.add(CellUtil.createCell(row, family, qualifier, qv.getTimestamp(),
814               KeyValue.Type.Put, value, tags));
815         }
816       }
817     }
818     append.setDurability(toDurability(proto.getDurability()));
819     for (NameBytesPair attribute: proto.getAttributeList()) {
820       append.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
821     }
822     return append;
823   }
824 
825   /**
826    * Convert a MutateRequest to Mutation
827    *
828    * @param proto the protocol buffer Mutate to convert
829    * @return the converted Mutation
830    * @throws IOException
831    */
832   public static Mutation toMutation(final MutationProto proto) throws IOException {
833     MutationType type = proto.getMutateType();
834     if (type == MutationType.APPEND) {
835       return toAppend(proto, null);
836     }
837     if (type == MutationType.DELETE) {
838       return toDelete(proto, null);
839     }
840     if (type == MutationType.PUT) {
841       return toPut(proto, null);
842     }
843     throw new IOException("Unknown mutation type " + type);
844   }
845 
846   /**
847    * Convert a protocol buffer Mutate to an Increment
848    *
849    * @param proto the protocol buffer Mutate to convert
850    * @return the converted client Increment
851    * @throws IOException
852    */
853   public static Increment toIncrement(final MutationProto proto, final CellScanner cellScanner)
854   throws IOException {
855     MutationType type = proto.getMutateType();
856     assert type == MutationType.INCREMENT : type.name();
857     byte [] row = proto.hasRow()? zeroCopyGetBytes(proto.getRow()): null;
858     Increment increment = null;
859     int cellCount = proto.hasAssociatedCellCount()? proto.getAssociatedCellCount(): 0;
860     if (cellCount > 0) {
861       // The proto has metadata only and the data is separate to be found in the cellScanner.
862       if (cellScanner == null) {
863         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: " +
864           TextFormat.shortDebugString(proto));
865       }
866       for (int i = 0; i < cellCount; i++) {
867         if (!cellScanner.advance()) {
868           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i +
869             " no cell returned: " + TextFormat.shortDebugString(proto));
870         }
871         Cell cell = cellScanner.current();
872         if (increment == null) {
873           increment = new Increment(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
874         }
875         increment.add(cell);
876       }
877     } else {
878       increment = new Increment(row);
879       for (ColumnValue column: proto.getColumnValueList()) {
880         byte[] family = zeroCopyGetBytes(column.getFamily());
881         for (QualifierValue qv: column.getQualifierValueList()) {
882           byte[] qualifier = zeroCopyGetBytes(qv.getQualifier());
883           if (!qv.hasValue()) {
884             throw new DoNotRetryIOException("Missing required field: qualifier value");
885           }
886           byte[] value = zeroCopyGetBytes(qv.getValue());
887           byte[] tags = null;
888           if (qv.hasTags()) {
889             tags = zeroCopyGetBytes(qv.getTags());
890           }
891           increment.add(CellUtil.createCell(row, family, qualifier, qv.getTimestamp(),
892               KeyValue.Type.Put, value, tags));
893         }
894       }
895     }
896     if (proto.hasTimeRange()) {
897       TimeRange timeRange = protoToTimeRange(proto.getTimeRange());
898       increment.setTimeRange(timeRange.getMin(), timeRange.getMax());
899     }
900     increment.setDurability(toDurability(proto.getDurability()));
901     for (NameBytesPair attribute : proto.getAttributeList()) {
902       increment.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
903     }
904     return increment;
905   }
906 
907   /**
908    * Convert a protocol buffer Mutate to a Get.
909    * @param proto the protocol buffer Mutate to convert.
910    * @param cellScanner
911    * @return the converted client get.
912    * @throws IOException
913    */
914   public static Get toGet(final MutationProto proto, final CellScanner cellScanner)
915       throws IOException {
916     MutationType type = proto.getMutateType();
917     assert type == MutationType.INCREMENT || type == MutationType.APPEND : type.name();
918     byte[] row = proto.hasRow() ? zeroCopyGetBytes(proto.getRow()) : null;
919     Get get = null;
920     int cellCount = proto.hasAssociatedCellCount() ? proto.getAssociatedCellCount() : 0;
921     if (cellCount > 0) {
922       // The proto has metadata only and the data is separate to be found in the cellScanner.
923       if (cellScanner == null) {
924         throw new DoNotRetryIOException("Cell count of " + cellCount + " but no cellScanner: "
925             + TextFormat.shortDebugString(proto));
926       }
927       for (int i = 0; i < cellCount; i++) {
928         if (!cellScanner.advance()) {
929           throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i
930               + " no cell returned: " + TextFormat.shortDebugString(proto));
931         }
932         Cell cell = cellScanner.current();
933         if (get == null) {
934           get = new Get(Bytes.copy(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
935         }
936         get.addColumn(Bytes.copy(cell.getFamilyArray(), cell.getFamilyOffset(),
937           cell.getFamilyLength()), Bytes.copy(cell.getQualifierArray(), cell.getQualifierOffset(),
938           cell.getQualifierLength()));
939       }
940     } else {
941       get = new Get(row);
942       for (ColumnValue column : proto.getColumnValueList()) {
943         byte[] family = zeroCopyGetBytes(column.getFamily());
944         for (QualifierValue qv : column.getQualifierValueList()) {
945           byte[] qualifier = zeroCopyGetBytes(qv.getQualifier());
946           if (!qv.hasValue()) {
947             throw new DoNotRetryIOException("Missing required field: qualifier value");
948           }
949           get.addColumn(family, qualifier);
950         }
951       }
952     }
953     if (proto.hasTimeRange()) {
954       TimeRange timeRange = protoToTimeRange(proto.getTimeRange());
955       get.setTimeRange(timeRange.getMin(), timeRange.getMax());
956     }
957     for (NameBytesPair attribute : proto.getAttributeList()) {
958       get.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
959     }
960     return get;
961   }
962 
963   public static ClientProtos.Scan.ReadType toReadType(Scan.ReadType readType) {
964     switch (readType) {
965       case DEFAULT:
966         return ClientProtos.Scan.ReadType.DEFAULT;
967       case STREAM:
968         return ClientProtos.Scan.ReadType.STREAM;
969       case PREAD:
970         return ClientProtos.Scan.ReadType.PREAD;
971       default:
972         throw new IllegalArgumentException("Unknown ReadType: " + readType);
973     }
974   }
975 
976   public static Scan.ReadType toReadType(ClientProtos.Scan.ReadType readType) {
977     switch (readType) {
978       case DEFAULT:
979         return Scan.ReadType.DEFAULT;
980       case STREAM:
981         return Scan.ReadType.STREAM;
982       case PREAD:
983         return Scan.ReadType.PREAD;
984       default:
985         throw new IllegalArgumentException("Unknown ReadType: " + readType);
986     }
987   }
988 
989   /**
990    * Convert a client Scan to a protocol buffer Scan
991    *
992    * @param scan the client Scan to convert
993    * @return the converted protocol buffer Scan
994    * @throws IOException
995    */
996   public static ClientProtos.Scan toScan(
997       final Scan scan) throws IOException {
998     ClientProtos.Scan.Builder scanBuilder =
999       ClientProtos.Scan.newBuilder();
1000     scanBuilder.setCacheBlocks(scan.getCacheBlocks());
1001     if (scan.getBatch() > 0) {
1002       scanBuilder.setBatchSize(scan.getBatch());
1003     }
1004     if (scan.getMaxResultSize() > 0) {
1005       scanBuilder.setMaxResultSize(scan.getMaxResultSize());
1006     }
1007     if (scan.isSmall()) {
1008       scanBuilder.setSmall(scan.isSmall());
1009     }
1010     if (scan.getAllowPartialResults()) {
1011       scanBuilder.setAllowPartialResults(scan.getAllowPartialResults());
1012     }
1013     Boolean loadColumnFamiliesOnDemand = scan.getLoadColumnFamiliesOnDemandValue();
1014     if (loadColumnFamiliesOnDemand != null) {
1015       scanBuilder.setLoadColumnFamiliesOnDemand(loadColumnFamiliesOnDemand);
1016     }
1017     scanBuilder.setMaxVersions(scan.getMaxVersions());
1018     for (Entry<byte[], TimeRange> cftr : scan.getColumnFamilyTimeRange().entrySet()) {
1019       HBaseProtos.ColumnFamilyTimeRange.Builder b = HBaseProtos.ColumnFamilyTimeRange.newBuilder();
1020       b.setColumnFamily(ByteString.copyFrom(cftr.getKey()));
1021       b.setTimeRange(timeRangeToProto(cftr.getValue()));
1022       scanBuilder.addCfTimeRange(b);
1023     }
1024     TimeRange timeRange = scan.getTimeRange();
1025     if (!timeRange.isAllTime()) {
1026       HBaseProtos.TimeRange.Builder timeRangeBuilder =
1027         HBaseProtos.TimeRange.newBuilder();
1028       timeRangeBuilder.setFrom(timeRange.getMin());
1029       timeRangeBuilder.setTo(timeRange.getMax());
1030       scanBuilder.setTimeRange(timeRangeBuilder.build());
1031     }
1032     Map<String, byte[]> attributes = scan.getAttributesMap();
1033     if (!attributes.isEmpty()) {
1034       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
1035       for (Map.Entry<String, byte[]> attribute: attributes.entrySet()) {
1036         attributeBuilder.setName(attribute.getKey());
1037         attributeBuilder.setValue(ByteStringer.wrap(attribute.getValue()));
1038         scanBuilder.addAttribute(attributeBuilder.build());
1039       }
1040     }
1041     byte[] startRow = scan.getStartRow();
1042     if (startRow != null && startRow.length > 0) {
1043       scanBuilder.setStartRow(ByteStringer.wrap(startRow));
1044     }
1045     byte[] stopRow = scan.getStopRow();
1046     if (stopRow != null && stopRow.length > 0) {
1047       scanBuilder.setStopRow(ByteStringer.wrap(stopRow));
1048     }
1049     if (scan.hasFilter()) {
1050       scanBuilder.setFilter(ProtobufUtil.toFilter(scan.getFilter()));
1051     }
1052     if (scan.hasFamilies()) {
1053       Column.Builder columnBuilder = Column.newBuilder();
1054       for (Map.Entry<byte[],NavigableSet<byte []>>
1055           family: scan.getFamilyMap().entrySet()) {
1056         columnBuilder.setFamily(ByteStringer.wrap(family.getKey()));
1057         NavigableSet<byte []> qualifiers = family.getValue();
1058         columnBuilder.clearQualifier();
1059         if (qualifiers != null && qualifiers.size() > 0) {
1060           for (byte [] qualifier: qualifiers) {
1061             columnBuilder.addQualifier(ByteStringer.wrap(qualifier));
1062           }
1063         }
1064         scanBuilder.addColumn(columnBuilder.build());
1065       }
1066     }
1067     if (scan.getMaxResultsPerColumnFamily() >= 0) {
1068       scanBuilder.setStoreLimit(scan.getMaxResultsPerColumnFamily());
1069     }
1070     if (scan.getRowOffsetPerColumnFamily() > 0) {
1071       scanBuilder.setStoreOffset(scan.getRowOffsetPerColumnFamily());
1072     }
1073     if (scan.isReversed()) {
1074       scanBuilder.setReversed(scan.isReversed());
1075     }
1076     if (scan.getConsistency() == Consistency.TIMELINE) {
1077       scanBuilder.setConsistency(toConsistency(scan.getConsistency()));
1078     }
1079     if (scan.getCaching() > 0) {
1080       scanBuilder.setCaching(scan.getCaching());
1081     }
1082     long mvccReadPoint = PackagePrivateFieldAccessor.getMvccReadPoint(scan);
1083     if (mvccReadPoint > 0) {
1084       scanBuilder.setMvccReadPoint(mvccReadPoint);
1085     }
1086     if (!scan.includeStartRow()) {
1087       scanBuilder.setIncludeStartRow(false);
1088     }
1089     if (scan.includeStopRow()) {
1090       scanBuilder.setIncludeStopRow(true);
1091     }
1092     if (scan.getReadType() != Scan.ReadType.DEFAULT) {
1093       scanBuilder.setReadType(toReadType(scan.getReadType()));
1094     }
1095     if (scan.isNeedCursorResult()) {
1096       scanBuilder.setNeedCursorResult(true);
1097     }
1098     return scanBuilder.build();
1099   }
1100 
1101   /**
1102    * Convert a protocol buffer Scan to a client Scan
1103    *
1104    * @param proto the protocol buffer Scan to convert
1105    * @return the converted client Scan
1106    * @throws IOException
1107    */
1108   public static Scan toScan(
1109       final ClientProtos.Scan proto) throws IOException {
1110     byte[] startRow = HConstants.EMPTY_START_ROW;
1111     byte[] stopRow = HConstants.EMPTY_END_ROW;
1112     boolean includeStartRow = true;
1113     boolean includeStopRow = false;
1114     if (proto.hasStartRow()) {
1115       startRow = proto.getStartRow().toByteArray();
1116     }
1117     if (proto.hasStopRow()) {
1118       stopRow = proto.getStopRow().toByteArray();
1119     }
1120     if (proto.hasIncludeStartRow()) {
1121       includeStartRow = proto.getIncludeStartRow();
1122     }
1123     if (proto.hasIncludeStopRow()) {
1124       includeStopRow = proto.getIncludeStopRow();
1125     } else {
1126       // old client without this flag, we should consider start=end as a get.
1127       if (ClientUtil.areScanStartRowAndStopRowEqual(startRow, stopRow)) {
1128         includeStopRow = true;
1129       }
1130     }
1131     Scan scan =
1132         new Scan().withStartRow(startRow, includeStartRow).withStopRow(stopRow, includeStopRow);
1133     if (proto.hasCacheBlocks()) {
1134       scan.setCacheBlocks(proto.getCacheBlocks());
1135     }
1136     if (proto.hasMaxVersions()) {
1137       scan.setMaxVersions(proto.getMaxVersions());
1138     }
1139     if (proto.hasStoreLimit()) {
1140       scan.setMaxResultsPerColumnFamily(proto.getStoreLimit());
1141     }
1142     if (proto.hasStoreOffset()) {
1143       scan.setRowOffsetPerColumnFamily(proto.getStoreOffset());
1144     }
1145     if (proto.hasLoadColumnFamiliesOnDemand()) {
1146       scan.setLoadColumnFamiliesOnDemand(proto.getLoadColumnFamiliesOnDemand());
1147     }
1148     if (proto.getCfTimeRangeCount() > 0) {
1149       for (HBaseProtos.ColumnFamilyTimeRange cftr : proto.getCfTimeRangeList()) {
1150         TimeRange timeRange = protoToTimeRange(cftr.getTimeRange());
1151         scan.setColumnFamilyTimeRange(cftr.getColumnFamily().toByteArray(),
1152             timeRange.getMin(), timeRange.getMax());
1153       }
1154     }
1155     if (proto.hasTimeRange()) {
1156       TimeRange timeRange = protoToTimeRange(proto.getTimeRange());
1157       scan.setTimeRange(timeRange.getMin(), timeRange.getMax());
1158     }
1159     if (proto.hasFilter()) {
1160       FilterProtos.Filter filter = proto.getFilter();
1161       scan.setFilter(ProtobufUtil.toFilter(filter));
1162     }
1163     if (proto.hasBatchSize()) {
1164       scan.setBatch(proto.getBatchSize());
1165     }
1166     if (proto.hasMaxResultSize()) {
1167       scan.setMaxResultSize(proto.getMaxResultSize());
1168     }
1169     if (proto.hasSmall()) {
1170       scan.setSmall(proto.getSmall());
1171     }
1172     if (proto.hasAllowPartialResults()) {
1173       scan.setAllowPartialResults(proto.getAllowPartialResults());
1174     }
1175     for (NameBytesPair attribute: proto.getAttributeList()) {
1176       scan.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
1177     }
1178     if (proto.getColumnCount() > 0) {
1179       for (Column column: proto.getColumnList()) {
1180         byte[] family = column.getFamily().toByteArray();
1181         if (column.getQualifierCount() > 0) {
1182           for (ByteString qualifier: column.getQualifierList()) {
1183             scan.addColumn(family, qualifier.toByteArray());
1184           }
1185         } else {
1186           scan.addFamily(family);
1187         }
1188       }
1189     }
1190     if (proto.hasReversed()) {
1191       scan.setReversed(proto.getReversed());
1192     }
1193     if (proto.hasConsistency()) {
1194       scan.setConsistency(toConsistency(proto.getConsistency()));
1195     }
1196     if (proto.hasCaching()) {
1197       scan.setCaching(proto.getCaching());
1198     }
1199     if (proto.hasMvccReadPoint()) {
1200       PackagePrivateFieldAccessor.setMvccReadPoint(scan, proto.getMvccReadPoint());
1201     }
1202     if (scan.isSmall()) {
1203       scan.setReadType(Scan.ReadType.PREAD);
1204     } else if (proto.hasReadType()) {
1205       scan.setReadType(toReadType(proto.getReadType()));
1206     }
1207     if (proto.getNeedCursorResult()) {
1208       scan.setNeedCursorResult(true);
1209     }
1210     return scan;
1211   }
1212 
1213   public static ClientProtos.Cursor toCursor(Cursor cursor) {
1214     ClientProtos.Cursor.Builder builder = ClientProtos.Cursor.newBuilder();
1215     ClientProtos.Cursor.newBuilder().setRow(ByteString.copyFrom(cursor.getRow()));
1216     return builder.build();
1217   }
1218 
1219   public static ClientProtos.Cursor toCursor(Cell cell) {
1220     return ClientProtos.Cursor.newBuilder()
1221         .setRow(ByteString.copyFrom(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()))
1222         .build();
1223   }
1224 
1225   public static Cursor toCursor(ClientProtos.Cursor cursor) {
1226     return ClientUtil.createCursor(cursor.getRow().toByteArray());
1227   }
1228 
1229   /**
1230    * Create a protocol buffer Get based on a client Get.
1231    *
1232    * @param get the client Get
1233    * @return a protocol buffer Get
1234    * @throws IOException
1235    */
1236   public static ClientProtos.Get toGet(
1237       final Get get) throws IOException {
1238     ClientProtos.Get.Builder builder =
1239       ClientProtos.Get.newBuilder();
1240     builder.setRow(ByteStringer.wrap(get.getRow()));
1241     builder.setCacheBlocks(get.getCacheBlocks());
1242     builder.setMaxVersions(get.getMaxVersions());
1243     if (get.getFilter() != null) {
1244       builder.setFilter(ProtobufUtil.toFilter(get.getFilter()));
1245     }
1246     for (Entry<byte[], TimeRange> cftr : get.getColumnFamilyTimeRange().entrySet()) {
1247       HBaseProtos.ColumnFamilyTimeRange.Builder b = HBaseProtos.ColumnFamilyTimeRange.newBuilder();
1248       b.setColumnFamily(ByteString.copyFrom(cftr.getKey()));
1249       b.setTimeRange(timeRangeToProto(cftr.getValue()));
1250       builder.addCfTimeRange(b);
1251     }
1252     TimeRange timeRange = get.getTimeRange();
1253     if (!timeRange.isAllTime()) {
1254       HBaseProtos.TimeRange.Builder timeRangeBuilder =
1255         HBaseProtos.TimeRange.newBuilder();
1256       timeRangeBuilder.setFrom(timeRange.getMin());
1257       timeRangeBuilder.setTo(timeRange.getMax());
1258       builder.setTimeRange(timeRangeBuilder.build());
1259     }
1260     Map<String, byte[]> attributes = get.getAttributesMap();
1261     if (!attributes.isEmpty()) {
1262       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
1263       for (Map.Entry<String, byte[]> attribute: attributes.entrySet()) {
1264         attributeBuilder.setName(attribute.getKey());
1265         attributeBuilder.setValue(ByteStringer.wrap(attribute.getValue()));
1266         builder.addAttribute(attributeBuilder.build());
1267       }
1268     }
1269     if (get.hasFamilies()) {
1270       Column.Builder columnBuilder = Column.newBuilder();
1271       Map<byte[], NavigableSet<byte[]>> families = get.getFamilyMap();
1272       for (Map.Entry<byte[], NavigableSet<byte[]>> family: families.entrySet()) {
1273         NavigableSet<byte[]> qualifiers = family.getValue();
1274         columnBuilder.setFamily(ByteStringer.wrap(family.getKey()));
1275         columnBuilder.clearQualifier();
1276         if (qualifiers != null && qualifiers.size() > 0) {
1277           for (byte[] qualifier: qualifiers) {
1278             columnBuilder.addQualifier(ByteStringer.wrap(qualifier));
1279           }
1280         }
1281         builder.addColumn(columnBuilder.build());
1282       }
1283     }
1284     if (get.getMaxResultsPerColumnFamily() >= 0) {
1285       builder.setStoreLimit(get.getMaxResultsPerColumnFamily());
1286     }
1287     if (get.getRowOffsetPerColumnFamily() > 0) {
1288       builder.setStoreOffset(get.getRowOffsetPerColumnFamily());
1289     }
1290     if (get.isCheckExistenceOnly()){
1291       builder.setExistenceOnly(true);
1292     }
1293     if (get.isClosestRowBefore()){
1294       builder.setClosestRowBefore(true);
1295     }
1296     if (get.getConsistency() != null && get.getConsistency() != Consistency.STRONG) {
1297       builder.setConsistency(toConsistency(get.getConsistency()));
1298     }
1299     Boolean loadColumnFamiliesOnDemand = get.getLoadColumnFamiliesOnDemandValue();
1300     if (loadColumnFamiliesOnDemand != null) {
1301       builder.setLoadColumnFamiliesOnDemand(loadColumnFamiliesOnDemand);
1302     }
1303 
1304     return builder.build();
1305   }
1306 
1307   static void setTimeRange(final MutationProto.Builder builder, final TimeRange timeRange) {
1308     if (!timeRange.isAllTime()) {
1309       HBaseProtos.TimeRange.Builder timeRangeBuilder =
1310         HBaseProtos.TimeRange.newBuilder();
1311       timeRangeBuilder.setFrom(timeRange.getMin());
1312       timeRangeBuilder.setTo(timeRange.getMax());
1313       builder.setTimeRange(timeRangeBuilder.build());
1314     }
1315   }
1316 
1317   /**
1318    * Convert a client Increment to a protobuf Mutate.
1319    *
1320    * @param increment
1321    * @return the converted mutate
1322    */
1323   public static MutationProto toMutation(
1324     final Increment increment, final MutationProto.Builder builder, long nonce) {
1325     builder.setRow(ByteStringer.wrap(increment.getRow()));
1326     builder.setMutateType(MutationType.INCREMENT);
1327     builder.setDurability(toDurability(increment.getDurability()));
1328     if (nonce != HConstants.NO_NONCE) {
1329       builder.setNonce(nonce);
1330     }
1331     TimeRange timeRange = increment.getTimeRange();
1332     setTimeRange(builder, timeRange);
1333     ColumnValue.Builder columnBuilder = ColumnValue.newBuilder();
1334     QualifierValue.Builder valueBuilder = QualifierValue.newBuilder();
1335     for (Map.Entry<byte[], List<Cell>> family: increment.getFamilyCellMap().entrySet()) {
1336       columnBuilder.setFamily(ByteStringer.wrap(family.getKey()));
1337       columnBuilder.clearQualifierValue();
1338       List<Cell> values = family.getValue();
1339       if (values != null && values.size() > 0) {
1340         for (Cell cell: values) {
1341           valueBuilder.clear();
1342           valueBuilder.setQualifier(ByteStringer.wrap(
1343               cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()));
1344           valueBuilder.setValue(ByteStringer.wrap(
1345               cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
1346           if (cell.getTagsLength() > 0) {
1347             valueBuilder.setTags(ByteStringer.wrap(cell.getTagsArray(),
1348                 cell.getTagsOffset(), cell.getTagsLength()));
1349           }
1350           columnBuilder.addQualifierValue(valueBuilder.build());
1351         }
1352       }
1353       builder.addColumnValue(columnBuilder.build());
1354     }
1355     Map<String, byte[]> attributes = increment.getAttributesMap();
1356     if (!attributes.isEmpty()) {
1357       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
1358       for (Map.Entry<String, byte[]> attribute : attributes.entrySet()) {
1359         attributeBuilder.setName(attribute.getKey());
1360         attributeBuilder.setValue(ByteStringer.wrap(attribute.getValue()));
1361         builder.addAttribute(attributeBuilder.build());
1362       }
1363     }
1364     return builder.build();
1365   }
1366 
1367   public static MutationProto toMutation(final MutationType type, final Mutation mutation)
1368     throws IOException {
1369     return toMutation(type, mutation, HConstants.NO_NONCE);
1370   }
1371 
1372   /**
1373    * Create a protocol buffer Mutate based on a client Mutation
1374    *
1375    * @param type
1376    * @param mutation
1377    * @return a protobuf'd Mutation
1378    * @throws IOException
1379    */
1380   public static MutationProto toMutation(final MutationType type, final Mutation mutation,
1381     final long nonce) throws IOException {
1382     return toMutation(type, mutation, MutationProto.newBuilder(), nonce);
1383   }
1384 
1385   public static MutationProto toMutation(final MutationType type, final Mutation mutation,
1386       MutationProto.Builder builder) throws IOException {
1387     return toMutation(type, mutation, builder, HConstants.NO_NONCE);
1388   }
1389 
1390   public static MutationProto toMutation(final MutationType type, final Mutation mutation,
1391       MutationProto.Builder builder, long nonce)
1392   throws IOException {
1393     builder = getMutationBuilderAndSetCommonFields(type, mutation, builder);
1394     if (nonce != HConstants.NO_NONCE) {
1395       builder.setNonce(nonce);
1396     }
1397     ColumnValue.Builder columnBuilder = ColumnValue.newBuilder();
1398     QualifierValue.Builder valueBuilder = QualifierValue.newBuilder();
1399     for (Map.Entry<byte[],List<Cell>> family: mutation.getFamilyCellMap().entrySet()) {
1400       columnBuilder.clear();
1401       columnBuilder.setFamily(ByteStringer.wrap(family.getKey()));
1402       for (Cell cell: family.getValue()) {
1403         valueBuilder.clear();
1404         valueBuilder.setQualifier(ByteStringer.wrap(
1405             cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()));
1406         valueBuilder.setValue(ByteStringer.wrap(
1407             cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
1408         valueBuilder.setTimestamp(cell.getTimestamp());
1409         if (type == MutationType.DELETE || (type == MutationType.PUT && CellUtil.isDelete(cell))) {
1410           KeyValue.Type keyValueType = KeyValue.Type.codeToType(cell.getTypeByte());
1411           valueBuilder.setDeleteType(toDeleteType(keyValueType));
1412         }
1413         columnBuilder.addQualifierValue(valueBuilder.build());
1414       }
1415       builder.addColumnValue(columnBuilder.build());
1416     }
1417     return builder.build();
1418   }
1419 
1420   /**
1421    * Create a protocol buffer MutationProto based on a client Mutation. Does NOT include data.
1422    * Understanding is that the Cell will be transported other than via protobuf.
1423    * @param type
1424    * @param mutation
1425    * @param builder
1426    * @return a protobuf'd Mutation
1427    * @throws IOException
1428    */
1429   public static MutationProto toMutationNoData(final MutationType type, final Mutation mutation,
1430       final MutationProto.Builder builder)  throws IOException {
1431     return toMutationNoData(type, mutation, builder, HConstants.NO_NONCE);
1432   }
1433 
1434   /**
1435    * Create a protocol buffer MutationProto based on a client Mutation.  Does NOT include data.
1436    * Understanding is that the Cell will be transported other than via protobuf.
1437    * @param type
1438    * @param mutation
1439    * @return a protobuf'd Mutation
1440    * @throws IOException
1441    */
1442   public static MutationProto toMutationNoData(final MutationType type, final Mutation mutation)
1443   throws IOException {
1444     MutationProto.Builder builder =  MutationProto.newBuilder();
1445     return toMutationNoData(type, mutation, builder);
1446   }
1447 
1448   public static MutationProto toMutationNoData(final MutationType type, final Mutation mutation,
1449       final MutationProto.Builder builder, long nonce) throws IOException {
1450     getMutationBuilderAndSetCommonFields(type, mutation, builder);
1451     builder.setAssociatedCellCount(mutation.size());
1452     if (mutation instanceof Increment) {
1453       setTimeRange(builder, ((Increment)mutation).getTimeRange());
1454     }
1455     if (nonce != HConstants.NO_NONCE) {
1456       builder.setNonce(nonce);
1457     }
1458     return builder.build();
1459   }
1460 
1461   /**
1462    * Code shared by {@link #toMutation(MutationType, Mutation)} and
1463    * {@link #toMutationNoData(MutationType, Mutation)}
1464    * @param type
1465    * @param mutation
1466    * @return A partly-filled out protobuf'd Mutation.
1467    */
1468   private static MutationProto.Builder getMutationBuilderAndSetCommonFields(final MutationType type,
1469       final Mutation mutation, MutationProto.Builder builder) {
1470     builder.setRow(ByteStringer.wrap(mutation.getRow()));
1471     builder.setMutateType(type);
1472     builder.setDurability(toDurability(mutation.getDurability()));
1473     builder.setTimestamp(mutation.getTimeStamp());
1474     Map<String, byte[]> attributes = mutation.getAttributesMap();
1475     if (!attributes.isEmpty()) {
1476       NameBytesPair.Builder attributeBuilder = NameBytesPair.newBuilder();
1477       for (Map.Entry<String, byte[]> attribute: attributes.entrySet()) {
1478         attributeBuilder.setName(attribute.getKey());
1479         attributeBuilder.setValue(ByteStringer.wrap(attribute.getValue()));
1480         builder.addAttribute(attributeBuilder.build());
1481       }
1482     }
1483     return builder;
1484   }
1485 
1486   /**
1487    * Convert a client Result to a protocol buffer Result
1488    *
1489    * @param result the client Result to convert
1490    * @return the converted protocol buffer Result
1491    */
1492   public static ClientProtos.Result toResult(final Result result) {
1493     if (result.getExists() != null) {
1494       return toResult(result.getExists(), result.isStale());
1495     }
1496 
1497     Cell[] cells = result.rawCells();
1498     if (cells == null || cells.length == 0) {
1499       return result.isStale() ? EMPTY_RESULT_PB_STALE : EMPTY_RESULT_PB;
1500     }
1501 
1502     ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder();
1503     for (Cell c : cells) {
1504       builder.addCell(toCell(c));
1505     }
1506 
1507     builder.setStale(result.isStale());
1508     builder.setPartial(result.mayHaveMoreCellsInRow());
1509 
1510     return builder.build();
1511   }
1512 
1513   /**
1514    * Convert a client Result to a protocol buffer Result
1515    *
1516    * @param existence the client existence to send
1517    * @return the converted protocol buffer Result
1518    */
1519   public static ClientProtos.Result toResult(final boolean existence, boolean stale) {
1520     if (stale){
1521       return existence ? EMPTY_RESULT_PB_EXISTS_TRUE_STALE : EMPTY_RESULT_PB_EXISTS_FALSE_STALE;
1522     } else {
1523       return existence ? EMPTY_RESULT_PB_EXISTS_TRUE : EMPTY_RESULT_PB_EXISTS_FALSE;
1524     }
1525   }
1526 
1527   /**
1528    * Convert a client Result to a protocol buffer Result.
1529    * The pb Result does not include the Cell data.  That is for transport otherwise.
1530    *
1531    * @param result the client Result to convert
1532    * @return the converted protocol buffer Result
1533    */
1534   public static ClientProtos.Result toResultNoData(final Result result) {
1535     if (result.getExists() != null) return toResult(result.getExists(), result.isStale());
1536     int size = result.size();
1537     if (size == 0) return result.isStale() ? EMPTY_RESULT_PB_STALE : EMPTY_RESULT_PB;
1538     ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder();
1539     builder.setAssociatedCellCount(size);
1540     builder.setStale(result.isStale());
1541     return builder.build();
1542   }
1543 
1544   /**
1545    * Convert a protocol buffer Result to a client Result
1546    *
1547    * @param proto the protocol buffer Result to convert
1548    * @return the converted client Result
1549    */
1550   public static Result toResult(final ClientProtos.Result proto) {
1551     if (proto.hasExists()) {
1552       if (proto.getStale()) {
1553         return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE_STALE :EMPTY_RESULT_EXISTS_FALSE_STALE;
1554       }
1555       return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE : EMPTY_RESULT_EXISTS_FALSE;
1556     }
1557 
1558     List<CellProtos.Cell> values = proto.getCellList();
1559     if (values.isEmpty()){
1560       return proto.getStale() ? EMPTY_RESULT_STALE : EMPTY_RESULT;
1561     }
1562 
1563     List<Cell> cells = new ArrayList<Cell>(values.size());
1564     for (CellProtos.Cell c : values) {
1565       cells.add(toCell(c));
1566     }
1567     return Result.create(cells, null, proto.getStale(), proto.getPartial());
1568   }
1569 
1570   /**
1571    * Convert a protocol buffer Result to a client Result
1572    *
1573    * @param proto the protocol buffer Result to convert
1574    * @param scanner Optional cell scanner.
1575    * @return the converted client Result
1576    * @throws IOException
1577    */
1578   public static Result toResult(final ClientProtos.Result proto, final CellScanner scanner)
1579   throws IOException {
1580     List<CellProtos.Cell> values = proto.getCellList();
1581 
1582     if (proto.hasExists()) {
1583       if ((values != null && !values.isEmpty()) ||
1584           (proto.hasAssociatedCellCount() && proto.getAssociatedCellCount() > 0)) {
1585         throw new IllegalArgumentException("bad proto: exists with cells is no allowed " + proto);
1586       }
1587       if (proto.getStale()) {
1588         return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE_STALE :EMPTY_RESULT_EXISTS_FALSE_STALE;
1589       }
1590       return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE : EMPTY_RESULT_EXISTS_FALSE;
1591     }
1592 
1593     // TODO: Unit test that has some Cells in scanner and some in the proto.
1594     List<Cell> cells = null;
1595     if (proto.hasAssociatedCellCount()) {
1596       int count = proto.getAssociatedCellCount();
1597       cells = new ArrayList<Cell>(count + values.size());
1598       for (int i = 0; i < count; i++) {
1599         if (!scanner.advance()) throw new IOException("Failed get " + i + " of " + count);
1600         cells.add(scanner.current());
1601       }
1602     }
1603 
1604     if (!values.isEmpty()){
1605       if (cells == null) cells = new ArrayList<Cell>(values.size());
1606       for (CellProtos.Cell c: values) {
1607         cells.add(toCell(c));
1608       }
1609     }
1610 
1611     return (cells == null || cells.isEmpty())
1612         ? (proto.getStale() ? EMPTY_RESULT_STALE : EMPTY_RESULT)
1613         : Result.create(cells, null, proto.getStale());
1614   }
1615 
1616 
1617   /**
1618    * Convert a ByteArrayComparable to a protocol buffer Comparator
1619    *
1620    * @param comparator the ByteArrayComparable to convert
1621    * @return the converted protocol buffer Comparator
1622    */
1623   public static ComparatorProtos.Comparator toComparator(ByteArrayComparable comparator) {
1624     ComparatorProtos.Comparator.Builder builder = ComparatorProtos.Comparator.newBuilder();
1625     builder.setName(comparator.getClass().getName());
1626     builder.setSerializedComparator(ByteStringer.wrap(comparator.toByteArray()));
1627     return builder.build();
1628   }
1629 
1630   /**
1631    * Convert a protocol buffer Comparator to a ByteArrayComparable
1632    *
1633    * @param proto the protocol buffer Comparator to convert
1634    * @return the converted ByteArrayComparable
1635    */
1636   @SuppressWarnings("unchecked")
1637   public static ByteArrayComparable toComparator(ComparatorProtos.Comparator proto)
1638   throws IOException {
1639     String type = proto.getName();
1640     String funcName = "parseFrom";
1641     byte [] value = proto.getSerializedComparator().toByteArray();
1642     try {
1643       Class<? extends ByteArrayComparable> c =
1644         (Class<? extends ByteArrayComparable>)Class.forName(type, true, CLASS_LOADER);
1645       Method parseFrom = c.getMethod(funcName, byte[].class);
1646       if (parseFrom == null) {
1647         throw new IOException("Unable to locate function: " + funcName + " in type: " + type);
1648       }
1649       return (ByteArrayComparable)parseFrom.invoke(null, value);
1650     } catch (Exception e) {
1651       throw new IOException(e);
1652     }
1653   }
1654 
1655   /**
1656    * Convert a protocol buffer Filter to a client Filter
1657    *
1658    * @param proto the protocol buffer Filter to convert
1659    * @return the converted Filter
1660    */
1661   @SuppressWarnings("unchecked")
1662   public static Filter toFilter(FilterProtos.Filter proto) throws IOException {
1663     String type = proto.getName();
1664     final byte [] value = proto.getSerializedFilter().toByteArray();
1665     String funcName = "parseFrom";
1666     try {
1667       Class<? extends Filter> c =
1668         (Class<? extends Filter>)Class.forName(type, true, CLASS_LOADER);
1669       Method parseFrom = c.getMethod(funcName, byte[].class);
1670       if (parseFrom == null) {
1671         throw new IOException("Unable to locate function: " + funcName + " in type: " + type);
1672       }
1673       return (Filter)parseFrom.invoke(c, value);
1674     } catch (Exception e) {
1675       // Either we couldn't instantiate the method object, or "parseFrom" failed.
1676       // In either case, let's not retry.
1677       throw new DoNotRetryIOException(e);
1678     }
1679   }
1680 
1681   /**
1682    * Convert a client Filter to a protocol buffer Filter
1683    *
1684    * @param filter the Filter to convert
1685    * @return the converted protocol buffer Filter
1686    */
1687   public static FilterProtos.Filter toFilter(Filter filter) throws IOException {
1688     FilterProtos.Filter.Builder builder = FilterProtos.Filter.newBuilder();
1689     builder.setName(filter.getClass().getName());
1690     builder.setSerializedFilter(ByteStringer.wrap(filter.toByteArray()));
1691     return builder.build();
1692   }
1693 
1694   /**
1695    * Convert a delete KeyValue type to protocol buffer DeleteType.
1696    *
1697    * @param type
1698    * @return protocol buffer DeleteType
1699    * @throws IOException
1700    */
1701   public static DeleteType toDeleteType(
1702       KeyValue.Type type) throws IOException {
1703     switch (type) {
1704     case Delete:
1705       return DeleteType.DELETE_ONE_VERSION;
1706     case DeleteColumn:
1707       return DeleteType.DELETE_MULTIPLE_VERSIONS;
1708     case DeleteFamily:
1709       return DeleteType.DELETE_FAMILY;
1710     case DeleteFamilyVersion:
1711       return DeleteType.DELETE_FAMILY_VERSION;
1712     default:
1713         throw new IOException("Unknown delete type: " + type);
1714     }
1715   }
1716 
1717   /**
1718    * Convert a protocol buffer DeleteType to delete KeyValue type.
1719    *
1720    * @param type The DeleteType
1721    * @return The type.
1722    * @throws IOException
1723    */
1724   public static KeyValue.Type fromDeleteType(
1725       DeleteType type) throws IOException {
1726     switch (type) {
1727     case DELETE_ONE_VERSION:
1728       return KeyValue.Type.Delete;
1729     case DELETE_MULTIPLE_VERSIONS:
1730       return KeyValue.Type.DeleteColumn;
1731     case DELETE_FAMILY:
1732       return KeyValue.Type.DeleteFamily;
1733     case DELETE_FAMILY_VERSION:
1734       return KeyValue.Type.DeleteFamilyVersion;
1735     default:
1736       throw new IOException("Unknown delete type: " + type);
1737     }
1738   }
1739 
1740   /**
1741    * Convert a stringified protocol buffer exception Parameter to a Java Exception
1742    *
1743    * @param parameter the protocol buffer Parameter to convert
1744    * @return the converted Exception
1745    * @throws IOException if failed to deserialize the parameter
1746    */
1747   @SuppressWarnings("unchecked")
1748   public static Throwable toException(final NameBytesPair parameter) throws IOException {
1749     if (parameter == null || !parameter.hasValue()) return null;
1750     String desc = parameter.getValue().toStringUtf8();
1751     String type = parameter.getName();
1752     try {
1753       Class<? extends Throwable> c =
1754         (Class<? extends Throwable>)Class.forName(type, true, CLASS_LOADER);
1755       Constructor<? extends Throwable> cn = null;
1756       try {
1757         cn = c.getDeclaredConstructor(String.class);
1758         return cn.newInstance(desc);
1759       } catch (NoSuchMethodException e) {
1760         // Could be a raw RemoteException. See HBASE-8987.
1761         cn = c.getDeclaredConstructor(String.class, String.class);
1762         return cn.newInstance(type, desc);
1763       }
1764     } catch (Exception e) {
1765       throw new IOException(e);
1766     }
1767   }
1768 
1769 // Start helpers for Client
1770 
1771   /**
1772    * A helper to get a row of the closet one before using client protocol.
1773    *
1774    * @param client
1775    * @param regionName
1776    * @param row
1777    * @param family
1778    * @return the row or the closestRowBefore if it doesn't exist
1779    * @throws IOException
1780    * @deprecated since 0.99 - use reversed scanner instead.
1781    */
1782   @Deprecated
1783   public static Result getRowOrBefore(final ClientService.BlockingInterface client,
1784       final byte[] regionName, final byte[] row,
1785       final byte[] family) throws IOException {
1786     GetRequest request =
1787       RequestConverter.buildGetRowOrBeforeRequest(
1788         regionName, row, family);
1789     try {
1790       GetResponse response = client.get(null, request);
1791       if (!response.hasResult()) return null;
1792       // We pass 'null' RpcController. So Result will be pure RB.
1793       return toResult(response.getResult());
1794     } catch (ServiceException se) {
1795       throw getRemoteException(se);
1796     }
1797   }
1798 
1799   /**
1800    * A helper to bulk load a list of HFiles using client protocol.
1801    *
1802    * @param client
1803    * @param familyPaths
1804    * @param regionName
1805    * @param assignSeqNum
1806    * @return true if all are loaded
1807    * @throws IOException
1808    */
1809   public static boolean bulkLoadHFile(final ClientService.BlockingInterface client,
1810       final List<Pair<byte[], String>> familyPaths,
1811       final byte[] regionName, boolean assignSeqNum) throws IOException {
1812     BulkLoadHFileRequest request =
1813       RequestConverter.buildBulkLoadHFileRequest(familyPaths, regionName, assignSeqNum);
1814     try {
1815       BulkLoadHFileResponse response =
1816         client.bulkLoadHFile(null, request);
1817       return response.getLoaded();
1818     } catch (ServiceException se) {
1819       throw getRemoteException(se);
1820     }
1821   }
1822 
1823   public static CoprocessorServiceResponse execService(final RpcController controller,
1824       final ClientService.BlockingInterface client, final CoprocessorServiceCall call,
1825       final byte[] regionName) throws IOException {
1826     CoprocessorServiceRequest request = CoprocessorServiceRequest.newBuilder()
1827         .setCall(call).setRegion(
1828             RequestConverter.buildRegionSpecifier(REGION_NAME, regionName)).build();
1829     try {
1830       CoprocessorServiceResponse response =
1831           client.execService(controller, request);
1832       return response;
1833     } catch (ServiceException se) {
1834       throw getRemoteException(se);
1835     }
1836   }
1837 
1838   public static CoprocessorServiceResponse execService(final RpcController controller,
1839     final MasterService.BlockingInterface client, final CoprocessorServiceCall call)
1840   throws IOException {
1841     CoprocessorServiceRequest request = CoprocessorServiceRequest.newBuilder()
1842         .setCall(call).setRegion(
1843             RequestConverter.buildRegionSpecifier(REGION_NAME, HConstants.EMPTY_BYTE_ARRAY)).build();
1844     try {
1845       CoprocessorServiceResponse response =
1846           client.execMasterService(controller, request);
1847       return response;
1848     } catch (ServiceException se) {
1849       throw getRemoteException(se);
1850     }
1851   }
1852 
1853   /**
1854    * Make a region server endpoint call
1855    * @param client
1856    * @param call
1857    * @return CoprocessorServiceResponse
1858    * @throws IOException
1859    */
1860   public static CoprocessorServiceResponse execRegionServerService(
1861       final RpcController controller, final ClientService.BlockingInterface client,
1862       final CoprocessorServiceCall call)
1863       throws IOException {
1864     CoprocessorServiceRequest request =
1865         CoprocessorServiceRequest
1866             .newBuilder()
1867             .setCall(call)
1868             .setRegion(
1869               RequestConverter.buildRegionSpecifier(REGION_NAME, HConstants.EMPTY_BYTE_ARRAY))
1870             .build();
1871     try {
1872       CoprocessorServiceResponse response = client.execRegionServerService(controller, request);
1873       return response;
1874     } catch (ServiceException se) {
1875       throw getRemoteException(se);
1876     }
1877   }
1878 
1879   @SuppressWarnings("unchecked")
1880   public static <T extends Service> T newServiceStub(Class<T> service, RpcChannel channel)
1881       throws Exception {
1882     return (T)Methods.call(service, null, "newStub",
1883         new Class[]{ RpcChannel.class }, new Object[]{ channel });
1884   }
1885 
1886 // End helpers for Client
1887 // Start helpers for Admin
1888 
1889   /**
1890    * A helper to retrieve region info given a region name
1891    * using admin protocol.
1892    *
1893    * @param admin
1894    * @param regionName
1895    * @return the retrieved region info
1896    * @throws IOException
1897    */
1898   public static HRegionInfo getRegionInfo(final RpcController controller,
1899       final AdminService.BlockingInterface admin, final byte[] regionName) throws IOException {
1900     try {
1901       GetRegionInfoRequest request =
1902         RequestConverter.buildGetRegionInfoRequest(regionName);
1903       GetRegionInfoResponse response =
1904         admin.getRegionInfo(controller, request);
1905       return HRegionInfo.convert(response.getRegionInfo());
1906     } catch (ServiceException se) {
1907       throw getRemoteException(se);
1908     }
1909   }
1910 
1911   /**
1912    * A helper to close a region given a region name
1913    * using admin protocol.
1914    *
1915    * @param admin
1916    * @param regionName
1917    * @param transitionInZK
1918    * @throws IOException
1919    */
1920   public static void closeRegion(final RpcController controller,
1921       final AdminService.BlockingInterface admin, final ServerName server, final byte[] regionName,
1922       final boolean transitionInZK) throws IOException {
1923     CloseRegionRequest closeRegionRequest =
1924       RequestConverter.buildCloseRegionRequest(server, regionName, transitionInZK);
1925     try {
1926       admin.closeRegion(controller, closeRegionRequest);
1927     } catch (ServiceException se) {
1928       throw getRemoteException(se);
1929     }
1930   }
1931 
1932   /**
1933    * A helper to close a region given a region name
1934    * using admin protocol.
1935    *
1936    * @param admin
1937    * @param regionName
1938    * @param versionOfClosingNode
1939    * @return true if the region is closed
1940    * @throws IOException
1941    */
1942   public static boolean closeRegion(final RpcController controller,
1943       final AdminService.BlockingInterface admin,
1944       final ServerName server,
1945       final byte[] regionName,
1946       final int versionOfClosingNode, final ServerName destinationServer,
1947       final boolean transitionInZK) throws IOException {
1948     CloseRegionRequest closeRegionRequest =
1949       RequestConverter.buildCloseRegionRequest(server,
1950         regionName, versionOfClosingNode, destinationServer, transitionInZK);
1951     try {
1952       CloseRegionResponse response = admin.closeRegion(controller, closeRegionRequest);
1953       return ResponseConverter.isClosed(response);
1954     } catch (ServiceException se) {
1955       throw getRemoteException(se);
1956     }
1957   }
1958 
1959   /**
1960    * A helper to warmup a region given a region name
1961    * using admin protocol
1962    *
1963    * @param admin
1964    * @param regionInfo
1965    *
1966    */
1967   public static void warmupRegion(final RpcController controller,
1968       final AdminService.BlockingInterface admin, final HRegionInfo regionInfo) throws IOException {
1969 
1970     try {
1971       WarmupRegionRequest warmupRegionRequest =
1972            RequestConverter.buildWarmupRegionRequest(regionInfo);
1973 
1974       admin.warmupRegion(controller, warmupRegionRequest);
1975     } catch (ServiceException e) {
1976       throw getRemoteException(e);
1977     }
1978   }
1979 
1980   /**
1981    * A helper to open a region using admin protocol.
1982    * @param admin
1983    * @param region
1984    * @throws IOException
1985    */
1986   public static void openRegion(final RpcController controller,
1987       final AdminService.BlockingInterface admin, ServerName server, final HRegionInfo region)
1988           throws IOException {
1989     OpenRegionRequest request =
1990       RequestConverter.buildOpenRegionRequest(server, region, -1, null, null);
1991     try {
1992       admin.openRegion(controller, request);
1993     } catch (ServiceException se) {
1994       throw ProtobufUtil.getRemoteException(se);
1995     }
1996   }
1997 
1998   /**
1999    * A helper to get the all the online regions on a region
2000    * server using admin protocol.
2001    *
2002    * @param admin
2003    * @return a list of online region info
2004    * @throws IOException
2005    */
2006   public static List<HRegionInfo> getOnlineRegions(final AdminService.BlockingInterface admin)
2007       throws IOException {
2008     return getOnlineRegions(null, admin);
2009   }
2010 
2011   /**
2012    * A helper to get the all the online regions on a region
2013    * server using admin protocol.
2014    * @return a list of online region info
2015    */
2016   public static List<HRegionInfo> getOnlineRegions(final RpcController controller,
2017       final AdminService.BlockingInterface admin)
2018   throws IOException {
2019     GetOnlineRegionRequest request = RequestConverter.buildGetOnlineRegionRequest();
2020     GetOnlineRegionResponse response = null;
2021     try {
2022       response = admin.getOnlineRegion(controller, request);
2023     } catch (ServiceException se) {
2024       throw getRemoteException(se);
2025     }
2026     return getRegionInfos(response);
2027   }
2028 
2029   /**
2030    * Get the list of region info from a GetOnlineRegionResponse
2031    *
2032    * @param proto the GetOnlineRegionResponse
2033    * @return the list of region info or null if <code>proto</code> is null
2034    */
2035   static List<HRegionInfo> getRegionInfos(final GetOnlineRegionResponse proto) {
2036     if (proto == null) return null;
2037     List<HRegionInfo> regionInfos = new ArrayList<HRegionInfo>();
2038     for (RegionInfo regionInfo: proto.getRegionInfoList()) {
2039       regionInfos.add(HRegionInfo.convert(regionInfo));
2040     }
2041     return regionInfos;
2042   }
2043 
2044   /**
2045    * A helper to get the info of a region server using admin protocol.
2046    * @return the server name
2047    */
2048   public static ServerInfo getServerInfo(final RpcController controller,
2049       final AdminService.BlockingInterface admin)
2050   throws IOException {
2051     GetServerInfoRequest request = RequestConverter.buildGetServerInfoRequest();
2052     try {
2053       GetServerInfoResponse response = admin.getServerInfo(controller, request);
2054       return response.getServerInfo();
2055     } catch (ServiceException se) {
2056       throw getRemoteException(se);
2057     }
2058   }
2059 
2060   /**
2061    * A helper to get the list of files of a column family
2062    * on a given region using admin protocol.
2063    *
2064    * @return the list of store files
2065    */
2066   public static List<String> getStoreFiles(final AdminService.BlockingInterface admin,
2067       final byte[] regionName, final byte[] family)
2068   throws IOException {
2069     return getStoreFiles(null, admin, regionName, family);
2070   }
2071 
2072   /**
2073    * A helper to get the list of files of a column family
2074    * on a given region using admin protocol.
2075    *
2076    * @return the list of store files
2077    */
2078   public static List<String> getStoreFiles(final RpcController controller,
2079       final AdminService.BlockingInterface admin, final byte[] regionName, final byte[] family)
2080   throws IOException {
2081     GetStoreFileRequest request =
2082       RequestConverter.buildGetStoreFileRequest(regionName, family);
2083     try {
2084       GetStoreFileResponse response = admin.getStoreFile(controller, request);
2085       return response.getStoreFileList();
2086     } catch (ServiceException se) {
2087       throw ProtobufUtil.getRemoteException(se);
2088     }
2089   }
2090 
2091   /**
2092    * A helper to split a region using admin protocol.
2093    *
2094    * @param admin
2095    * @param hri
2096    * @param splitPoint
2097    * @throws IOException
2098    */
2099   public static void split(final RpcController controller,
2100       final AdminService.BlockingInterface admin, final HRegionInfo hri, byte[] splitPoint)
2101           throws IOException {
2102     SplitRegionRequest request =
2103       RequestConverter.buildSplitRegionRequest(hri.getRegionName(), splitPoint);
2104     try {
2105       admin.splitRegion(controller, request);
2106     } catch (ServiceException se) {
2107       throw ProtobufUtil.getRemoteException(se);
2108     }
2109   }
2110 
2111   /**
2112    * A helper to merge regions using admin protocol. Send request to
2113    * regionserver.
2114    * @param admin
2115    * @param region_a
2116    * @param region_b
2117    * @param forcible true if do a compulsory merge, otherwise we will only merge
2118    *          two adjacent regions
2119    * @param user effective user
2120    * @throws IOException
2121    */
2122   public static void mergeRegions(final RpcController controller,
2123       final AdminService.BlockingInterface admin,
2124       final HRegionInfo region_a, final HRegionInfo region_b,
2125       final boolean forcible, final User user) throws IOException {
2126     final MergeRegionsRequest request = RequestConverter.buildMergeRegionsRequest(
2127         region_a.getRegionName(), region_b.getRegionName(),forcible);
2128     if (user != null) {
2129       try {
2130         user.getUGI().doAs(new PrivilegedExceptionAction<Void>() {
2131           @Override
2132           public Void run() throws Exception {
2133             try {
2134               admin.mergeRegions(controller, request);
2135             } catch (ServiceException se) {
2136               throw ProtobufUtil.getRemoteException(se);
2137             }
2138             return null;
2139           }
2140         });
2141       } catch (InterruptedException ie) {
2142         InterruptedIOException iioe = new InterruptedIOException();
2143         iioe.initCause(ie);
2144         throw iioe;
2145       }
2146     } else {
2147       try {
2148         admin.mergeRegions(controller, request);
2149       } catch (ServiceException se) {
2150         throw ProtobufUtil.getRemoteException(se);
2151       }
2152     }
2153   }
2154 
2155 // End helpers for Admin
2156 
2157   /*
2158    * Get the total (read + write) requests from a RegionLoad pb
2159    * @param rl - RegionLoad pb
2160    * @return total (read + write) requests
2161    */
2162   public static long getTotalRequestsCount(RegionLoad rl) {
2163     if (rl == null) {
2164       return 0;
2165     }
2166 
2167     return rl.getReadRequestsCount() + rl.getWriteRequestsCount();
2168   }
2169 
2170 
2171   /**
2172    * @param m Message to get delimited pb serialization of (with pb magic prefix)
2173    */
2174   public static byte [] toDelimitedByteArray(final Message m) throws IOException {
2175     // Allocate arbitrary big size so we avoid resizing.
2176     ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
2177     baos.write(PB_MAGIC);
2178     m.writeDelimitedTo(baos);
2179     return baos.toByteArray();
2180   }
2181 
2182   /**
2183    * Converts a Permission proto to a client Permission object.
2184    *
2185    * @param proto the protobuf Permission
2186    * @return the converted Permission
2187    */
2188   public static Permission toPermission(AccessControlProtos.Permission proto) {
2189     if (proto.getType() != AccessControlProtos.Permission.Type.Global) {
2190       return toTablePermission(proto);
2191     } else {
2192       List<Permission.Action> actions = toPermissionActions(proto.getGlobalPermission().getActionList());
2193       return new Permission(actions.toArray(new Permission.Action[actions.size()]));
2194     }
2195   }
2196 
2197   /**
2198    * Converts a Permission proto to a client TablePermission object.
2199    *
2200    * @param proto the protobuf Permission
2201    * @return the converted TablePermission
2202    */
2203   public static TablePermission toTablePermission(AccessControlProtos.Permission proto) {
2204     if(proto.getType() == AccessControlProtos.Permission.Type.Global) {
2205       AccessControlProtos.GlobalPermission perm = proto.getGlobalPermission();
2206       List<Permission.Action> actions = toPermissionActions(perm.getActionList());
2207 
2208       return new TablePermission(null, null, null,
2209           actions.toArray(new Permission.Action[actions.size()]));
2210     }
2211     if(proto.getType() == AccessControlProtos.Permission.Type.Namespace) {
2212       AccessControlProtos.NamespacePermission perm = proto.getNamespacePermission();
2213       List<Permission.Action> actions = toPermissionActions(perm.getActionList());
2214 
2215       if(!proto.hasNamespacePermission()) {
2216         throw new IllegalStateException("Namespace must not be empty in NamespacePermission");
2217       }
2218       String namespace = perm.getNamespaceName().toStringUtf8();
2219       return new TablePermission(namespace, actions.toArray(new Permission.Action[actions.size()]));
2220     }
2221     if(proto.getType() == AccessControlProtos.Permission.Type.Table) {
2222       AccessControlProtos.TablePermission perm = proto.getTablePermission();
2223       List<Permission.Action> actions = toPermissionActions(perm.getActionList());
2224 
2225       byte[] qualifier = null;
2226       byte[] family = null;
2227       TableName table = null;
2228 
2229       if (!perm.hasTableName()) {
2230         throw new IllegalStateException("TableName cannot be empty");
2231       }
2232       table = ProtobufUtil.toTableName(perm.getTableName());
2233 
2234       if (perm.hasFamily()) family = perm.getFamily().toByteArray();
2235       if (perm.hasQualifier()) qualifier = perm.getQualifier().toByteArray();
2236 
2237       return new TablePermission(table, family, qualifier,
2238           actions.toArray(new Permission.Action[actions.size()]));
2239     }
2240     throw new IllegalStateException("Unrecognize Perm Type: "+proto.getType());
2241   }
2242 
2243   /**
2244    * Convert a client Permission to a Permission proto
2245    *
2246    * @param perm the client Permission
2247    * @return the protobuf Permission
2248    */
2249   public static AccessControlProtos.Permission toPermission(Permission perm) {
2250     AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
2251     if (perm instanceof TablePermission) {
2252       TablePermission tablePerm = (TablePermission)perm;
2253       if(tablePerm.hasNamespace()) {
2254         ret.setType(AccessControlProtos.Permission.Type.Namespace);
2255 
2256         AccessControlProtos.NamespacePermission.Builder builder =
2257             AccessControlProtos.NamespacePermission.newBuilder();
2258         builder.setNamespaceName(ByteString.copyFromUtf8(tablePerm.getNamespace()));
2259         Permission.Action actions[] = perm.getActions();
2260         if (actions != null) {
2261           for (Permission.Action a : actions) {
2262             builder.addAction(toPermissionAction(a));
2263           }
2264         }
2265         ret.setNamespacePermission(builder);
2266         return ret.build();
2267       } else if (tablePerm.hasTable()) {
2268         ret.setType(AccessControlProtos.Permission.Type.Table);
2269 
2270         AccessControlProtos.TablePermission.Builder builder =
2271             AccessControlProtos.TablePermission.newBuilder();
2272         builder.setTableName(ProtobufUtil.toProtoTableName(tablePerm.getTableName()));
2273         if (tablePerm.hasFamily()) {
2274           builder.setFamily(ByteStringer.wrap(tablePerm.getFamily()));
2275         }
2276         if (tablePerm.hasQualifier()) {
2277           builder.setQualifier(ByteStringer.wrap(tablePerm.getQualifier()));
2278         }
2279         Permission.Action actions[] = perm.getActions();
2280         if (actions != null) {
2281           for (Permission.Action a : actions) {
2282             builder.addAction(toPermissionAction(a));
2283           }
2284         }
2285         ret.setTablePermission(builder);
2286         return ret.build();
2287       }
2288     }
2289 
2290     ret.setType(AccessControlProtos.Permission.Type.Global);
2291 
2292     AccessControlProtos.GlobalPermission.Builder builder =
2293         AccessControlProtos.GlobalPermission.newBuilder();
2294     Permission.Action actions[] = perm.getActions();
2295     if (actions != null) {
2296       for (Permission.Action a: actions) {
2297         builder.addAction(toPermissionAction(a));
2298       }
2299     }
2300     ret.setGlobalPermission(builder);
2301     return ret.build();
2302   }
2303 
2304   /**
2305    * Converts a list of Permission.Action proto to a list of client Permission.Action objects.
2306    *
2307    * @param protoActions the list of protobuf Actions
2308    * @return the converted list of Actions
2309    */
2310   public static List<Permission.Action> toPermissionActions(
2311       List<AccessControlProtos.Permission.Action> protoActions) {
2312     List<Permission.Action> actions = new ArrayList<Permission.Action>(protoActions.size());
2313     for (AccessControlProtos.Permission.Action a : protoActions) {
2314       actions.add(toPermissionAction(a));
2315     }
2316     return actions;
2317   }
2318 
2319   /**
2320    * Converts a Permission.Action proto to a client Permission.Action object.
2321    *
2322    * @param action the protobuf Action
2323    * @return the converted Action
2324    */
2325   public static Permission.Action toPermissionAction(
2326       AccessControlProtos.Permission.Action action) {
2327     switch (action) {
2328       case READ:
2329         return Permission.Action.READ;
2330       case WRITE:
2331         return Permission.Action.WRITE;
2332       case EXEC:
2333         return Permission.Action.EXEC;
2334       case CREATE:
2335         return Permission.Action.CREATE;
2336       case ADMIN:
2337         return Permission.Action.ADMIN;
2338     }
2339     throw new IllegalArgumentException("Unknown action value "+action.name());
2340   }
2341 
2342   /**
2343    * Convert a client Permission.Action to a Permission.Action proto
2344    *
2345    * @param action the client Action
2346    * @return the protobuf Action
2347    */
2348   public static AccessControlProtos.Permission.Action toPermissionAction(
2349       Permission.Action action) {
2350     switch (action) {
2351       case READ:
2352         return AccessControlProtos.Permission.Action.READ;
2353       case WRITE:
2354         return AccessControlProtos.Permission.Action.WRITE;
2355       case EXEC:
2356         return AccessControlProtos.Permission.Action.EXEC;
2357       case CREATE:
2358         return AccessControlProtos.Permission.Action.CREATE;
2359       case ADMIN:
2360         return AccessControlProtos.Permission.Action.ADMIN;
2361     }
2362     throw new IllegalArgumentException("Unknown action value "+action.name());
2363   }
2364 
2365   /**
2366    * Convert a client user permission to a user permission proto
2367    *
2368    * @param perm the client UserPermission
2369    * @return the protobuf UserPermission
2370    */
2371   public static AccessControlProtos.UserPermission toUserPermission(UserPermission perm) {
2372     return AccessControlProtos.UserPermission.newBuilder()
2373         .setUser(ByteStringer.wrap(perm.getUser()))
2374         .setPermission(toPermission(perm))
2375         .build();
2376   }
2377 
2378   /**
2379    * Converts a user permission proto to a client user permission object.
2380    *
2381    * @param proto the protobuf UserPermission
2382    * @return the converted UserPermission
2383    */
2384   public static UserPermission toUserPermission(AccessControlProtos.UserPermission proto) {
2385     return new UserPermission(proto.getUser().toByteArray(),
2386         toTablePermission(proto.getPermission()));
2387   }
2388 
2389   /**
2390    * Convert a ListMultimap&lt;String, TablePermission&gt; where key is username
2391    * to a protobuf UserPermission
2392    *
2393    * @param perm the list of user and table permissions
2394    * @return the protobuf UserTablePermissions
2395    */
2396   public static AccessControlProtos.UsersAndPermissions toUserTablePermissions(
2397       ListMultimap<String, TablePermission> perm) {
2398     AccessControlProtos.UsersAndPermissions.Builder builder =
2399                   AccessControlProtos.UsersAndPermissions.newBuilder();
2400     for (Map.Entry<String, Collection<TablePermission>> entry : perm.asMap().entrySet()) {
2401       AccessControlProtos.UsersAndPermissions.UserPermissions.Builder userPermBuilder =
2402                   AccessControlProtos.UsersAndPermissions.UserPermissions.newBuilder();
2403       userPermBuilder.setUser(ByteString.copyFromUtf8(entry.getKey()));
2404       for (TablePermission tablePerm: entry.getValue()) {
2405         userPermBuilder.addPermissions(toPermission(tablePerm));
2406       }
2407       builder.addUserPermissions(userPermBuilder.build());
2408     }
2409     return builder.build();
2410   }
2411 
2412   /**
2413    * A utility used to grant a user global permissions.
2414    * <p>
2415    * It's also called by the shell, in case you want to find references.
2416    *
2417    * @param protocol the AccessControlService protocol proxy
2418    * @param userShortName the short name of the user to grant permissions
2419    * @param actions the permissions to be granted
2420    * @throws ServiceException
2421    */
2422   public static void grant(RpcController controller,
2423       AccessControlService.BlockingInterface protocol, String userShortName,
2424       boolean mergeExistingPermissions, Permission.Action... actions) throws ServiceException {
2425     List<AccessControlProtos.Permission.Action> permActions =
2426         Lists.newArrayListWithCapacity(actions.length);
2427     for (Permission.Action a : actions) {
2428       permActions.add(ProtobufUtil.toPermissionAction(a));
2429     }
2430     AccessControlProtos.GrantRequest request =
2431         RequestConverter.buildGrantRequest(userShortName, mergeExistingPermissions,
2432           permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
2433     protocol.grant(controller, request);
2434   }
2435 
2436   /**
2437    * A utility used to grant a user table permissions. The permissions will
2438    * be for a table table/column family/qualifier.
2439    * <p>
2440    * It's also called by the shell, in case you want to find references.
2441    *
2442    * @param protocol the AccessControlService protocol proxy
2443    * @param userShortName the short name of the user to grant permissions
2444    * @param tableName optional table name
2445    * @param f optional column family
2446    * @param q optional qualifier
2447    * @param actions the permissions to be granted
2448    * @throws ServiceException
2449    */
2450   public static void grant(RpcController controller,
2451       AccessControlService.BlockingInterface protocol, String userShortName, TableName tableName,
2452       byte[] f, byte[] q, boolean mergeExistingPermissions, Permission.Action... actions)
2453       throws ServiceException {
2454     List<AccessControlProtos.Permission.Action> permActions =
2455         Lists.newArrayListWithCapacity(actions.length);
2456     for (Permission.Action a : actions) {
2457       permActions.add(ProtobufUtil.toPermissionAction(a));
2458     }
2459     AccessControlProtos.GrantRequest request =
2460         RequestConverter.buildGrantRequest(userShortName, tableName, f, q, mergeExistingPermissions,
2461           permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
2462     protocol.grant(controller, request);
2463   }
2464 
2465   /**
2466    * A utility used to grant a user namespace permissions.
2467    * <p>
2468    * It's also called by the shell, in case you want to find references.
2469    *
2470    * @param protocol the AccessControlService protocol proxy
2471    * @param namespace the short name of the user to grant permissions
2472    * @param actions the permissions to be granted
2473    * @throws ServiceException
2474    */
2475   public static void grant(RpcController controller,
2476       AccessControlService.BlockingInterface protocol, String userShortName, String namespace,
2477       boolean mergeExistingPermissions, Permission.Action... actions) throws ServiceException {
2478     List<AccessControlProtos.Permission.Action> permActions =
2479         Lists.newArrayListWithCapacity(actions.length);
2480     for (Permission.Action a : actions) {
2481       permActions.add(ProtobufUtil.toPermissionAction(a));
2482     }
2483     AccessControlProtos.GrantRequest request =
2484         RequestConverter.buildGrantRequest(userShortName, namespace, mergeExistingPermissions,
2485           permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
2486     protocol.grant(controller, request);
2487   }
2488 
2489   /**
2490    * A utility used to revoke a user's global permissions.
2491    * <p>
2492    * It's also called by the shell, in case you want to find references.
2493    *
2494    * @param protocol the AccessControlService protocol proxy
2495    * @param userShortName the short name of the user to revoke permissions
2496    * @param actions the permissions to be revoked
2497    * @throws ServiceException
2498    */
2499   public static void revoke(RpcController controller,
2500       AccessControlService.BlockingInterface protocol, String userShortName,
2501       Permission.Action... actions) throws ServiceException {
2502     List<AccessControlProtos.Permission.Action> permActions =
2503         Lists.newArrayListWithCapacity(actions.length);
2504     for (Permission.Action a : actions) {
2505       permActions.add(ProtobufUtil.toPermissionAction(a));
2506     }
2507     AccessControlProtos.RevokeRequest request = RequestConverter.
2508       buildRevokeRequest(userShortName, permActions.toArray(
2509         new AccessControlProtos.Permission.Action[actions.length]));
2510     protocol.revoke(controller, request);
2511   }
2512 
2513   /**
2514    * A utility used to revoke a user's table permissions. The permissions will
2515    * be for a table/column family/qualifier.
2516    * <p>
2517    * It's also called by the shell, in case you want to find references.
2518    *
2519    * @param protocol the AccessControlService protocol proxy
2520    * @param userShortName the short name of the user to revoke permissions
2521    * @param tableName optional table name
2522    * @param f optional column family
2523    * @param q optional qualifier
2524    * @param actions the permissions to be revoked
2525    * @throws ServiceException
2526    */
2527   public static void revoke(RpcController controller,
2528       AccessControlService.BlockingInterface protocol, String userShortName, TableName tableName,
2529       byte[] f, byte[] q, Permission.Action... actions) throws ServiceException {
2530     List<AccessControlProtos.Permission.Action> permActions =
2531         Lists.newArrayListWithCapacity(actions.length);
2532     for (Permission.Action a : actions) {
2533       permActions.add(ProtobufUtil.toPermissionAction(a));
2534     }
2535     AccessControlProtos.RevokeRequest request = RequestConverter.
2536       buildRevokeRequest(userShortName, tableName, f, q, permActions.toArray(
2537         new AccessControlProtos.Permission.Action[actions.length]));
2538     protocol.revoke(controller, request);
2539   }
2540 
2541   /**
2542    * A utility used to revoke a user's namespace permissions.
2543    * <p>
2544    * It's also called by the shell, in case you want to find references.
2545    *
2546    * @param protocol the AccessControlService protocol proxy
2547    * @param userShortName the short name of the user to revoke permissions
2548    * @param namespace optional table name
2549    * @param actions the permissions to be revoked
2550    * @throws ServiceException
2551    */
2552   public static void revoke(RpcController controller,
2553       AccessControlService.BlockingInterface protocol, String userShortName, String namespace,
2554       Permission.Action... actions) throws ServiceException {
2555     List<AccessControlProtos.Permission.Action> permActions =
2556         Lists.newArrayListWithCapacity(actions.length);
2557     for (Permission.Action a : actions) {
2558       permActions.add(ProtobufUtil.toPermissionAction(a));
2559     }
2560     AccessControlProtos.RevokeRequest request = RequestConverter.
2561       buildRevokeRequest(userShortName, namespace, permActions.toArray(
2562         new AccessControlProtos.Permission.Action[actions.length]));
2563     protocol.revoke(controller, request);
2564   }
2565 
2566   /**
2567    * A utility used to get user's global permissions.
2568    * <p>
2569    * It's also called by the shell, in case you want to find references.
2570    *
2571    * @param protocol the AccessControlService protocol proxy
2572    * @throws ServiceException
2573    */
2574   public static List<UserPermission> getUserPermissions(RpcController controller,
2575       AccessControlService.BlockingInterface protocol) throws ServiceException {
2576     AccessControlProtos.GetUserPermissionsRequest.Builder builder =
2577       AccessControlProtos.GetUserPermissionsRequest.newBuilder();
2578     builder.setType(AccessControlProtos.Permission.Type.Global);
2579     AccessControlProtos.GetUserPermissionsRequest request = builder.build();
2580     AccessControlProtos.GetUserPermissionsResponse response =
2581       protocol.getUserPermissions(controller, request);
2582     List<UserPermission> perms = new ArrayList<UserPermission>(response.getUserPermissionCount());
2583     for (AccessControlProtos.UserPermission perm: response.getUserPermissionList()) {
2584       perms.add(ProtobufUtil.toUserPermission(perm));
2585     }
2586     return perms;
2587   }
2588 
2589   /**
2590    * A utility used to get user table permissions.
2591    * <p>
2592    * It's also called by the shell, in case you want to find references.
2593    *
2594    * @param protocol the AccessControlService protocol proxy
2595    * @param t optional table name
2596    * @throws ServiceException
2597    */
2598   public static List<UserPermission> getUserPermissions(RpcController controller,
2599       AccessControlService.BlockingInterface protocol,
2600       TableName t) throws ServiceException {
2601     AccessControlProtos.GetUserPermissionsRequest.Builder builder =
2602       AccessControlProtos.GetUserPermissionsRequest.newBuilder();
2603     if (t != null) {
2604       builder.setTableName(ProtobufUtil.toProtoTableName(t));
2605     }
2606     builder.setType(AccessControlProtos.Permission.Type.Table);
2607     AccessControlProtos.GetUserPermissionsRequest request = builder.build();
2608     AccessControlProtos.GetUserPermissionsResponse response =
2609       protocol.getUserPermissions(controller, request);
2610     List<UserPermission> perms = new ArrayList<UserPermission>(response.getUserPermissionCount());
2611     for (AccessControlProtos.UserPermission perm: response.getUserPermissionList()) {
2612       perms.add(ProtobufUtil.toUserPermission(perm));
2613     }
2614     return perms;
2615   }
2616 
2617   /**
2618    * A utility used to get permissions for selected namespace.
2619    * <p>
2620    * It's also called by the shell, in case you want to find references.
2621    *
2622    * @param protocol the AccessControlService protocol proxy
2623    * @param namespace name of the namespace
2624    * @throws ServiceException
2625    */
2626   public static List<UserPermission> getUserPermissions(RpcController controller,
2627       AccessControlService.BlockingInterface protocol,
2628       byte[] namespace) throws ServiceException {
2629     AccessControlProtos.GetUserPermissionsRequest.Builder builder =
2630       AccessControlProtos.GetUserPermissionsRequest.newBuilder();
2631     if (namespace != null) {
2632       builder.setNamespaceName(ByteStringer.wrap(namespace));
2633     }
2634     builder.setType(AccessControlProtos.Permission.Type.Namespace);
2635     AccessControlProtos.GetUserPermissionsRequest request = builder.build();
2636     AccessControlProtos.GetUserPermissionsResponse response =
2637       protocol.getUserPermissions(controller, request);
2638     List<UserPermission> perms = new ArrayList<UserPermission>(response.getUserPermissionCount());
2639     for (AccessControlProtos.UserPermission perm: response.getUserPermissionList()) {
2640       perms.add(ProtobufUtil.toUserPermission(perm));
2641     }
2642     return perms;
2643   }
2644 
2645   /**
2646    * Convert a protobuf UserTablePermissions to a
2647    * ListMultimap&lt;String, TablePermission&gt; where key is username.
2648    *
2649    * @param proto the protobuf UserPermission
2650    * @return the converted UserPermission
2651    */
2652   public static ListMultimap<String, TablePermission> toUserTablePermissions(
2653       AccessControlProtos.UsersAndPermissions proto) {
2654     ListMultimap<String, TablePermission> perms = ArrayListMultimap.create();
2655     AccessControlProtos.UsersAndPermissions.UserPermissions userPerm;
2656 
2657     for (int i = 0; i < proto.getUserPermissionsCount(); i++) {
2658       userPerm = proto.getUserPermissions(i);
2659       for (int j = 0; j < userPerm.getPermissionsCount(); j++) {
2660         TablePermission tablePerm = toTablePermission(userPerm.getPermissions(j));
2661         perms.put(userPerm.getUser().toStringUtf8(), tablePerm);
2662       }
2663     }
2664 
2665     return perms;
2666   }
2667 
2668   /**
2669    * Converts a Token instance (with embedded identifier) to the protobuf representation.
2670    *
2671    * @param token the Token instance to copy
2672    * @return the protobuf Token message
2673    */
2674   public static AuthenticationProtos.Token toToken(Token<AuthenticationTokenIdentifier> token) {
2675     AuthenticationProtos.Token.Builder builder = AuthenticationProtos.Token.newBuilder();
2676     builder.setIdentifier(ByteStringer.wrap(token.getIdentifier()));
2677     builder.setPassword(ByteStringer.wrap(token.getPassword()));
2678     if (token.getService() != null) {
2679       builder.setService(ByteString.copyFromUtf8(token.getService().toString()));
2680     }
2681     return builder.build();
2682   }
2683 
2684   /**
2685    * Converts a protobuf Token message back into a Token instance.
2686    *
2687    * @param proto the protobuf Token message
2688    * @return the Token instance
2689    */
2690   public static Token<AuthenticationTokenIdentifier> toToken(AuthenticationProtos.Token proto) {
2691     return new Token<AuthenticationTokenIdentifier>(
2692         proto.hasIdentifier() ? proto.getIdentifier().toByteArray() : null,
2693         proto.hasPassword() ? proto.getPassword().toByteArray() : null,
2694         AuthenticationTokenIdentifier.AUTH_TOKEN_TYPE,
2695         proto.hasService() ? new Text(proto.getService().toStringUtf8()) : null);
2696   }
2697 
2698   /**
2699    * Find the HRegion encoded name based on a region specifier
2700    *
2701    * @param regionSpecifier the region specifier
2702    * @return the corresponding region's encoded name
2703    * @throws DoNotRetryIOException if the specifier type is unsupported
2704    */
2705   public static String getRegionEncodedName(
2706       final RegionSpecifier regionSpecifier) throws DoNotRetryIOException {
2707     ByteString value = regionSpecifier.getValue();
2708     RegionSpecifierType type = regionSpecifier.getType();
2709     switch (type) {
2710       case REGION_NAME:
2711         return HRegionInfo.encodeRegionName(value.toByteArray());
2712       case ENCODED_REGION_NAME:
2713         return value.toStringUtf8();
2714       default:
2715         throw new DoNotRetryIOException(
2716           "Unsupported region specifier type: " + type);
2717     }
2718   }
2719 
2720   public static ScanMetrics toScanMetrics(final byte[] bytes) {
2721     Parser<MapReduceProtos.ScanMetrics> parser = MapReduceProtos.ScanMetrics.PARSER;
2722     MapReduceProtos.ScanMetrics pScanMetrics = null;
2723     try {
2724       pScanMetrics = parser.parseFrom(bytes);
2725     } catch (InvalidProtocolBufferException e) {
2726       //Ignored there are just no key values to add.
2727     }
2728     ScanMetrics scanMetrics = new ScanMetrics();
2729     if (pScanMetrics != null) {
2730       for (HBaseProtos.NameInt64Pair pair : pScanMetrics.getMetricsList()) {
2731         if (pair.hasName() && pair.hasValue()) {
2732           scanMetrics.setCounter(pair.getName(), pair.getValue());
2733         }
2734       }
2735     }
2736     return scanMetrics;
2737   }
2738 
2739   public static MapReduceProtos.ScanMetrics toScanMetrics(ScanMetrics scanMetrics, boolean reset) {
2740     MapReduceProtos.ScanMetrics.Builder builder = MapReduceProtos.ScanMetrics.newBuilder();
2741     Map<String, Long> metrics = scanMetrics.getMetricsMap(reset);
2742     for (Entry<String, Long> e : metrics.entrySet()) {
2743       HBaseProtos.NameInt64Pair nameInt64Pair =
2744           HBaseProtos.NameInt64Pair.newBuilder()
2745               .setName(e.getKey())
2746               .setValue(e.getValue())
2747               .build();
2748       builder.addMetrics(nameInt64Pair);
2749     }
2750     return builder.build();
2751   }
2752 
2753   /**
2754    * Unwraps an exception from a protobuf service into the underlying (expected) IOException.
2755    * This method will <strong>always</strong> throw an exception.
2756    * @param se the {@code ServiceException} instance to convert into an {@code IOException}
2757    */
2758   public static void toIOException(ServiceException se) throws IOException {
2759     if (se == null) {
2760       throw new NullPointerException("Null service exception passed!");
2761     }
2762 
2763     Throwable cause = se.getCause();
2764     if (cause != null && cause instanceof IOException) {
2765       throw (IOException)cause;
2766     }
2767     throw new IOException(se);
2768   }
2769 
2770   public static CellProtos.Cell toCell(final Cell kv) {
2771     // Doing this is going to kill us if we do it for all data passed.
2772     // St.Ack 20121205
2773     CellProtos.Cell.Builder kvbuilder = CellProtos.Cell.newBuilder();
2774     kvbuilder.setRow(ByteStringer.wrap(kv.getRowArray(), kv.getRowOffset(),
2775         kv.getRowLength()));
2776     kvbuilder.setFamily(ByteStringer.wrap(kv.getFamilyArray(),
2777         kv.getFamilyOffset(), kv.getFamilyLength()));
2778     kvbuilder.setQualifier(ByteStringer.wrap(kv.getQualifierArray(),
2779         kv.getQualifierOffset(), kv.getQualifierLength()));
2780     kvbuilder.setCellType(CellProtos.CellType.valueOf(kv.getTypeByte()));
2781     kvbuilder.setTimestamp(kv.getTimestamp());
2782     kvbuilder.setValue(ByteStringer.wrap(kv.getValueArray(), kv.getValueOffset(),
2783         kv.getValueLength()));
2784     return kvbuilder.build();
2785   }
2786 
2787   public static Cell toCell(final CellProtos.Cell cell) {
2788     // Doing this is going to kill us if we do it for all data passed.
2789     // St.Ack 20121205
2790     return CellUtil.createCell(cell.getRow().toByteArray(),
2791       cell.getFamily().toByteArray(),
2792       cell.getQualifier().toByteArray(),
2793       cell.getTimestamp(),
2794       (byte)cell.getCellType().getNumber(),
2795       cell.getValue().toByteArray());
2796   }
2797 
2798   public static HBaseProtos.NamespaceDescriptor toProtoNamespaceDescriptor(NamespaceDescriptor ns) {
2799     HBaseProtos.NamespaceDescriptor.Builder b =
2800         HBaseProtos.NamespaceDescriptor.newBuilder()
2801             .setName(ByteString.copyFromUtf8(ns.getName()));
2802     for(Map.Entry<String, String> entry: ns.getConfiguration().entrySet()) {
2803       b.addConfiguration(HBaseProtos.NameStringPair.newBuilder()
2804           .setName(entry.getKey())
2805           .setValue(entry.getValue()));
2806     }
2807     return b.build();
2808   }
2809 
2810   public static NamespaceDescriptor toNamespaceDescriptor(
2811       HBaseProtos.NamespaceDescriptor desc) throws IOException {
2812     NamespaceDescriptor.Builder b =
2813       NamespaceDescriptor.create(desc.getName().toStringUtf8());
2814     for(HBaseProtos.NameStringPair prop : desc.getConfigurationList()) {
2815       b.addConfiguration(prop.getName(), prop.getValue());
2816     }
2817     return b.build();
2818   }
2819 
2820   /**
2821    * Get an instance of the argument type declared in a class's signature. The
2822    * argument type is assumed to be a PB Message subclass, and the instance is
2823    * created using parseFrom method on the passed ByteString.
2824    * @param runtimeClass the runtime type of the class
2825    * @param position the position of the argument in the class declaration
2826    * @param b the ByteString which should be parsed to get the instance created
2827    * @return the instance
2828    * @throws IOException
2829    */
2830   @SuppressWarnings("unchecked")
2831   public static <T extends Message>
2832   T getParsedGenericInstance(Class<?> runtimeClass, int position, ByteString b)
2833       throws IOException {
2834     Type type = runtimeClass.getGenericSuperclass();
2835     Type argType = ((ParameterizedType)type).getActualTypeArguments()[position];
2836     Class<T> classType = (Class<T>)argType;
2837     T inst;
2838     try {
2839       Method m = classType.getMethod("parseFrom", ByteString.class);
2840       inst = (T)m.invoke(null, b);
2841       return inst;
2842     } catch (SecurityException e) {
2843       throw new IOException(e);
2844     } catch (NoSuchMethodException e) {
2845       throw new IOException(e);
2846     } catch (IllegalArgumentException e) {
2847       throw new IOException(e);
2848     } catch (InvocationTargetException e) {
2849       throw new IOException(e);
2850     } catch (IllegalAccessException e) {
2851       throw new IOException(e);
2852     }
2853   }
2854 
2855   public static CompactionDescriptor toCompactionDescriptor(HRegionInfo info, byte[] family,
2856       List<Path> inputPaths, List<Path> outputPaths, Path storeDir) {
2857     return toCompactionDescriptor(info, null, family, inputPaths, outputPaths, storeDir);
2858   }
2859 
2860   @SuppressWarnings("deprecation")
2861   public static CompactionDescriptor toCompactionDescriptor(HRegionInfo info, byte[] regionName,
2862       byte[] family, List<Path> inputPaths, List<Path> outputPaths, Path storeDir) {
2863     // compaction descriptor contains relative paths.
2864     // input / output paths are relative to the store dir
2865     // store dir is relative to region dir
2866     CompactionDescriptor.Builder builder = CompactionDescriptor.newBuilder()
2867         .setTableName(ByteStringer.wrap(info.getTableName()))
2868         .setEncodedRegionName(ByteStringer.wrap(
2869           regionName == null ? info.getEncodedNameAsBytes() : regionName))
2870         .setFamilyName(ByteStringer.wrap(family))
2871         .setStoreHomeDir(storeDir.getName()); //make relative
2872     for (Path inputPath : inputPaths) {
2873       builder.addCompactionInput(inputPath.getName()); //relative path
2874     }
2875     for (Path outputPath : outputPaths) {
2876       builder.addCompactionOutput(outputPath.getName());
2877     }
2878     builder.setRegionName(ByteStringer.wrap(info.getRegionName()));
2879     return builder.build();
2880   }
2881 
2882   public static FlushDescriptor toFlushDescriptor(FlushAction action, HRegionInfo hri,
2883       long flushSeqId, Map<byte[], List<Path>> committedFiles) {
2884     FlushDescriptor.Builder desc = FlushDescriptor.newBuilder()
2885         .setAction(action)
2886         .setEncodedRegionName(ByteStringer.wrap(hri.getEncodedNameAsBytes()))
2887         .setRegionName(ByteStringer.wrap(hri.getRegionName()))
2888         .setFlushSequenceNumber(flushSeqId)
2889         .setTableName(ByteStringer.wrap(hri.getTable().getName()));
2890 
2891     for (Map.Entry<byte[], List<Path>> entry : committedFiles.entrySet()) {
2892       WALProtos.FlushDescriptor.StoreFlushDescriptor.Builder builder =
2893           WALProtos.FlushDescriptor.StoreFlushDescriptor.newBuilder()
2894           .setFamilyName(ByteStringer.wrap(entry.getKey()))
2895           .setStoreHomeDir(Bytes.toString(entry.getKey())); //relative to region
2896       if (entry.getValue() != null) {
2897         for (Path path : entry.getValue()) {
2898           builder.addFlushOutput(path.getName());
2899         }
2900       }
2901       desc.addStoreFlushes(builder);
2902     }
2903     return desc.build();
2904   }
2905 
2906   public static RegionEventDescriptor toRegionEventDescriptor(
2907       EventType eventType, HRegionInfo hri, long seqId, ServerName server,
2908       Map<byte[], List<Path>> storeFiles) {
2909     final byte[] tableNameAsBytes = hri.getTable().getName();
2910     final byte[] encodedNameAsBytes = hri.getEncodedNameAsBytes();
2911     final byte[] regionNameAsBytes = hri.getRegionName();
2912     return toRegionEventDescriptor(eventType,
2913         tableNameAsBytes,
2914         encodedNameAsBytes,
2915         regionNameAsBytes,
2916         seqId,
2917 
2918         server,
2919         storeFiles);
2920   }
2921 
2922   public static RegionEventDescriptor toRegionEventDescriptor(EventType eventType,
2923                                                               byte[] tableNameAsBytes,
2924                                                               byte[] encodedNameAsBytes,
2925                                                               byte[] regionNameAsBytes,
2926                                                                long seqId,
2927 
2928                                                               ServerName server,
2929                                                               Map<byte[], List<Path>> storeFiles) {
2930     RegionEventDescriptor.Builder desc = RegionEventDescriptor.newBuilder()
2931         .setEventType(eventType)
2932         .setTableName(ByteStringer.wrap(tableNameAsBytes))
2933         .setEncodedRegionName(ByteStringer.wrap(encodedNameAsBytes))
2934         .setRegionName(ByteStringer.wrap(regionNameAsBytes))
2935         .setLogSequenceNumber(seqId)
2936         .setServer(toServerName(server));
2937 
2938     for (Entry<byte[], List<Path>> entry : storeFiles.entrySet()) {
2939       StoreDescriptor.Builder builder = StoreDescriptor.newBuilder()
2940           .setFamilyName(ByteStringer.wrap(entry.getKey()))
2941           .setStoreHomeDir(Bytes.toString(entry.getKey()));
2942       for (Path path : entry.getValue()) {
2943         builder.addStoreFile(path.getName());
2944       }
2945 
2946       desc.addStores(builder);
2947     }
2948     return desc.build();
2949   }
2950 
2951   /**
2952    * Return short version of Message toString'd, shorter than TextFormat#shortDebugString.
2953    * Tries to NOT print out data both because it can be big but also so we do not have data in our
2954    * logs. Use judiciously.
2955    * @param m
2956    * @return toString of passed <code>m</code>
2957    */
2958   public static String getShortTextFormat(Message m) {
2959     if (m == null) return "null";
2960     if (m instanceof ScanRequest) {
2961       // This should be small and safe to output.  No data.
2962       return TextFormat.shortDebugString(m);
2963     } else if (m instanceof RegionServerReportRequest) {
2964       // Print a short message only, just the servername and the requests, not the full load.
2965       RegionServerReportRequest r = (RegionServerReportRequest)m;
2966       return "server " + TextFormat.shortDebugString(r.getServer()) +
2967         " load { numberOfRequests: " + r.getLoad().getNumberOfRequests() + " }";
2968     } else if (m instanceof RegionServerStartupRequest) {
2969       // Should be small enough.
2970       return TextFormat.shortDebugString(m);
2971     } else if (m instanceof MutationProto) {
2972       return toShortString((MutationProto)m);
2973     } else if (m instanceof GetRequest) {
2974       GetRequest r = (GetRequest) m;
2975       return "region= " + getStringForByteString(r.getRegion().getValue()) +
2976           ", row=" + getStringForByteString(r.getGet().getRow());
2977     } else if (m instanceof ClientProtos.MultiRequest) {
2978       ClientProtos.MultiRequest r = (ClientProtos.MultiRequest) m;
2979 
2980       // Get the number of Actions
2981       int actionsCount = 0;
2982       for (ClientProtos.RegionAction regionAction : r.getRegionActionList()) {
2983         actionsCount += regionAction.getActionCount();
2984       }
2985 
2986       // Get first set of Actions.
2987       ClientProtos.RegionAction actions = r.getRegionActionList().get(0);
2988       String row = actions.getActionCount() <= 0? "":
2989         getStringForByteString(actions.getAction(0).hasGet()?
2990           actions.getAction(0).getGet().getRow():
2991           actions.getAction(0).getMutation().getRow());
2992       return "region= " + getStringForByteString(actions.getRegion().getValue()) +
2993           ", for " + actionsCount + " action(s) and 1st row key=" + row;
2994     } else if (m instanceof ClientProtos.MutateRequest) {
2995       ClientProtos.MutateRequest r = (ClientProtos.MutateRequest) m;
2996       return "region= " + getStringForByteString(r.getRegion().getValue()) +
2997           ", row=" + getStringForByteString(r.getMutation().getRow());
2998     } else if (m instanceof ClientProtos.CoprocessorServiceRequest) {
2999       ClientProtos.CoprocessorServiceRequest r = (ClientProtos.CoprocessorServiceRequest) m;
3000       return "coprocessorService= " + r.getCall().getServiceName() + ":" + r.getCall()
3001           .getMethodName();
3002     }
3003 
3004     return "TODO: " + m.getClass().toString();
3005   }
3006 
3007   private static String getStringForByteString(ByteString bs) {
3008     return Bytes.toStringBinary(bs.toByteArray());
3009   }
3010 
3011   /**
3012    * Print out some subset of a MutationProto rather than all of it and its data
3013    * @param proto Protobuf to print out
3014    * @return Short String of mutation proto
3015    */
3016   static String toShortString(final MutationProto proto) {
3017     return "row=" + Bytes.toString(proto.getRow().toByteArray()) +
3018         ", type=" + proto.getMutateType().toString();
3019   }
3020 
3021   public static TableName toTableName(TableProtos.TableName tableNamePB) {
3022     return TableName.valueOf(tableNamePB.getNamespace().asReadOnlyByteBuffer(),
3023         tableNamePB.getQualifier().asReadOnlyByteBuffer());
3024   }
3025 
3026   public static TableProtos.TableName toProtoTableName(TableName tableName) {
3027     return TableProtos.TableName.newBuilder()
3028         .setNamespace(ByteStringer.wrap(tableName.getNamespace()))
3029         .setQualifier(ByteStringer.wrap(tableName.getQualifier())).build();
3030   }
3031 
3032   public static TableName[] getTableNameArray(List<TableProtos.TableName> tableNamesList) {
3033     if (tableNamesList == null) {
3034       return new TableName[0];
3035     }
3036     TableName[] tableNames = new TableName[tableNamesList.size()];
3037     for (int i = 0; i < tableNamesList.size(); i++) {
3038       tableNames[i] = toTableName(tableNamesList.get(i));
3039     }
3040     return tableNames;
3041   }
3042 
3043   /**
3044    * Convert a protocol buffer CellVisibility to a client CellVisibility
3045    *
3046    * @param proto
3047    * @return the converted client CellVisibility
3048    */
3049   public static CellVisibility toCellVisibility(ClientProtos.CellVisibility proto) {
3050     if (proto == null) return null;
3051     return new CellVisibility(proto.getExpression());
3052   }
3053 
3054   /**
3055    * Convert a protocol buffer CellVisibility bytes to a client CellVisibility
3056    *
3057    * @param protoBytes
3058    * @return the converted client CellVisibility
3059    * @throws DeserializationException
3060    */
3061   public static CellVisibility toCellVisibility(byte[] protoBytes) throws DeserializationException {
3062     if (protoBytes == null) return null;
3063     ClientProtos.CellVisibility.Builder builder = ClientProtos.CellVisibility.newBuilder();
3064     ClientProtos.CellVisibility proto = null;
3065     try {
3066       ProtobufUtil.mergeFrom(builder, protoBytes);
3067       proto = builder.build();
3068     } catch (IOException e) {
3069       throw new DeserializationException(e);
3070     }
3071     return toCellVisibility(proto);
3072   }
3073 
3074   /**
3075    * Create a protocol buffer CellVisibility based on a client CellVisibility.
3076    *
3077    * @param cellVisibility
3078    * @return a protocol buffer CellVisibility
3079    */
3080   public static ClientProtos.CellVisibility toCellVisibility(CellVisibility cellVisibility) {
3081     ClientProtos.CellVisibility.Builder builder = ClientProtos.CellVisibility.newBuilder();
3082     builder.setExpression(cellVisibility.getExpression());
3083     return builder.build();
3084   }
3085 
3086   /**
3087    * Convert a protocol buffer Authorizations to a client Authorizations
3088    *
3089    * @param proto
3090    * @return the converted client Authorizations
3091    */
3092   public static Authorizations toAuthorizations(ClientProtos.Authorizations proto) {
3093     if (proto == null) return null;
3094     return new Authorizations(proto.getLabelList());
3095   }
3096 
3097   /**
3098    * Convert a protocol buffer Authorizations bytes to a client Authorizations
3099    *
3100    * @param protoBytes
3101    * @return the converted client Authorizations
3102    * @throws DeserializationException
3103    */
3104   public static Authorizations toAuthorizations(byte[] protoBytes) throws DeserializationException {
3105     if (protoBytes == null) return null;
3106     ClientProtos.Authorizations.Builder builder = ClientProtos.Authorizations.newBuilder();
3107     ClientProtos.Authorizations proto = null;
3108     try {
3109       ProtobufUtil.mergeFrom(builder, protoBytes);
3110       proto = builder.build();
3111     } catch (IOException e) {
3112       throw new DeserializationException(e);
3113     }
3114     return toAuthorizations(proto);
3115   }
3116 
3117   /**
3118    * Create a protocol buffer Authorizations based on a client Authorizations.
3119    *
3120    * @param authorizations
3121    * @return a protocol buffer Authorizations
3122    */
3123   public static ClientProtos.Authorizations toAuthorizations(Authorizations authorizations) {
3124     ClientProtos.Authorizations.Builder builder = ClientProtos.Authorizations.newBuilder();
3125     for (String label : authorizations.getLabels()) {
3126       builder.addLabel(label);
3127     }
3128     return builder.build();
3129   }
3130 
3131   public static AccessControlProtos.UsersAndPermissions toUsersAndPermissions(String user,
3132       Permission perms) {
3133     return AccessControlProtos.UsersAndPermissions.newBuilder()
3134       .addUserPermissions(AccessControlProtos.UsersAndPermissions.UserPermissions.newBuilder()
3135         .setUser(ByteString.copyFromUtf8(user))
3136         .addPermissions(toPermission(perms))
3137         .build())
3138       .build();
3139   }
3140 
3141   public static AccessControlProtos.UsersAndPermissions toUsersAndPermissions(
3142       ListMultimap<String, Permission> perms) {
3143     AccessControlProtos.UsersAndPermissions.Builder builder =
3144         AccessControlProtos.UsersAndPermissions.newBuilder();
3145     for (Map.Entry<String, Collection<Permission>> entry : perms.asMap().entrySet()) {
3146       AccessControlProtos.UsersAndPermissions.UserPermissions.Builder userPermBuilder =
3147         AccessControlProtos.UsersAndPermissions.UserPermissions.newBuilder();
3148       userPermBuilder.setUser(ByteString.copyFromUtf8(entry.getKey()));
3149       for (Permission perm: entry.getValue()) {
3150         userPermBuilder.addPermissions(toPermission(perm));
3151       }
3152       builder.addUserPermissions(userPermBuilder.build());
3153     }
3154     return builder.build();
3155   }
3156 
3157   public static ListMultimap<String, Permission> toUsersAndPermissions(
3158       AccessControlProtos.UsersAndPermissions proto) {
3159     ListMultimap<String, Permission> result = ArrayListMultimap.create();
3160     for (AccessControlProtos.UsersAndPermissions.UserPermissions userPerms:
3161         proto.getUserPermissionsList()) {
3162       String user = userPerms.getUser().toStringUtf8();
3163       for (AccessControlProtos.Permission perm: userPerms.getPermissionsList()) {
3164         result.put(user, toPermission(perm));
3165       }
3166     }
3167     return result;
3168   }
3169 
3170   /**
3171    * Convert a protocol buffer TimeUnit to a client TimeUnit
3172    * @param proto
3173    * @return the converted client TimeUnit
3174    */
3175   public static TimeUnit toTimeUnit(final HBaseProtos.TimeUnit proto) {
3176     switch (proto) {
3177     case NANOSECONDS:
3178       return TimeUnit.NANOSECONDS;
3179     case MICROSECONDS:
3180       return TimeUnit.MICROSECONDS;
3181     case MILLISECONDS:
3182       return TimeUnit.MILLISECONDS;
3183     case SECONDS:
3184       return TimeUnit.SECONDS;
3185     case MINUTES:
3186       return TimeUnit.MINUTES;
3187     case HOURS:
3188       return TimeUnit.HOURS;
3189     case DAYS:
3190       return TimeUnit.DAYS;
3191     default:
3192       throw new RuntimeException("Invalid TimeUnit " + proto);
3193     }
3194   }
3195 
3196   /**
3197    * Convert a client TimeUnit to a protocol buffer TimeUnit
3198    * @param timeUnit
3199    * @return the converted protocol buffer TimeUnit
3200    */
3201   public static HBaseProtos.TimeUnit toProtoTimeUnit(final TimeUnit timeUnit) {
3202     switch (timeUnit) {
3203     case NANOSECONDS:
3204       return HBaseProtos.TimeUnit.NANOSECONDS;
3205     case MICROSECONDS:
3206       return HBaseProtos.TimeUnit.MICROSECONDS;
3207     case MILLISECONDS:
3208       return HBaseProtos.TimeUnit.MILLISECONDS;
3209     case SECONDS:
3210       return HBaseProtos.TimeUnit.SECONDS;
3211     case MINUTES:
3212       return HBaseProtos.TimeUnit.MINUTES;
3213     case HOURS:
3214       return HBaseProtos.TimeUnit.HOURS;
3215     case DAYS:
3216       return HBaseProtos.TimeUnit.DAYS;
3217     default:
3218       throw new RuntimeException("Invalid TimeUnit " + timeUnit);
3219     }
3220   }
3221 
3222   /**
3223    * Convert a protocol buffer ThrottleType to a client ThrottleType
3224    * @param proto
3225    * @return the converted client ThrottleType
3226    */
3227   public static ThrottleType toThrottleType(final QuotaProtos.ThrottleType proto) {
3228     switch (proto) {
3229     case REQUEST_NUMBER:
3230       return ThrottleType.REQUEST_NUMBER;
3231     case REQUEST_SIZE:
3232       return ThrottleType.REQUEST_SIZE;
3233     case WRITE_NUMBER:
3234       return ThrottleType.WRITE_NUMBER;
3235     case WRITE_SIZE:
3236       return ThrottleType.WRITE_SIZE;
3237     case READ_NUMBER:
3238       return ThrottleType.READ_NUMBER;
3239     case READ_SIZE:
3240       return ThrottleType.READ_SIZE;
3241     default:
3242       throw new RuntimeException("Invalid ThrottleType " + proto);
3243     }
3244   }
3245 
3246   /**
3247    * Convert a client ThrottleType to a protocol buffer ThrottleType
3248    * @param type
3249    * @return the converted protocol buffer ThrottleType
3250    */
3251   public static QuotaProtos.ThrottleType toProtoThrottleType(final ThrottleType type) {
3252     switch (type) {
3253     case REQUEST_NUMBER:
3254       return QuotaProtos.ThrottleType.REQUEST_NUMBER;
3255     case REQUEST_SIZE:
3256       return QuotaProtos.ThrottleType.REQUEST_SIZE;
3257     case WRITE_NUMBER:
3258       return QuotaProtos.ThrottleType.WRITE_NUMBER;
3259     case WRITE_SIZE:
3260       return QuotaProtos.ThrottleType.WRITE_SIZE;
3261     case READ_NUMBER:
3262       return QuotaProtos.ThrottleType.READ_NUMBER;
3263     case READ_SIZE:
3264       return QuotaProtos.ThrottleType.READ_SIZE;
3265     default:
3266       throw new RuntimeException("Invalid ThrottleType " + type);
3267     }
3268   }
3269 
3270   /**
3271    * Convert a protocol buffer QuotaScope to a client QuotaScope
3272    * @param proto
3273    * @return the converted client QuotaScope
3274    */
3275   public static QuotaScope toQuotaScope(final QuotaProtos.QuotaScope proto) {
3276     switch (proto) {
3277     case CLUSTER:
3278       return QuotaScope.CLUSTER;
3279     case MACHINE:
3280       return QuotaScope.MACHINE;
3281     default:
3282       throw new RuntimeException("Invalid QuotaScope " + proto);
3283     }
3284   }
3285 
3286   /**
3287    * Convert a client QuotaScope to a protocol buffer QuotaScope
3288    * @param scope
3289    * @return the converted protocol buffer QuotaScope
3290    */
3291   public static QuotaProtos.QuotaScope toProtoQuotaScope(final QuotaScope scope) {
3292     switch (scope) {
3293     case CLUSTER:
3294       return QuotaProtos.QuotaScope.CLUSTER;
3295     case MACHINE:
3296       return QuotaProtos.QuotaScope.MACHINE;
3297     default:
3298       throw new RuntimeException("Invalid QuotaScope " + scope);
3299     }
3300   }
3301 
3302   /**
3303    * Convert a protocol buffer QuotaType to a client QuotaType
3304    * @param proto
3305    * @return the converted client QuotaType
3306    */
3307   public static QuotaType toQuotaScope(final QuotaProtos.QuotaType proto) {
3308     switch (proto) {
3309     case THROTTLE:
3310       return QuotaType.THROTTLE;
3311     default:
3312       throw new RuntimeException("Invalid QuotaType " + proto);
3313     }
3314   }
3315 
3316   /**
3317    * Convert a client QuotaType to a protocol buffer QuotaType
3318    * @param type
3319    * @return the converted protocol buffer QuotaType
3320    */
3321   public static QuotaProtos.QuotaType toProtoQuotaScope(final QuotaType type) {
3322     switch (type) {
3323     case THROTTLE:
3324       return QuotaProtos.QuotaType.THROTTLE;
3325     default:
3326       throw new RuntimeException("Invalid QuotaType " + type);
3327     }
3328   }
3329 
3330   /**
3331    * Build a protocol buffer TimedQuota
3332    * @param limit the allowed number of request/data per timeUnit
3333    * @param timeUnit the limit time unit
3334    * @param scope the quota scope
3335    * @return the protocol buffer TimedQuota
3336    */
3337   public static QuotaProtos.TimedQuota toTimedQuota(final long limit, final TimeUnit timeUnit,
3338       final QuotaScope scope) {
3339     return QuotaProtos.TimedQuota.newBuilder().setSoftLimit(limit)
3340         .setTimeUnit(toProtoTimeUnit(timeUnit)).setScope(toProtoQuotaScope(scope)).build();
3341   }
3342 
3343   /**
3344    * Generates a marker for the WAL so that we propagate the notion of a bulk region load
3345    * throughout the WAL.
3346    *
3347    * @param tableName         The tableName into which the bulk load is being imported into.
3348    * @param encodedRegionName Encoded region name of the region which is being bulk loaded.
3349    * @param storeFiles        A set of store files of a column family are bulk loaded.
3350    * @param storeFilesSize  Map of store files and their lengths
3351    * @param bulkloadSeqId     sequence ID (by a force flush) used to create bulk load hfile
3352    *                          name
3353    * @return The WAL log marker for bulk loads.
3354    */
3355   public static WALProtos.BulkLoadDescriptor toBulkLoadDescriptor(TableName tableName,
3356       ByteString encodedRegionName, Map<byte[], List<Path>> storeFiles,
3357       Map<String, Long> storeFilesSize, long bulkloadSeqId) {
3358     BulkLoadDescriptor.Builder desc =
3359         BulkLoadDescriptor.newBuilder()
3360         .setTableName(ProtobufUtil.toProtoTableName(tableName))
3361         .setEncodedRegionName(encodedRegionName).setBulkloadSeqNum(bulkloadSeqId);
3362 
3363     for (Map.Entry<byte[], List<Path>> entry : storeFiles.entrySet()) {
3364       WALProtos.StoreDescriptor.Builder builder = StoreDescriptor.newBuilder()
3365           .setFamilyName(ByteStringer.wrap(entry.getKey()))
3366           .setStoreHomeDir(Bytes.toString(entry.getKey())); // relative to region
3367       for (Path path : entry.getValue()) {
3368         String name = path.getName();
3369         builder.addStoreFile(name);
3370         Long size = storeFilesSize.get(name) == null ? (Long) 0L : storeFilesSize.get(name);
3371         builder.setStoreFileSizeBytes(size);
3372       }
3373       desc.addStores(builder);
3374     }
3375 
3376     return desc.build();
3377   }
3378 
3379   /**
3380    * This version of protobuf's mergeDelimitedFrom avoids the hard-coded 64MB limit for decoding
3381    * buffers
3382    * @param builder current message builder
3383    * @param in Inputsream with delimited protobuf data
3384    * @throws IOException
3385    */
3386   public static void mergeDelimitedFrom(Message.Builder builder, InputStream in)
3387     throws IOException {
3388     // This used to be builder.mergeDelimitedFrom(in);
3389     // but is replaced to allow us to bump the protobuf size limit.
3390     final int firstByte = in.read();
3391     if (firstByte != -1) {
3392       final int size = CodedInputStream.readRawVarint32(firstByte, in);
3393       final InputStream limitedInput = new LimitInputStream(in, size);
3394       final CodedInputStream codedInput = CodedInputStream.newInstance(limitedInput);
3395       codedInput.setSizeLimit(size);
3396       builder.mergeFrom(codedInput);
3397       codedInput.checkLastTagWas(0);
3398     }
3399   }
3400 
3401   /**
3402    * This version of protobuf's mergeFrom avoids the hard-coded 64MB limit for decoding
3403    * buffers where the message size is known
3404    * @param builder current message builder
3405    * @param in InputStream containing protobuf data
3406    * @param size known size of protobuf data
3407    * @throws IOException
3408    */
3409   public static void mergeFrom(Message.Builder builder, InputStream in, int size)
3410       throws IOException {
3411     final CodedInputStream codedInput = CodedInputStream.newInstance(in);
3412     codedInput.setSizeLimit(size);
3413     builder.mergeFrom(codedInput);
3414     codedInput.checkLastTagWas(0);
3415   }
3416 
3417   /**
3418    * This version of protobuf's mergeFrom avoids the hard-coded 64MB limit for decoding
3419    * buffers where the message size is not known
3420    * @param builder current message builder
3421    * @param in InputStream containing protobuf data
3422    * @throws IOException
3423    */
3424   public static void mergeFrom(Message.Builder builder, InputStream in)
3425       throws IOException {
3426     final CodedInputStream codedInput = CodedInputStream.newInstance(in);
3427     codedInput.setSizeLimit(Integer.MAX_VALUE);
3428     builder.mergeFrom(codedInput);
3429     codedInput.checkLastTagWas(0);
3430   }
3431 
3432   /**
3433    * This version of protobuf's mergeFrom avoids the hard-coded 64MB limit for decoding
3434    * buffers when working with ByteStrings
3435    * @param builder current message builder
3436    * @param bs ByteString containing the
3437    * @throws IOException
3438    */
3439   public static void mergeFrom(Message.Builder builder, ByteString bs) throws IOException {
3440     final CodedInputStream codedInput = bs.newCodedInput();
3441     codedInput.setSizeLimit(bs.size());
3442     builder.mergeFrom(codedInput);
3443     codedInput.checkLastTagWas(0);
3444   }
3445 
3446   /**
3447    * This version of protobuf's mergeFrom avoids the hard-coded 64MB limit for decoding
3448    * buffers when working with byte arrays
3449    * @param builder current message builder
3450    * @param b byte array
3451    * @throws IOException
3452    */
3453   public static void mergeFrom(Message.Builder builder, byte[] b) throws IOException {
3454     final CodedInputStream codedInput = CodedInputStream.newInstance(b);
3455     codedInput.setSizeLimit(b.length);
3456     builder.mergeFrom(codedInput);
3457     codedInput.checkLastTagWas(0);
3458   }
3459 
3460   /**
3461    * This version of protobuf's mergeFrom avoids the hard-coded 64MB limit for decoding
3462    * buffers when working with byte arrays
3463    * @param builder current message builder
3464    * @param b byte array
3465    * @param offset
3466    * @param length
3467    * @throws IOException
3468    */
3469   public static void mergeFrom(Message.Builder builder, byte[] b, int offset, int length)
3470       throws IOException {
3471     final CodedInputStream codedInput = CodedInputStream.newInstance(b, offset, length);
3472     codedInput.setSizeLimit(length);
3473     builder.mergeFrom(codedInput);
3474     codedInput.checkLastTagWas(0);
3475   }
3476 
3477   public static void mergeFrom(Message.Builder builder, CodedInputStream codedInput, int length)
3478       throws IOException {
3479     codedInput.resetSizeCounter();
3480     int prevLimit = codedInput.setSizeLimit(length);
3481 
3482     int limit = codedInput.pushLimit(length);
3483     builder.mergeFrom(codedInput);
3484     codedInput.popLimit(limit);
3485 
3486     codedInput.checkLastTagWas(0);
3487     codedInput.setSizeLimit(prevLimit);
3488   }
3489 
3490   public static ReplicationLoadSink toReplicationLoadSink(
3491       ClusterStatusProtos.ReplicationLoadSink cls) {
3492     return new ReplicationLoadSink(cls.getAgeOfLastAppliedOp(), cls.getTimeStampsOfLastAppliedOp());
3493   }
3494 
3495   public static ReplicationLoadSource toReplicationLoadSource(
3496       ClusterStatusProtos.ReplicationLoadSource cls) {
3497     return new ReplicationLoadSource(cls.getPeerID(), cls.getAgeOfLastShippedOp(),
3498         cls.getSizeOfLogQueue(), cls.getTimeStampOfLastShippedOp(), cls.getReplicationLag());
3499   }
3500 
3501   public static List<ReplicationLoadSource> toReplicationLoadSourceList(
3502       List<ClusterStatusProtos.ReplicationLoadSource> clsList) {
3503     ArrayList<ReplicationLoadSource> rlsList = new ArrayList<ReplicationLoadSource>();
3504     for (ClusterStatusProtos.ReplicationLoadSource cls : clsList) {
3505       rlsList.add(toReplicationLoadSource(cls));
3506     }
3507     return rlsList;
3508   }
3509 
3510   /**
3511    * Get a protocol buffer VersionInfo
3512    *
3513    * @return the converted protocol buffer VersionInfo
3514    */
3515   public static HBaseProtos.VersionInfo getVersionInfo() {
3516     HBaseProtos.VersionInfo.Builder builder = HBaseProtos.VersionInfo.newBuilder();
3517     String version = VersionInfo.getVersion();
3518     builder.setVersion(version);
3519     String[] components = version.split("\\.");
3520     if (components != null && components.length > 2) {
3521       builder.setVersionMajor(Integer.parseInt(components[0]));
3522       builder.setVersionMinor(Integer.parseInt(components[1]));
3523     }
3524     builder.setUrl(VersionInfo.getUrl());
3525     builder.setRevision(VersionInfo.getRevision());
3526     builder.setUser(VersionInfo.getUser());
3527     builder.setDate(VersionInfo.getDate());
3528     builder.setSrcChecksum(VersionInfo.getSrcChecksum());
3529     return builder.build();
3530   }
3531 
3532   /**
3533    * Convert SecurityCapabilitiesResponse.Capability to SecurityCapability
3534    * @param capabilities capabilities returned in the SecurityCapabilitiesResponse message
3535    * @return the converted list of SecurityCapability elements
3536    */
3537   public static List<SecurityCapability> toSecurityCapabilityList(
3538       List<MasterProtos.SecurityCapabilitiesResponse.Capability> capabilities) {
3539     List<SecurityCapability> scList = new ArrayList<>(capabilities.size());
3540     for (MasterProtos.SecurityCapabilitiesResponse.Capability c: capabilities) {
3541       try {
3542         scList.add(SecurityCapability.valueOf(c.getNumber()));
3543       } catch (IllegalArgumentException e) {
3544         // Unknown capability, just ignore it. We don't understand the new capability
3545         // but don't care since by definition we cannot take advantage of it.
3546       }
3547     }
3548     return scList;
3549   }
3550 
3551   private static HBaseProtos.TimeRange.Builder timeRangeToProto(TimeRange timeRange) {
3552     HBaseProtos.TimeRange.Builder timeRangeBuilder =
3553         HBaseProtos.TimeRange.newBuilder();
3554     timeRangeBuilder.setFrom(timeRange.getMin());
3555     timeRangeBuilder.setTo(timeRange.getMax());
3556     return timeRangeBuilder;
3557   }
3558 
3559   private static TimeRange protoToTimeRange(HBaseProtos.TimeRange timeRange) throws IOException {
3560       long minStamp = 0;
3561       long maxStamp = Long.MAX_VALUE;
3562       if (timeRange.hasFrom()) {
3563         minStamp = timeRange.getFrom();
3564       }
3565       if (timeRange.hasTo()) {
3566         maxStamp = timeRange.getTo();
3567       }
3568     return new TimeRange(minStamp, maxStamp);
3569   }
3570 
3571 }