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  import java.io.IOException;
21  import java.util.List;
22  
23  import org.apache.hadoop.classification.InterfaceAudience;
24  import org.apache.hadoop.hbase.CellScannable;
25  import org.apache.hadoop.hbase.HColumnDescriptor;
26  import org.apache.hadoop.hbase.HRegionInfo;
27  import org.apache.hadoop.hbase.HTableDescriptor;
28  import org.apache.hadoop.hbase.ServerName;
29  import org.apache.hadoop.hbase.client.Action;
30  import org.apache.hadoop.hbase.client.Append;
31  import org.apache.hadoop.hbase.client.Delete;
32  import org.apache.hadoop.hbase.client.Get;
33  import org.apache.hadoop.hbase.client.Increment;
34  import org.apache.hadoop.hbase.client.Mutation;
35  import org.apache.hadoop.hbase.client.Put;
36  import org.apache.hadoop.hbase.client.Row;
37  import org.apache.hadoop.hbase.client.RowMutations;
38  import org.apache.hadoop.hbase.client.Scan;
39  import org.apache.hadoop.hbase.client.Durability;
40  import org.apache.hadoop.hbase.exceptions.DeserializationException;
41  import org.apache.hadoop.hbase.exceptions.DoNotRetryIOException;
42  import org.apache.hadoop.hbase.filter.ByteArrayComparable;
43  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
44  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionRequest;
45  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CompactRegionRequest;
46  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.FlushRegionRequest;
47  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetOnlineRegionRequest;
48  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoRequest;
49  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetServerInfoRequest;
50  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetStoreFileRequest;
51  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.MergeRegionsRequest;
52  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionRequest;
53  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.OpenRegionRequest.RegionOpenInfo;
54  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.RollWALWriterRequest;
55  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.SplitRegionRequest;
56  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.StopServerRequest;
57  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
58  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.BulkLoadHFileRequest;
59  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.BulkLoadHFileRequest.FamilyPath;
60  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.Column;
61  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.Condition;
62  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest;
63  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiAction;
64  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiGetRequest;
65  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRequest;
66  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutateRequest;
67  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
68  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.ColumnValue;
69  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.ColumnValue.QualifierValue;
70  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType;
71  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
72  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.CompareType;
73  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
74  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
75  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.AddColumnRequest;
76  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.AssignRegionRequest;
77  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.BalanceRequest;
78  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.CatalogScanRequest;
79  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.CreateTableRequest;
80  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.DeleteColumnRequest;
81  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.DeleteTableRequest;
82  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.DisableTableRequest;
83  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.DispatchMergingRegionsRequest;
84  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.EnableCatalogJanitorRequest;
85  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.EnableTableRequest;
86  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsCatalogJanitorEnabledRequest;
87  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.ModifyColumnRequest;
88  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.ModifyTableRequest;
89  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.MoveRegionRequest;
90  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.OfflineRegionRequest;
91  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.SetBalancerRunningRequest;
92  import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.UnassignRegionRequest;
93  import org.apache.hadoop.hbase.protobuf.generated.MasterMonitorProtos.GetClusterStatusRequest;
94  import org.apache.hadoop.hbase.protobuf.generated.MasterMonitorProtos.GetSchemaAlterStatusRequest;
95  import org.apache.hadoop.hbase.protobuf.generated.MasterMonitorProtos.GetTableDescriptorsRequest;
96  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsMasterRunningRequest;
97  import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdRequest;
98  import org.apache.hadoop.hbase.util.Bytes;
99  import org.apache.hadoop.hbase.util.Pair;
100 import org.apache.hadoop.hbase.util.Triple;
101 
102 import com.google.protobuf.ByteString;
103 
104 /**
105  * Helper utility to build protocol buffer requests,
106  * or build components for protocol buffer requests.
107  */
108 @InterfaceAudience.Private
109 public final class RequestConverter {
110 
111   private RequestConverter() {
112   }
113 
114 // Start utilities for Client
115 
116 /**
117    * Create a new protocol buffer GetRequest to get a row, all columns in a family.
118    * If there is no such row, return the closest row before it.
119    *
120    * @param regionName the name of the region to get
121    * @param row the row to get
122    * @param family the column family to get
123    * should return the immediate row before
124    * @return a protocol buffer GetReuqest
125    */
126   public static GetRequest buildGetRowOrBeforeRequest(
127       final byte[] regionName, final byte[] row, final byte[] family) {
128     GetRequest.Builder builder = GetRequest.newBuilder();
129     RegionSpecifier region = buildRegionSpecifier(
130       RegionSpecifierType.REGION_NAME, regionName);
131     builder.setClosestRowBefore(true);
132     builder.setRegion(region);
133 
134     Column.Builder columnBuilder = Column.newBuilder();
135     columnBuilder.setFamily(ByteString.copyFrom(family));
136     ClientProtos.Get.Builder getBuilder =
137       ClientProtos.Get.newBuilder();
138     getBuilder.setRow(ByteString.copyFrom(row));
139     getBuilder.addColumn(columnBuilder.build());
140     builder.setGet(getBuilder.build());
141     return builder.build();
142   }
143 
144   /**
145    * Create a protocol buffer GetRequest for a client Get
146    *
147    * @param regionName the name of the region to get
148    * @param get the client Get
149    * @return a protocol buffer GetReuqest
150    */
151   public static GetRequest buildGetRequest(final byte[] regionName,
152       final Get get) throws IOException {
153     return buildGetRequest(regionName, get, false);
154   }
155 
156   /**
157    * Create a protocol buffer GetRequest for a client Get
158    *
159    * @param regionName the name of the region to get
160    * @param get the client Get
161    * @param existenceOnly indicate if check row existence only
162    * @return a protocol buffer GetRequest
163    */
164   public static GetRequest buildGetRequest(final byte[] regionName,
165       final Get get, final boolean existenceOnly) throws IOException {
166     GetRequest.Builder builder = GetRequest.newBuilder();
167     RegionSpecifier region = buildRegionSpecifier(
168       RegionSpecifierType.REGION_NAME, regionName);
169     builder.setExistenceOnly(existenceOnly);
170     builder.setRegion(region);
171     builder.setGet(ProtobufUtil.toGet(get));
172     return builder.build();
173   }
174 
175   /**
176    * Create a protocol buffer MultiGetRequest for client Gets All gets are going to be run against
177    * the same region.
178    * @param regionName the name of the region to get from
179    * @param gets the client Gets
180    * @param existenceOnly indicate if check rows existence only
181    * @return a protocol buffer MultiGetRequest
182    */
183   public static MultiGetRequest buildMultiGetRequest(final byte[] regionName, final List<Get> gets,
184       final boolean existenceOnly, final boolean closestRowBefore) throws IOException {
185     MultiGetRequest.Builder builder = MultiGetRequest.newBuilder();
186     RegionSpecifier region = buildRegionSpecifier(RegionSpecifierType.REGION_NAME, regionName);
187     builder.setExistenceOnly(existenceOnly);
188     builder.setClosestRowBefore(closestRowBefore);
189     builder.setRegion(region);
190     for (Get get : gets) {
191       builder.addGet(ProtobufUtil.toGet(get));
192     }
193     return builder.build();
194   }
195 
196   /**
197    * Create a protocol buffer MutateRequest for a client increment
198    *
199    * @param regionName
200    * @param row
201    * @param family
202    * @param qualifier
203    * @param amount
204    * @param durability
205    * @return a mutate request
206    */
207   public static MutateRequest buildMutateRequest(
208       final byte[] regionName, final byte[] row, final byte[] family,
209       final byte [] qualifier, final long amount, final Durability durability) {
210     MutateRequest.Builder builder = MutateRequest.newBuilder();
211     RegionSpecifier region = buildRegionSpecifier(
212       RegionSpecifierType.REGION_NAME, regionName);
213     builder.setRegion(region);
214 
215     MutationProto.Builder mutateBuilder = MutationProto.newBuilder();
216     mutateBuilder.setRow(ByteString.copyFrom(row));
217     mutateBuilder.setMutateType(MutationType.INCREMENT);
218     mutateBuilder.setDurability(ProtobufUtil.toDurability(durability));
219     ColumnValue.Builder columnBuilder = ColumnValue.newBuilder();
220     columnBuilder.setFamily(ByteString.copyFrom(family));
221     QualifierValue.Builder valueBuilder = QualifierValue.newBuilder();
222     valueBuilder.setValue(ByteString.copyFrom(Bytes.toBytes(amount)));
223     valueBuilder.setQualifier(ByteString.copyFrom(qualifier));
224     columnBuilder.addQualifierValue(valueBuilder.build());
225     mutateBuilder.addColumnValue(columnBuilder.build());
226     builder.setMutation(mutateBuilder.build());
227     return builder.build();
228   }
229 
230   /**
231    * Create a protocol buffer MutateRequest for a conditioned put
232    *
233    * @param regionName
234    * @param row
235    * @param family
236    * @param qualifier
237    * @param comparator
238    * @param compareType
239    * @param put
240    * @return a mutate request
241    * @throws IOException
242    */
243   public static MutateRequest buildMutateRequest(
244       final byte[] regionName, final byte[] row, final byte[] family,
245       final byte [] qualifier, final ByteArrayComparable comparator,
246       final CompareType compareType, final Put put) throws IOException {
247     MutateRequest.Builder builder = MutateRequest.newBuilder();
248     RegionSpecifier region = buildRegionSpecifier(
249       RegionSpecifierType.REGION_NAME, regionName);
250     builder.setRegion(region);
251     Condition condition = buildCondition(
252       row, family, qualifier, comparator, compareType);
253     builder.setMutation(ProtobufUtil.toMutation(MutationType.PUT, put));
254     builder.setCondition(condition);
255     return builder.build();
256   }
257 
258   /**
259    * Create a protocol buffer MutateRequest for a conditioned delete
260    *
261    * @param regionName
262    * @param row
263    * @param family
264    * @param qualifier
265    * @param comparator
266    * @param compareType
267    * @param delete
268    * @return a mutate request
269    * @throws IOException
270    */
271   public static MutateRequest buildMutateRequest(
272       final byte[] regionName, final byte[] row, final byte[] family,
273       final byte [] qualifier, final ByteArrayComparable comparator,
274       final CompareType compareType, final Delete delete) throws IOException {
275     MutateRequest.Builder builder = MutateRequest.newBuilder();
276     RegionSpecifier region = buildRegionSpecifier(
277       RegionSpecifierType.REGION_NAME, regionName);
278     builder.setRegion(region);
279     Condition condition = buildCondition(
280       row, family, qualifier, comparator, compareType);
281     builder.setMutation(ProtobufUtil.toMutation(MutationType.DELETE, delete));
282     builder.setCondition(condition);
283     return builder.build();
284   }
285 
286   /**
287    * Create a protocol buffer MutateRequest for a put
288    *
289    * @param regionName
290    * @param put
291    * @return a mutate request
292    * @throws IOException
293    */
294   public static MutateRequest buildMutateRequest(
295       final byte[] regionName, final Put put) throws IOException {
296     MutateRequest.Builder builder = MutateRequest.newBuilder();
297     RegionSpecifier region = buildRegionSpecifier(
298       RegionSpecifierType.REGION_NAME, regionName);
299     builder.setRegion(region);
300     builder.setMutation(ProtobufUtil.toMutation(MutationType.PUT, put));
301     return builder.build();
302   }
303 
304   /**
305    * Create a protocol buffer MutateRequest for an append
306    *
307    * @param regionName
308    * @param append
309    * @return a mutate request
310    * @throws IOException
311    */
312   public static MutateRequest buildMutateRequest(
313       final byte[] regionName, final Append append) throws IOException {
314     MutateRequest.Builder builder = MutateRequest.newBuilder();
315     RegionSpecifier region = buildRegionSpecifier(
316       RegionSpecifierType.REGION_NAME, regionName);
317     builder.setRegion(region);
318     builder.setMutation(ProtobufUtil.toMutation(MutationType.APPEND, append));
319     return builder.build();
320   }
321 
322   /**
323    * Create a protocol buffer MutateRequest for a client increment
324    *
325    * @param regionName
326    * @param increment
327    * @return a mutate request
328    */
329   public static MutateRequest buildMutateRequest(
330       final byte[] regionName, final Increment increment) {
331     MutateRequest.Builder builder = MutateRequest.newBuilder();
332     RegionSpecifier region = buildRegionSpecifier(
333       RegionSpecifierType.REGION_NAME, regionName);
334     builder.setRegion(region);
335     builder.setMutation(ProtobufUtil.toMutation(increment));
336     return builder.build();
337   }
338 
339   /**
340    * Create a protocol buffer MutateRequest for a delete
341    *
342    * @param regionName
343    * @param delete
344    * @return a mutate request
345    * @throws IOException
346    */
347   public static MutateRequest buildMutateRequest(
348       final byte[] regionName, final Delete delete) throws IOException {
349     MutateRequest.Builder builder = MutateRequest.newBuilder();
350     RegionSpecifier region = buildRegionSpecifier(
351       RegionSpecifierType.REGION_NAME, regionName);
352     builder.setRegion(region);
353     builder.setMutation(ProtobufUtil.toMutation(MutationType.DELETE, delete));
354     return builder.build();
355   }
356 
357   /**
358    * Create a protocol buffer MultiRequest for a row mutations
359    *
360    * @param regionName
361    * @param rowMutations
362    * @return a multi request
363    * @throws IOException
364    */
365   public static MultiRequest buildMultiRequest(final byte[] regionName,
366       final RowMutations rowMutations)
367   throws IOException {
368     MultiRequest.Builder builder = getMultiRequestBuilderWithRegionAndAtomicSet(regionName, true);
369     for (Mutation mutation: rowMutations.getMutations()) {
370       MutationType mutateType = null;
371       if (mutation instanceof Put) {
372         mutateType = MutationType.PUT;
373       } else if (mutation instanceof Delete) {
374         mutateType = MutationType.DELETE;
375       } else {
376         throw new DoNotRetryIOException("RowMutations supports only put and delete, not " +
377           mutation.getClass().getName());
378       }
379       MutationProto mp = ProtobufUtil.toMutation(mutateType, mutation);
380       builder.addAction(MultiAction.newBuilder().setMutation(mp).build());
381     }
382     return builder.build();
383   }
384 
385   /**
386    * Create a protocol buffer MultiRequest for row mutations that does not hold data.  Data/Cells
387    * are carried outside of protobuf.  Return references to the Cells in <code>cells</code> param
388    *
389    * @param regionName
390    * @param rowMutations
391    * @param cells Return in here a list of Cells as CellIterable.
392    * @return a multi request minus data
393    * @throws IOException
394    */
395   public static MultiRequest buildNoDataMultiRequest(final byte[] regionName,
396       final RowMutations rowMutations, final List<CellScannable> cells)
397   throws IOException {
398     MultiRequest.Builder builder = getMultiRequestBuilderWithRegionAndAtomicSet(regionName, true);
399     for (Mutation mutation: rowMutations.getMutations()) {
400       MutationType type = null;
401       if (mutation instanceof Put) {
402         type = MutationType.PUT;
403       } else if (mutation instanceof Delete) {
404         type = MutationType.DELETE;
405       } else {
406         throw new DoNotRetryIOException("RowMutations supports only put and delete, not " +
407           mutation.getClass().getName());
408       }
409       MutationProto mp = ProtobufUtil.toMutationNoData(type, mutation);
410       cells.add(mutation);
411       builder.addAction(MultiAction.newBuilder().setMutation(mp).build());
412     }
413     return builder.build();
414   }
415 
416   private static MultiRequest.Builder getMultiRequestBuilderWithRegionAndAtomicSet(final byte [] regionName,
417       final boolean atomic) {
418     MultiRequest.Builder builder = MultiRequest.newBuilder();
419     RegionSpecifier region = buildRegionSpecifier(RegionSpecifierType.REGION_NAME, regionName);
420     builder.setRegion(region);
421     return builder.setAtomic(atomic);
422   }
423 
424   /**
425    * Create a protocol buffer ScanRequest for a client Scan
426    *
427    * @param regionName
428    * @param scan
429    * @param numberOfRows
430    * @param closeScanner
431    * @return a scan request
432    * @throws IOException
433    */
434   public static ScanRequest buildScanRequest(final byte[] regionName,
435       final Scan scan, final int numberOfRows,
436         final boolean closeScanner) throws IOException {
437     ScanRequest.Builder builder = ScanRequest.newBuilder();
438     RegionSpecifier region = buildRegionSpecifier(
439       RegionSpecifierType.REGION_NAME, regionName);
440     builder.setNumberOfRows(numberOfRows);
441     builder.setCloseScanner(closeScanner);
442     builder.setRegion(region);
443     builder.setScan(ProtobufUtil.toScan(scan));
444     return builder.build();
445   }
446 
447   /**
448    * Create a protocol buffer ScanRequest for a scanner id
449    *
450    * @param scannerId
451    * @param numberOfRows
452    * @param closeScanner
453    * @return a scan request
454    */
455   public static ScanRequest buildScanRequest(final long scannerId,
456       final int numberOfRows, final boolean closeScanner) {
457     ScanRequest.Builder builder = ScanRequest.newBuilder();
458     builder.setNumberOfRows(numberOfRows);
459     builder.setCloseScanner(closeScanner);
460     builder.setScannerId(scannerId);
461     return builder.build();
462   }
463   
464   /**
465    * Create a protocol buffer ScanRequest for a scanner id
466    * 
467    * @param scannerId
468    * @param numberOfRows
469    * @param closeScanner
470    * @param nextCallSeq
471    * @return a scan request
472    */
473   public static ScanRequest buildScanRequest(final long scannerId, final int numberOfRows,
474       final boolean closeScanner, final long nextCallSeq) {
475     ScanRequest.Builder builder = ScanRequest.newBuilder();
476     builder.setNumberOfRows(numberOfRows);
477     builder.setCloseScanner(closeScanner);
478     builder.setScannerId(scannerId);
479     builder.setNextCallSeq(nextCallSeq);
480     return builder.build();
481   }
482 
483   /**
484    * Create a protocol buffer bulk load request
485    *
486    * @param familyPaths
487    * @param regionName
488    * @param assignSeqNum
489    * @return a bulk load request
490    */
491   public static BulkLoadHFileRequest buildBulkLoadHFileRequest(
492       final List<Pair<byte[], String>> familyPaths,
493       final byte[] regionName, boolean assignSeqNum) {
494     BulkLoadHFileRequest.Builder builder = BulkLoadHFileRequest.newBuilder();
495     RegionSpecifier region = buildRegionSpecifier(
496       RegionSpecifierType.REGION_NAME, regionName);
497     builder.setRegion(region);
498     FamilyPath.Builder familyPathBuilder = FamilyPath.newBuilder();
499     for (Pair<byte[], String> familyPath: familyPaths) {
500       familyPathBuilder.setFamily(ByteString.copyFrom(familyPath.getFirst()));
501       familyPathBuilder.setPath(familyPath.getSecond());
502       builder.addFamilyPath(familyPathBuilder.build());
503     }
504     builder.setAssignSeqNum(assignSeqNum);
505     return builder.build();
506   }
507 
508   /**
509    * Create a protocol buffer multi request for a list of actions.
510    * RowMutations in the list (if any) will be ignored.
511    *
512    * @param regionName
513    * @param actions
514    * @return a multi request
515    * @throws IOException
516    */
517   public static <R> MultiRequest buildMultiRequest(final byte[] regionName,
518       final List<Action<R>> actions)
519   throws IOException {
520     MultiRequest.Builder builder = getMultiRequestBuilderWithRegionAndAtomicSet(regionName, false);
521     for (Action<R> action: actions) {
522       MultiAction.Builder protoAction = MultiAction.newBuilder();
523       Row row = action.getAction();
524       if (row instanceof Get) {
525         protoAction.setGet(ProtobufUtil.toGet((Get)row));
526       } else if (row instanceof Put) {
527         protoAction.setMutation(ProtobufUtil.toMutation(MutationType.PUT, (Put)row));
528       } else if (row instanceof Delete) {
529         protoAction.setMutation(ProtobufUtil.toMutation(MutationType.DELETE, (Delete)row));
530       } else if (row instanceof Append) {
531         protoAction.setMutation(ProtobufUtil.toMutation(MutationType.APPEND, (Append)row));
532       } else if (row instanceof Increment) {
533         protoAction.setMutation(ProtobufUtil.toMutation((Increment)row));
534       } else if (row instanceof RowMutations) {
535         continue; // ignore RowMutations
536       } else {
537         throw new DoNotRetryIOException(
538           "multi doesn't support " + row.getClass().getName());
539       }
540       builder.addAction(protoAction.build());
541     }
542     return builder.build();
543   }
544 
545   /**
546    * Create a protocol buffer multirequest with NO data for a list of actions (data is carried
547    * otherwise than via protobuf).  This means it just notes attributes, whether to write the
548    * WAL, etc., and the presence in protobuf serves as place holder for the data which is
549    * coming along otherwise.  Note that Get is different.  It does not contain 'data' and is always
550    * carried by protobuf.  We return references to the data by adding them to the passed in
551    * <code>data</code> param.
552    *
553    * RowMutations in the list (if any) will be ignored.
554    *
555    * @param regionName
556    * @param actions
557    * @param cells Place to stuff references to actual data.
558    * @return a multi request that does not carry any data.
559    * @throws IOException
560    */
561   public static <R> MultiRequest buildNoDataMultiRequest(final byte[] regionName,
562       final List<Action<R>> actions, final List<CellScannable> cells)
563   throws IOException {
564     MultiRequest.Builder builder = getMultiRequestBuilderWithRegionAndAtomicSet(regionName, false);
565     for (Action<R> action: actions) {
566       MultiAction.Builder protoAction = MultiAction.newBuilder();
567       Row row = action.getAction();
568       if (row instanceof Get) {
569         // Gets are carried by protobufs.
570         protoAction.setGet(ProtobufUtil.toGet((Get)row));
571       } else if (row instanceof Put) {
572         Put p = (Put)row;
573         cells.add(p);
574         protoAction.setMutation(ProtobufUtil.toMutationNoData(MutationType.PUT, p));
575       } else if (row instanceof Delete) {
576         Delete d = (Delete)row;
577         int size = d.size();
578         // Note that a legitimate Delete may have a size of zero; i.e. a Delete that has nothing
579         // in it but the row to delete.  In this case, the current implementation does not make
580         // a KeyValue to represent a delete-of-all-the-row until we serialize... For such cases
581         // where the size returned is zero, we will send the Delete fully pb'd rather than have
582         // metadata only in the pb and then send the kv along the side in cells.
583         if (size > 0) {
584           cells.add(d);
585           protoAction.setMutation(ProtobufUtil.toMutationNoData(MutationType.DELETE, d));
586         } else {
587           protoAction.setMutation(ProtobufUtil.toMutation(MutationType.DELETE, d));
588         }
589       } else if (row instanceof Append) {
590         Append a = (Append)row;
591         cells.add(a);
592         protoAction.setMutation(ProtobufUtil.toMutationNoData(MutationType.APPEND, a));
593       } else if (row instanceof Increment) {
594         Increment i = (Increment)row;
595         cells.add(i);
596         protoAction.setMutation(ProtobufUtil.toMutationNoData(MutationType.INCREMENT, i));
597       } else if (row instanceof RowMutations) {
598         continue; // ignore RowMutations
599       } else {
600         throw new DoNotRetryIOException("Multi doesn't support " + row.getClass().getName());
601       }
602       builder.addAction(protoAction.build());
603     }
604     return builder.build();
605   }
606 
607 // End utilities for Client
608 //Start utilities for Admin
609 
610   /**
611    * Create a protocol buffer GetRegionInfoRequest for a given region name
612    *
613    * @param regionName the name of the region to get info
614    * @return a protocol buffer GetRegionInfoRequest
615    */
616   public static GetRegionInfoRequest
617       buildGetRegionInfoRequest(final byte[] regionName) {
618     return buildGetRegionInfoRequest(regionName, false);
619   }
620 
621   /**
622    * Create a protocol buffer GetRegionInfoRequest for a given region name
623    *
624    * @param regionName the name of the region to get info
625    * @param includeCompactionState indicate if the compaction state is requested
626    * @return a protocol buffer GetRegionInfoRequest
627    */
628   public static GetRegionInfoRequest
629       buildGetRegionInfoRequest(final byte[] regionName,
630         final boolean includeCompactionState) {
631     GetRegionInfoRequest.Builder builder = GetRegionInfoRequest.newBuilder();
632     RegionSpecifier region = buildRegionSpecifier(
633       RegionSpecifierType.REGION_NAME, regionName);
634     builder.setRegion(region);
635     if (includeCompactionState) {
636       builder.setCompactionState(includeCompactionState);
637     }
638     return builder.build();
639   }
640 
641  /**
642   * Create a protocol buffer GetStoreFileRequest for a given region name
643   *
644   * @param regionName the name of the region to get info
645   * @param family the family to get store file list
646   * @return a protocol buffer GetStoreFileRequest
647   */
648  public static GetStoreFileRequest
649      buildGetStoreFileRequest(final byte[] regionName, final byte[] family) {
650    GetStoreFileRequest.Builder builder = GetStoreFileRequest.newBuilder();
651    RegionSpecifier region = buildRegionSpecifier(
652      RegionSpecifierType.REGION_NAME, regionName);
653    builder.setRegion(region);
654    builder.addFamily(ByteString.copyFrom(family));
655    return builder.build();
656  }
657 
658  /**
659   * Create a protocol buffer GetOnlineRegionRequest
660   *
661   * @return a protocol buffer GetOnlineRegionRequest
662   */
663  public static GetOnlineRegionRequest buildGetOnlineRegionRequest() {
664    return GetOnlineRegionRequest.newBuilder().build();
665  }
666 
667  /**
668   * Create a protocol buffer FlushRegionRequest for a given region name
669   *
670   * @param regionName the name of the region to get info
671   * @return a protocol buffer FlushRegionRequest
672   */
673  public static FlushRegionRequest
674      buildFlushRegionRequest(final byte[] regionName) {
675    FlushRegionRequest.Builder builder = FlushRegionRequest.newBuilder();
676    RegionSpecifier region = buildRegionSpecifier(
677      RegionSpecifierType.REGION_NAME, regionName);
678    builder.setRegion(region);
679    return builder.build();
680  }
681 
682  /**
683   * Create a protocol buffer OpenRegionRequest to open a list of regions
684   *
685   * @param regionOpenInfos info of a list of regions to open
686   * @return a protocol buffer OpenRegionRequest
687   */
688  public static OpenRegionRequest
689      buildOpenRegionRequest(final List<Triple<HRegionInfo, Integer,
690          List<ServerName>>> regionOpenInfos) {
691    OpenRegionRequest.Builder builder = OpenRegionRequest.newBuilder();
692    for (Triple<HRegionInfo, Integer, List<ServerName>> regionOpenInfo: regionOpenInfos) {
693      Integer second = regionOpenInfo.getSecond();
694      int versionOfOfflineNode = second == null ? -1 : second.intValue();
695      builder.addOpenInfo(buildRegionOpenInfo(
696        regionOpenInfo.getFirst(), versionOfOfflineNode, regionOpenInfo.getThird()));
697    }
698    return builder.build();
699  }
700 
701  /**
702   * Create a protocol buffer OpenRegionRequest for a given region
703   *
704   * @param region the region to open
705  * @param versionOfOfflineNode that needs to be present in the offline node
706  * @param favoredNodes
707   * @return a protocol buffer OpenRegionRequest
708   */
709  public static OpenRegionRequest buildOpenRegionRequest(
710      final HRegionInfo region, final int versionOfOfflineNode, List<ServerName> favoredNodes) {
711    OpenRegionRequest.Builder builder = OpenRegionRequest.newBuilder();
712    builder.addOpenInfo(buildRegionOpenInfo(region, versionOfOfflineNode, favoredNodes));
713    return builder.build();
714  }
715 
716  /**
717   * Create a CloseRegionRequest for a given region name
718   *
719   * @param regionName the name of the region to close
720   * @param transitionInZK indicator if to transition in ZK
721   * @return a CloseRegionRequest
722   */
723  public static CloseRegionRequest buildCloseRegionRequest(
724      final byte[] regionName, final boolean transitionInZK) {
725    CloseRegionRequest.Builder builder = CloseRegionRequest.newBuilder();
726    RegionSpecifier region = buildRegionSpecifier(
727      RegionSpecifierType.REGION_NAME, regionName);
728    builder.setRegion(region);
729    builder.setTransitionInZK(transitionInZK);
730    return builder.build();
731  }
732 
733   public static CloseRegionRequest buildCloseRegionRequest(
734     final byte[] regionName, final int versionOfClosingNode,
735     ServerName destinationServer, final boolean transitionInZK) {
736     CloseRegionRequest.Builder builder = CloseRegionRequest.newBuilder();
737     RegionSpecifier region = buildRegionSpecifier(
738       RegionSpecifierType.REGION_NAME, regionName);
739     builder.setRegion(region);
740     builder.setVersionOfClosingNode(versionOfClosingNode);
741     builder.setTransitionInZK(transitionInZK);
742     if (destinationServer != null){
743       builder.setDestinationServer(ProtobufUtil.toServerName( destinationServer) );
744     }
745     return builder.build();
746   }
747 
748  /**
749   * Create a CloseRegionRequest for a given encoded region name
750   *
751   * @param encodedRegionName the name of the region to close
752   * @param transitionInZK indicator if to transition in ZK
753   * @return a CloseRegionRequest
754   */
755  public static CloseRegionRequest
756      buildCloseRegionRequest(final String encodedRegionName,
757        final boolean transitionInZK) {
758    CloseRegionRequest.Builder builder = CloseRegionRequest.newBuilder();
759    RegionSpecifier region = buildRegionSpecifier(
760      RegionSpecifierType.ENCODED_REGION_NAME,
761      Bytes.toBytes(encodedRegionName));
762    builder.setRegion(region);
763    builder.setTransitionInZK(transitionInZK);
764    return builder.build();
765  }
766 
767  /**
768   * Create a SplitRegionRequest for a given region name
769   *
770   * @param regionName the name of the region to split
771   * @param splitPoint the split point
772   * @return a SplitRegionRequest
773   */
774  public static SplitRegionRequest buildSplitRegionRequest(
775      final byte[] regionName, final byte[] splitPoint) {
776    SplitRegionRequest.Builder builder = SplitRegionRequest.newBuilder();
777    RegionSpecifier region = buildRegionSpecifier(
778      RegionSpecifierType.REGION_NAME, regionName);
779    builder.setRegion(region);
780    if (splitPoint != null) {
781      builder.setSplitPoint(ByteString.copyFrom(splitPoint));
782    }
783    return builder.build();
784  }
785 
786   /**
787    * Create a MergeRegionsRequest for the given regions
788    * @param regionA name of region a
789    * @param regionB name of region b
790    * @param forcible true if it is a compulsory merge
791    * @return a MergeRegionsRequest
792    */
793   public static MergeRegionsRequest buildMergeRegionsRequest(
794       final byte[] regionA, final byte[] regionB, final boolean forcible) {
795     MergeRegionsRequest.Builder builder = MergeRegionsRequest.newBuilder();
796     RegionSpecifier regionASpecifier = buildRegionSpecifier(
797         RegionSpecifierType.REGION_NAME, regionA);
798     RegionSpecifier regionBSpecifier = buildRegionSpecifier(
799         RegionSpecifierType.REGION_NAME, regionB);
800     builder.setRegionA(regionASpecifier);
801     builder.setRegionB(regionBSpecifier);
802     builder.setForcible(forcible);
803     return builder.build();
804   }
805 
806  /**
807   * Create a  CompactRegionRequest for a given region name
808   *
809   * @param regionName the name of the region to get info
810   * @param major indicator if it is a major compaction
811   * @return a CompactRegionRequest
812   */
813  public static CompactRegionRequest buildCompactRegionRequest(
814      final byte[] regionName, final boolean major, final byte [] family) {
815    CompactRegionRequest.Builder builder = CompactRegionRequest.newBuilder();
816    RegionSpecifier region = buildRegionSpecifier(
817      RegionSpecifierType.REGION_NAME, regionName);
818    builder.setRegion(region);
819    builder.setMajor(major);
820    if (family != null) {
821      builder.setFamily(ByteString.copyFrom(family));
822    }
823    return builder.build();
824  }
825 
826   /**
827   * Create a new RollWALWriterRequest
828   *
829   * @return a ReplicateWALEntryRequest
830   */
831  public static RollWALWriterRequest buildRollWALWriterRequest() {
832    RollWALWriterRequest.Builder builder = RollWALWriterRequest.newBuilder();
833    return builder.build();
834  }
835 
836  /**
837   * Create a new GetServerInfoRequest
838   *
839   * @return a GetServerInfoRequest
840   */
841  public static GetServerInfoRequest buildGetServerInfoRequest() {
842    GetServerInfoRequest.Builder builder =  GetServerInfoRequest.newBuilder();
843    return builder.build();
844  }
845 
846  /**
847   * Create a new StopServerRequest
848   *
849   * @param reason the reason to stop the server
850   * @return a StopServerRequest
851   */
852  public static StopServerRequest buildStopServerRequest(final String reason) {
853    StopServerRequest.Builder builder = StopServerRequest.newBuilder();
854    builder.setReason(reason);
855    return builder.build();
856  }
857 
858 //End utilities for Admin
859 
860   /**
861    * Convert a byte array to a protocol buffer RegionSpecifier
862    *
863    * @param type the region specifier type
864    * @param value the region specifier byte array value
865    * @return a protocol buffer RegionSpecifier
866    */
867   public static RegionSpecifier buildRegionSpecifier(
868       final RegionSpecifierType type, final byte[] value) {
869     RegionSpecifier.Builder regionBuilder = RegionSpecifier.newBuilder();
870     regionBuilder.setValue(ByteString.copyFrom(value));
871     regionBuilder.setType(type);
872     return regionBuilder.build();
873   }
874 
875   /**
876    * Create a protocol buffer Condition
877    *
878    * @param row
879    * @param family
880    * @param qualifier
881    * @param comparator
882    * @param compareType
883    * @return a Condition
884    * @throws IOException
885    */
886   private static Condition buildCondition(final byte[] row,
887       final byte[] family, final byte [] qualifier,
888       final ByteArrayComparable comparator,
889       final CompareType compareType) throws IOException {
890     Condition.Builder builder = Condition.newBuilder();
891     builder.setRow(ByteString.copyFrom(row));
892     builder.setFamily(ByteString.copyFrom(family));
893     builder.setQualifier(ByteString.copyFrom(qualifier));
894     builder.setComparator(ProtobufUtil.toComparator(comparator));
895     builder.setCompareType(compareType);
896     return builder.build();
897   }
898 
899   /**
900    * Create a protocol buffer AddColumnRequest
901    *
902    * @param tableName
903    * @param column
904    * @return an AddColumnRequest
905    */
906   public static AddColumnRequest buildAddColumnRequest(
907       final byte [] tableName, final HColumnDescriptor column) {
908     AddColumnRequest.Builder builder = AddColumnRequest.newBuilder();
909     builder.setTableName(ByteString.copyFrom(tableName));
910     builder.setColumnFamilies(column.convert());
911     return builder.build();
912   }
913 
914   /**
915    * Create a protocol buffer DeleteColumnRequest
916    *
917    * @param tableName
918    * @param columnName
919    * @return a DeleteColumnRequest
920    */
921   public static DeleteColumnRequest buildDeleteColumnRequest(
922       final byte [] tableName, final byte [] columnName) {
923     DeleteColumnRequest.Builder builder = DeleteColumnRequest.newBuilder();
924     builder.setTableName(ByteString.copyFrom(tableName));
925     builder.setColumnName(ByteString.copyFrom(columnName));
926     return builder.build();
927   }
928 
929   /**
930    * Create a protocol buffer ModifyColumnRequest
931    *
932    * @param tableName
933    * @param column
934    * @return an ModifyColumnRequest
935    */
936   public static ModifyColumnRequest buildModifyColumnRequest(
937       final byte [] tableName, final HColumnDescriptor column) {
938     ModifyColumnRequest.Builder builder = ModifyColumnRequest.newBuilder();
939     builder.setTableName(ByteString.copyFrom(tableName));
940     builder.setColumnFamilies(column.convert());
941     return builder.build();
942   }
943 
944   /**
945    * Create a protocol buffer MoveRegionRequest
946    *
947    * @param encodedRegionName
948    * @param destServerName
949    * @return A MoveRegionRequest
950    * @throws DeserializationException
951    */
952   public static MoveRegionRequest buildMoveRegionRequest(
953       final byte [] encodedRegionName, final byte [] destServerName) throws
954       DeserializationException {
955 	MoveRegionRequest.Builder builder = MoveRegionRequest.newBuilder();
956     builder.setRegion(
957       buildRegionSpecifier(RegionSpecifierType.ENCODED_REGION_NAME,encodedRegionName));
958     if (destServerName != null) {
959       builder.setDestServerName(
960         ProtobufUtil.toServerName(new ServerName(Bytes.toString(destServerName))));
961     }
962     return builder.build();
963   }
964 
965   public static DispatchMergingRegionsRequest buildDispatchMergingRegionsRequest(
966       final byte[] encodedNameOfRegionA, final byte[] encodedNameOfRegionB,
967       final boolean forcible) throws DeserializationException {
968     DispatchMergingRegionsRequest.Builder builder = DispatchMergingRegionsRequest.newBuilder();
969     builder.setRegionA(buildRegionSpecifier(
970         RegionSpecifierType.ENCODED_REGION_NAME, encodedNameOfRegionA));
971     builder.setRegionB(buildRegionSpecifier(
972         RegionSpecifierType.ENCODED_REGION_NAME, encodedNameOfRegionB));
973     builder.setForcible(forcible);
974     return builder.build();
975   }
976 
977   /**
978    * Create a protocol buffer AssignRegionRequest
979    *
980    * @param regionName
981    * @return an AssignRegionRequest
982    */
983   public static AssignRegionRequest buildAssignRegionRequest(final byte [] regionName) {
984     AssignRegionRequest.Builder builder = AssignRegionRequest.newBuilder();
985     builder.setRegion(buildRegionSpecifier(RegionSpecifierType.REGION_NAME,regionName));
986     return builder.build();
987   }
988 
989   /**
990    * Creates a protocol buffer UnassignRegionRequest
991    *
992    * @param regionName
993    * @param force
994    * @return an UnassignRegionRequest
995    */
996   public static UnassignRegionRequest buildUnassignRegionRequest(
997       final byte [] regionName, final boolean force) {
998     UnassignRegionRequest.Builder builder = UnassignRegionRequest.newBuilder();
999     builder.setRegion(buildRegionSpecifier(RegionSpecifierType.REGION_NAME,regionName));
1000     builder.setForce(force);
1001     return builder.build();
1002   }
1003 
1004   /**
1005    * Creates a protocol buffer OfflineRegionRequest
1006    *
1007    * @param regionName
1008    * @return an OfflineRegionRequest
1009    */
1010   public static OfflineRegionRequest buildOfflineRegionRequest(final byte [] regionName) {
1011     OfflineRegionRequest.Builder builder = OfflineRegionRequest.newBuilder();
1012     builder.setRegion(buildRegionSpecifier(RegionSpecifierType.REGION_NAME,regionName));
1013     return builder.build();
1014   }
1015 
1016   /**
1017    * Creates a protocol buffer DeleteTableRequest
1018    *
1019    * @param tableName
1020    * @return a DeleteTableRequest
1021    */
1022   public static DeleteTableRequest buildDeleteTableRequest(final byte [] tableName) {
1023     DeleteTableRequest.Builder builder = DeleteTableRequest.newBuilder();
1024     builder.setTableName(ByteString.copyFrom(tableName));
1025     return builder.build();
1026   }
1027 
1028   /**
1029    * Creates a protocol buffer EnableTableRequest
1030    *
1031    * @param tableName
1032    * @return an EnableTableRequest
1033    */
1034   public static EnableTableRequest buildEnableTableRequest(final byte [] tableName) {
1035     EnableTableRequest.Builder builder = EnableTableRequest.newBuilder();
1036     builder.setTableName(ByteString.copyFrom(tableName));
1037     return builder.build();
1038   }
1039 
1040   /**
1041    * Creates a protocol buffer DisableTableRequest
1042    *
1043    * @param tableName
1044    * @return a DisableTableRequest
1045    */
1046   public static DisableTableRequest buildDisableTableRequest(final byte [] tableName) {
1047     DisableTableRequest.Builder builder = DisableTableRequest.newBuilder();
1048     builder.setTableName(ByteString.copyFrom(tableName));
1049     return builder.build();
1050   }
1051 
1052   /**
1053    * Creates a protocol buffer CreateTableRequest
1054    *
1055    * @param hTableDesc
1056    * @param splitKeys
1057    * @return a CreateTableRequest
1058    */
1059   public static CreateTableRequest buildCreateTableRequest(
1060       final HTableDescriptor hTableDesc, final byte [][] splitKeys) {
1061     CreateTableRequest.Builder builder = CreateTableRequest.newBuilder();
1062     builder.setTableSchema(hTableDesc.convert());
1063     if (splitKeys != null) {
1064       for (byte [] splitKey : splitKeys) {
1065         builder.addSplitKeys(ByteString.copyFrom(splitKey));
1066       }
1067     }
1068     return builder.build();
1069   }
1070 
1071 
1072   /**
1073    * Creates a protocol buffer ModifyTableRequest
1074    *
1075    * @param table
1076    * @param hTableDesc
1077    * @return a ModifyTableRequest
1078    */
1079   public static ModifyTableRequest buildModifyTableRequest(
1080       final byte [] table, final HTableDescriptor hTableDesc) {
1081     ModifyTableRequest.Builder builder = ModifyTableRequest.newBuilder();
1082     builder.setTableName(ByteString.copyFrom(table));
1083     builder.setTableSchema(hTableDesc.convert());
1084     return builder.build();
1085   }
1086 
1087   /**
1088    * Creates a protocol buffer GetSchemaAlterStatusRequest
1089    *
1090    * @param tableName
1091    * @return a GetSchemaAlterStatusRequest
1092    */
1093   public static GetSchemaAlterStatusRequest buildGetSchemaAlterStatusRequest(
1094       final byte [] tableName) {
1095     GetSchemaAlterStatusRequest.Builder builder = GetSchemaAlterStatusRequest.newBuilder();
1096     builder.setTableName(ByteString.copyFrom(tableName));
1097     return builder.build();
1098   }
1099 
1100   /**
1101    * Creates a protocol buffer GetTableDescriptorsRequest
1102    *
1103    * @param tableNames
1104    * @return a GetTableDescriptorsRequest
1105    */
1106   public static GetTableDescriptorsRequest buildGetTableDescriptorsRequest(
1107       final List<String> tableNames) {
1108     GetTableDescriptorsRequest.Builder builder = GetTableDescriptorsRequest.newBuilder();
1109     if (tableNames != null) {
1110       for (String str : tableNames) {
1111         builder.addTableNames(str);
1112       }
1113     }
1114     return builder.build();
1115   }
1116 
1117   /**
1118    * Creates a protocol buffer IsMasterRunningRequest
1119    *
1120    * @return a IsMasterRunningRequest
1121    */
1122   public static IsMasterRunningRequest buildIsMasterRunningRequest() {
1123     return IsMasterRunningRequest.newBuilder().build();
1124   }
1125 
1126   /**
1127    * Creates a protocol buffer BalanceRequest
1128    *
1129    * @return a BalanceRequest
1130    */
1131   public static BalanceRequest buildBalanceRequest() {
1132     return BalanceRequest.newBuilder().build();
1133   }
1134 
1135   /**
1136    * Creates a protocol buffer SetBalancerRunningRequest
1137    *
1138    * @param on
1139    * @param synchronous
1140    * @return a SetBalancerRunningRequest
1141    */
1142   public static SetBalancerRunningRequest buildSetBalancerRunningRequest(boolean on, boolean synchronous) {
1143     return SetBalancerRunningRequest.newBuilder().setOn(on).setSynchronous(synchronous).build();
1144   }
1145 
1146   /**
1147    * Creates a protocol buffer GetClusterStatusRequest
1148    *
1149    * @return A GetClusterStatusRequest
1150    */
1151   public static GetClusterStatusRequest buildGetClusterStatusRequest() {
1152     return GetClusterStatusRequest.newBuilder().build();
1153   }
1154 
1155   /**
1156    * Creates a request for running a catalog scan
1157    * @return A {@link CatalogScanRequest}
1158    */
1159   public static CatalogScanRequest buildCatalogScanRequest() {
1160     return CatalogScanRequest.newBuilder().build();
1161   }
1162 
1163   /**
1164    * Creates a request for enabling/disabling the catalog janitor
1165    * @return A {@link EnableCatalogJanitorRequest}
1166    */
1167   public static EnableCatalogJanitorRequest buildEnableCatalogJanitorRequest(boolean enable) {
1168     return EnableCatalogJanitorRequest.newBuilder().setEnable(enable).build();
1169   }
1170 
1171   /**
1172    * Creates a request for querying the master whether the catalog janitor is enabled
1173    * @return A {@link IsCatalogJanitorEnabledRequest}
1174    */
1175   public static IsCatalogJanitorEnabledRequest buildIsCatalogJanitorEnabledRequest() {
1176     return IsCatalogJanitorEnabledRequest.newBuilder().build();
1177   }
1178 
1179   /**
1180    * Creates a request for querying the master the last flushed sequence Id for a region
1181    * @param regionName
1182    * @return A {@link GetLastFlushedSequenceIdRequest}
1183    */
1184   public static GetLastFlushedSequenceIdRequest buildGetLastFlushedSequenceIdRequest(
1185       byte[] regionName) {
1186     return GetLastFlushedSequenceIdRequest.newBuilder().setRegionName(
1187         ByteString.copyFrom(regionName)).build();
1188   }
1189 
1190   /**
1191    * Create a request to grant user permissions.
1192    *
1193    * @param username the short user name who to grant permissions
1194    * @param table optional table name the permissions apply
1195    * @param family optional column family
1196    * @param qualifier optional qualifier
1197    * @param actions the permissions to be granted
1198    * @return A {@link AccessControlProtos} GrantRequest
1199    */
1200   public static AccessControlProtos.GrantRequest buildGrantRequest(
1201       String username, byte[] table, byte[] family, byte[] qualifier,
1202       AccessControlProtos.Permission.Action... actions) {
1203     AccessControlProtos.Permission.Builder permissionBuilder =
1204         AccessControlProtos.Permission.newBuilder();
1205     for (AccessControlProtos.Permission.Action a : actions) {
1206       permissionBuilder.addAction(a);
1207     }
1208     if (table != null) {
1209       permissionBuilder.setTable(ByteString.copyFrom(table));
1210     }
1211     if (family != null) {
1212       permissionBuilder.setFamily(ByteString.copyFrom(family));
1213     }
1214     if (qualifier != null) {
1215       permissionBuilder.setQualifier(ByteString.copyFrom(qualifier));
1216     }
1217 
1218     return AccessControlProtos.GrantRequest.newBuilder()
1219       .setPermission(
1220           AccessControlProtos.UserPermission.newBuilder()
1221               .setUser(ByteString.copyFromUtf8(username))
1222               .setPermission(permissionBuilder.build())
1223       ).build();
1224   }
1225 
1226   /**
1227    * Create a request to revoke user permissions.
1228    *
1229    * @param username the short user name whose permissions to be revoked
1230    * @param table optional table name the permissions apply
1231    * @param family optional column family
1232    * @param qualifier optional qualifier
1233    * @param actions the permissions to be revoked
1234    * @return A {@link AccessControlProtos} RevokeRequest
1235    */
1236   public static AccessControlProtos.RevokeRequest buildRevokeRequest(
1237       String username, byte[] table, byte[] family, byte[] qualifier,
1238       AccessControlProtos.Permission.Action... actions) {
1239     AccessControlProtos.Permission.Builder permissionBuilder =
1240         AccessControlProtos.Permission.newBuilder();
1241     for (AccessControlProtos.Permission.Action a : actions) {
1242       permissionBuilder.addAction(a);
1243     }
1244     if (table != null) {
1245       permissionBuilder.setTable(ByteString.copyFrom(table));
1246     }
1247     if (family != null) {
1248       permissionBuilder.setFamily(ByteString.copyFrom(family));
1249     }
1250     if (qualifier != null) {
1251       permissionBuilder.setQualifier(ByteString.copyFrom(qualifier));
1252     }
1253 
1254     return AccessControlProtos.RevokeRequest.newBuilder()
1255       .setPermission(
1256           AccessControlProtos.UserPermission.newBuilder()
1257               .setUser(ByteString.copyFromUtf8(username))
1258               .setPermission(permissionBuilder.build())
1259       ).build();
1260   }
1261 
1262   /**
1263    * Create a RegionOpenInfo based on given region info and version of offline node
1264    */
1265   private static RegionOpenInfo buildRegionOpenInfo(
1266       final HRegionInfo region, final int versionOfOfflineNode,
1267       final List<ServerName> favoredNodes) {
1268     RegionOpenInfo.Builder builder = RegionOpenInfo.newBuilder();
1269     builder.setRegion(HRegionInfo.convert(region));
1270     if (versionOfOfflineNode >= 0) {
1271       builder.setVersionOfOfflineNode(versionOfOfflineNode);
1272     }
1273     if (favoredNodes != null) {
1274       for (ServerName server : favoredNodes) {
1275         builder.addFavoredNodes(ProtobufUtil.toServerName(server));
1276       }
1277     }
1278     return builder.build();
1279   }
1280 }