View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.master;
21  
22  import java.io.IOException;
23  import java.util.List;
24  import java.util.Set;
25  
26  import org.apache.commons.lang.ClassUtils;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.conf.Configuration;
30  import org.apache.hadoop.hbase.ClusterStatus;
31  import org.apache.hadoop.hbase.Coprocessor;
32  import org.apache.hadoop.hbase.HColumnDescriptor;
33  import org.apache.hadoop.hbase.HRegionInfo;
34  import org.apache.hadoop.hbase.HTableDescriptor;
35  import org.apache.hadoop.hbase.NamespaceDescriptor;
36  import org.apache.hadoop.hbase.ProcedureInfo;
37  import org.apache.hadoop.hbase.ServerName;
38  import org.apache.hadoop.hbase.TableName;
39  import org.apache.hadoop.hbase.classification.InterfaceAudience;
40  import org.apache.hadoop.hbase.client.Admin;
41  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
42  import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
43  import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
44  import org.apache.hadoop.hbase.coprocessor.MasterObserver;
45  import org.apache.hadoop.hbase.coprocessor.MetricsCoprocessor;
46  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
47  import org.apache.hadoop.hbase.ipc.RpcServer;
48  import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
49  import org.apache.hadoop.hbase.metrics.MetricRegistry;
50  import org.apache.hadoop.hbase.net.Address;
51  import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
52  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
53  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
54  import org.apache.hadoop.hbase.security.User;
55  
56  /**
57   * Provides the coprocessor framework and environment for master oriented
58   * operations.  {@link HMaster} interacts with the loaded coprocessors
59   * through this class.
60   */
61  @InterfaceAudience.Private
62  public class MasterCoprocessorHost
63      extends CoprocessorHost<MasterCoprocessorHost.MasterEnvironment> {
64  
65    private static final Log LOG = LogFactory.getLog(MasterCoprocessorHost.class);
66  
67    /**
68     * Coprocessor environment extension providing access to master related
69     * services.
70     */
71    static class MasterEnvironment extends CoprocessorHost.Environment
72        implements MasterCoprocessorEnvironment {
73      private final MasterServices masterServices;
74      private final MetricRegistry metricRegistry;
75      private final boolean supportGroupCPs;
76  
77      public MasterEnvironment(final Class<?> implClass, final Coprocessor impl,
78          final int priority, final int seq, final Configuration conf,
79          final MasterServices services) {
80        super(impl, priority, seq, conf);
81        this.masterServices = services;
82        this.metricRegistry =
83            MetricsCoprocessor.createRegistryForMasterCoprocessor(implClass.getName());
84        supportGroupCPs = !useLegacyMethod(impl.getClass(),
85            "preBalanceRSGroup", ObserverContext.class, String.class);
86      }
87  
88      @Override
89      public MasterServices getMasterServices() {
90        return masterServices;
91      }
92  
93      @Override
94      public MetricRegistry getMetricRegistryForMaster() {
95        return metricRegistry;
96      }
97  
98      @Override
99      protected void shutdown() {
100       super.shutdown();
101       MetricsCoprocessor.removeRegistry(this.metricRegistry);
102     }
103   }
104 
105   private MasterServices masterServices;
106 
107   public MasterCoprocessorHost(final MasterServices services, final Configuration conf) {
108     super(services);
109     this.conf = conf;
110     this.masterServices = services;
111     // Log the state of coprocessor loading here; should appear only once or
112     // twice in the daemon log, depending on HBase version, because there is
113     // only one MasterCoprocessorHost instance in the master process
114     boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
115       DEFAULT_COPROCESSORS_ENABLED);
116     LOG.info("System coprocessor loading is " + (coprocessorsEnabled ? "enabled" : "disabled"));
117     loadSystemCoprocessors(conf, MASTER_COPROCESSOR_CONF_KEY);
118   }
119 
120   @Override
121   public MasterEnvironment createEnvironment(final Class<?> implClass,
122       final Coprocessor instance, final int priority, final int seq,
123       final Configuration conf) {
124     for (Object itf : ClassUtils.getAllInterfaces(implClass)) {
125       Class<?> c = (Class<?>) itf;
126       if (CoprocessorService.class.isAssignableFrom(c)) {
127         masterServices.registerService(((CoprocessorService)instance).getService());
128       }
129     }
130     return new MasterEnvironment(implClass, instance, priority, seq, conf,
131         masterServices);
132   }
133 
134   public boolean preCreateNamespace(final NamespaceDescriptor ns) throws IOException {
135     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
136       @Override
137       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
138           throws IOException {
139         oserver.preCreateNamespace(ctx, ns);
140       }
141     });
142   }
143 
144   public void postCreateNamespace(final NamespaceDescriptor ns) throws IOException {
145     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
146       @Override
147       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
148           throws IOException {
149         oserver.postCreateNamespace(ctx, ns);
150       }
151     });
152   }
153 
154   public boolean preDeleteNamespace(final String namespaceName) throws IOException {
155     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
156       @Override
157       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
158           throws IOException {
159         oserver.preDeleteNamespace(ctx, namespaceName);
160       }
161     });
162   }
163 
164   public void postDeleteNamespace(final String namespaceName) throws IOException {
165     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
166       @Override
167       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
168           throws IOException {
169         oserver.postDeleteNamespace(ctx, namespaceName);
170       }
171     });
172   }
173 
174   public boolean preModifyNamespace(final NamespaceDescriptor ns) throws IOException {
175     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
176       @Override
177       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
178           throws IOException {
179         oserver.preModifyNamespace(ctx, ns);
180       }
181     });
182   }
183 
184   public void postModifyNamespace(final NamespaceDescriptor ns) throws IOException {
185     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
186       @Override
187       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
188           throws IOException {
189         oserver.postModifyNamespace(ctx, ns);
190       }
191     });
192   }
193 
194   public void preGetNamespaceDescriptor(final String namespaceName)
195       throws IOException {
196     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
197       @Override
198       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
199           throws IOException {
200         oserver.preGetNamespaceDescriptor(ctx, namespaceName);
201       }
202     });
203   }
204 
205   public void postGetNamespaceDescriptor(final NamespaceDescriptor ns)
206       throws IOException {
207     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
208       @Override
209       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
210           throws IOException {
211         oserver.postGetNamespaceDescriptor(ctx, ns);
212       }
213     });
214   }
215 
216   public boolean preListNamespaces(final List<String> namespaces) throws IOException {
217     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
218       @Override
219       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
220           throws IOException {
221         oserver.preListNamespaces(ctx, namespaces);
222       }
223     });
224   }
225 
226   public boolean postListNamespaces(final List<String> namespaces) throws IOException {
227     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
228       @Override
229       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
230           throws IOException {
231         oserver.postListNamespaces(ctx, namespaces);
232       }
233     });
234   }
235 
236   public boolean preListNamespaceDescriptors(final List<NamespaceDescriptor> descriptors)
237       throws IOException {
238     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
239       @Override
240       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
241           throws IOException {
242         oserver.preListNamespaceDescriptors(ctx, descriptors);
243       }
244     });
245   }
246 
247   public void postListNamespaceDescriptors(final List<NamespaceDescriptor> descriptors)
248       throws IOException {
249     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
250       @Override
251       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
252           throws IOException {
253         oserver.postListNamespaceDescriptors(ctx, descriptors);
254       }
255     });
256   }
257 
258   /* Implementation of hooks for invoking MasterObservers */
259 
260   public void preCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
261       throws IOException {
262     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
263       @Override
264       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
265           throws IOException {
266         oserver.preCreateTable(ctx, htd, regions);
267       }
268     });
269   }
270 
271   public void postCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
272       throws IOException {
273     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
274       @Override
275       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
276           throws IOException {
277         oserver.postCreateTable(ctx, htd, regions);
278       }
279     });
280   }
281 
282   public void preCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions,
283       final User user) throws IOException {
284     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
285       @Override
286       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
287           throws IOException {
288         oserver.preCreateTableHandler(ctx, htd, regions);
289       }
290     });
291   }
292 
293   public void postCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions,
294       final User user) throws IOException {
295     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
296       @Override
297       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
298           throws IOException {
299         oserver.postCreateTableHandler(ctx, htd, regions);
300       }
301     });
302   }
303 
304   public void preDeleteTable(final TableName tableName) throws IOException {
305     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
306       @Override
307       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
308           throws IOException {
309         oserver.preDeleteTable(ctx, tableName);
310       }
311     });
312   }
313 
314   public void postDeleteTable(final TableName tableName) throws IOException {
315     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
316       @Override
317       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
318           throws IOException {
319         oserver.postDeleteTable(ctx, tableName);
320       }
321     });
322   }
323 
324   public void preDeleteTableHandler(final TableName tableName, final User user) throws IOException {
325     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
326       @Override
327       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
328           throws IOException {
329         oserver.preDeleteTableHandler(ctx, tableName);
330       }
331     });
332   }
333 
334   public void postDeleteTableHandler(final TableName tableName, final User user)
335       throws IOException {
336     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
337       @Override
338       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
339           throws IOException {
340         oserver.postDeleteTableHandler(ctx, tableName);
341       }
342     });
343   }
344 
345   public void preTruncateTable(final TableName tableName) throws IOException {
346     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
347       @Override
348       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
349           throws IOException {
350         oserver.preTruncateTable(ctx, tableName);
351       }
352     });
353   }
354 
355   public void postTruncateTable(final TableName tableName) throws IOException {
356     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
357       @Override
358       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
359           throws IOException {
360         oserver.postTruncateTable(ctx, tableName);
361       }
362     });
363   }
364 
365   public void preTruncateTableHandler(final TableName tableName, final User user)
366       throws IOException {
367     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
368       @Override
369       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
370           throws IOException {
371         oserver.preTruncateTableHandler(ctx, tableName);
372       }
373     });
374   }
375 
376   public void postTruncateTableHandler(final TableName tableName, final User user)
377       throws IOException {
378     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
379       @Override
380       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
381           throws IOException {
382         oserver.postTruncateTableHandler(ctx, tableName);
383       }
384     });
385   }
386 
387   public void preModifyTable(final TableName tableName, final HTableDescriptor htd)
388       throws IOException {
389     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
390       @Override
391       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
392           throws IOException {
393         oserver.preModifyTable(ctx, tableName, htd);
394       }
395     });
396   }
397 
398   public void postModifyTable(final TableName tableName, final HTableDescriptor htd)
399       throws IOException {
400     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
401       @Override
402       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
403           throws IOException {
404         oserver.postModifyTable(ctx, tableName, htd);
405       }
406     });
407   }
408 
409   public void preModifyTableHandler(final TableName tableName, final HTableDescriptor htd,
410                                     final User user)
411       throws IOException {
412     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
413       @Override
414       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
415           throws IOException {
416         oserver.preModifyTableHandler(ctx, tableName, htd);
417       }
418     });
419   }
420 
421   public void postModifyTableHandler(final TableName tableName, final HTableDescriptor htd,
422                                      final User user)
423       throws IOException {
424     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
425       @Override
426       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
427           throws IOException {
428         oserver.postModifyTableHandler(ctx, tableName, htd);
429       }
430     });
431   }
432 
433   public boolean preAddColumn(final TableName tableName, final HColumnDescriptor column)
434       throws IOException {
435     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
436       @Override
437       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
438           throws IOException {
439         oserver.preAddColumn(ctx, tableName, column);
440       }
441     });
442   }
443 
444   public void postAddColumn(final TableName tableName, final HColumnDescriptor column)
445       throws IOException {
446     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
447       @Override
448       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
449           throws IOException {
450         oserver.postAddColumn(ctx, tableName, column);
451       }
452     });
453   }
454 
455   public boolean preAddColumnHandler(final TableName tableName, final HColumnDescriptor column,
456                                      final User user)
457       throws IOException {
458     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
459       @Override
460       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
461           throws IOException {
462         oserver.preAddColumnHandler(ctx, tableName, column);
463       }
464     });
465   }
466 
467   public void postAddColumnHandler(final TableName tableName, final HColumnDescriptor column,
468                                    final User user)
469       throws IOException {
470     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
471       @Override
472       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
473           throws IOException {
474         oserver.postAddColumnHandler(ctx, tableName, column);
475       }
476     });
477   }
478 
479   public boolean preModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
480       throws IOException {
481     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
482       @Override
483       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
484           throws IOException {
485         oserver.preModifyColumn(ctx, tableName, descriptor);
486       }
487     });
488   }
489 
490   public void postModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
491       throws IOException {
492     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
493       @Override
494       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
495           throws IOException {
496         oserver.postModifyColumn(ctx, tableName, descriptor);
497       }
498     });
499   }
500 
501   public boolean preModifyColumnHandler(final TableName tableName,
502       final HColumnDescriptor descriptor, final User user) throws IOException {
503     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
504       @Override
505       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
506           throws IOException {
507         oserver.preModifyColumnHandler(ctx, tableName, descriptor);
508       }
509     });
510   }
511 
512   public void postModifyColumnHandler(final TableName tableName,
513       final HColumnDescriptor descriptor, final User user) throws IOException {
514     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
515       @Override
516       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
517           throws IOException {
518         oserver.postModifyColumnHandler(ctx, tableName, descriptor);
519       }
520     });
521   }
522 
523   public boolean preDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
524     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
525       @Override
526       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
527           throws IOException {
528         oserver.preDeleteColumn(ctx, tableName, c);
529       }
530     });
531   }
532 
533   public void postDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
534     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
535       @Override
536       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
537           throws IOException {
538         oserver.postDeleteColumn(ctx, tableName, c);
539       }
540     });
541   }
542 
543   public boolean preDeleteColumnHandler(final TableName tableName, final byte[] c,
544                                         final User user)
545       throws IOException {
546     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
547       @Override
548       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
549           throws IOException {
550         oserver.preDeleteColumnHandler(ctx, tableName, c);
551       }
552     });
553   }
554 
555   public void postDeleteColumnHandler(final TableName tableName, final byte[] c,
556                                       final User user)
557       throws IOException {
558     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
559       @Override
560       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
561           throws IOException {
562         oserver.postDeleteColumnHandler(ctx, tableName, c);
563       }
564     });
565   }
566 
567   public void preEnableTable(final TableName tableName) throws IOException {
568     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
569       @Override
570       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
571           throws IOException {
572         oserver.preEnableTable(ctx, tableName);
573       }
574     });
575   }
576 
577   public void postEnableTable(final TableName tableName) throws IOException {
578     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
579       @Override
580       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
581           throws IOException {
582         oserver.postEnableTable(ctx, tableName);
583       }
584     });
585   }
586 
587   public void preEnableTableHandler(final TableName tableName, final User user) throws IOException {
588     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
589       @Override
590       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
591           throws IOException {
592         oserver.preEnableTableHandler(ctx, tableName);
593       }
594     });
595   }
596 
597   public void postEnableTableHandler(final TableName tableName, final User user)
598       throws IOException {
599     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
600       @Override
601       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
602           throws IOException {
603         oserver.postEnableTableHandler(ctx, tableName);
604       }
605     });
606   }
607 
608   public void preDisableTable(final TableName tableName) throws IOException {
609     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
610       @Override
611       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
612           throws IOException {
613         oserver.preDisableTable(ctx, tableName);
614       }
615     });
616   }
617 
618   public void postDisableTable(final TableName tableName) throws IOException {
619     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
620       @Override
621       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
622           throws IOException {
623         oserver.postDisableTable(ctx, tableName);
624       }
625     });
626   }
627 
628   public void preDisableTableHandler(final TableName tableName, final User user)
629       throws IOException {
630     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
631       @Override
632       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
633           throws IOException {
634         oserver.preDisableTableHandler(ctx, tableName);
635       }
636     });
637   }
638 
639   public void postDisableTableHandler(final TableName tableName, final User user)
640       throws IOException {
641     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation(user) {
642       @Override
643       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
644           throws IOException {
645         oserver.postDisableTableHandler(ctx, tableName);
646       }
647     });
648   }
649 
650   public boolean preAbortProcedure(
651       final ProcedureExecutor<MasterProcedureEnv> procEnv,
652       final long procId) throws IOException {
653     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
654       @Override
655       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
656           throws IOException {
657         oserver.preAbortProcedure(ctx, procEnv, procId);
658       }
659     });
660   }
661 
662   public void postAbortProcedure() throws IOException {
663     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
664       @Override
665       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
666           throws IOException {
667         oserver.postAbortProcedure(ctx);
668       }
669     });
670   }
671 
672   public boolean preListProcedures() throws IOException {
673     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
674       @Override
675       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
676           throws IOException {
677         oserver.preListProcedures(ctx);
678       }
679     });
680   }
681 
682   public void postListProcedures(final List<ProcedureInfo> procInfoList) throws IOException {
683     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
684       @Override
685       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
686           throws IOException {
687         oserver.postListProcedures(ctx, procInfoList);
688       }
689     });
690   }
691 
692   public boolean preMove(final HRegionInfo region, final ServerName srcServer,
693       final ServerName destServer) throws IOException {
694     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
695       @Override
696       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
697           throws IOException {
698         oserver.preMove(ctx, region, srcServer, destServer);
699       }
700     });
701   }
702 
703   public void postMove(final HRegionInfo region, final ServerName srcServer,
704       final ServerName destServer) throws IOException {
705     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
706       @Override
707       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
708           throws IOException {
709         oserver.postMove(ctx, region, srcServer, destServer);
710       }
711     });
712   }
713 
714   public boolean preAssign(final HRegionInfo regionInfo) throws IOException {
715     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
716       @Override
717       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
718           throws IOException {
719         oserver.preAssign(ctx, regionInfo);
720       }
721     });
722   }
723 
724   public void postAssign(final HRegionInfo regionInfo) throws IOException {
725     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
726       @Override
727       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
728           throws IOException {
729         oserver.postAssign(ctx, regionInfo);
730       }
731     });
732   }
733 
734   public boolean preUnassign(final HRegionInfo regionInfo, final boolean force)
735       throws IOException {
736     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
737       @Override
738       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
739           throws IOException {
740         oserver.preUnassign(ctx, regionInfo, force);
741       }
742     });
743   }
744 
745   public void postUnassign(final HRegionInfo regionInfo, final boolean force) throws IOException {
746     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
747       @Override
748       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
749           throws IOException {
750         oserver.postUnassign(ctx, regionInfo, force);
751       }
752     });
753   }
754 
755   public void preRegionOffline(final HRegionInfo regionInfo) throws IOException {
756     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
757       @Override
758       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
759           throws IOException {
760         oserver.preRegionOffline(ctx, regionInfo);
761       }
762     });
763   }
764 
765   public void postRegionOffline(final HRegionInfo regionInfo) throws IOException {
766     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
767       @Override
768       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
769           throws IOException {
770         oserver.postRegionOffline(ctx, regionInfo);
771       }
772     });
773   }
774 
775   public void preDispatchMerge(final HRegionInfo regionInfoA, final HRegionInfo regionInfoB)
776       throws IOException {
777     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
778       @Override
779       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
780           throws IOException {
781         oserver.preDispatchMerge(ctx, regionInfoA, regionInfoB);
782       }
783     });
784   }
785 
786   public void postDispatchMerge(final HRegionInfo regionInfoA, final HRegionInfo regionInfoB)
787       throws IOException {
788     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
789       @Override
790       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
791           throws IOException {
792         oserver.postDispatchMerge(ctx, regionInfoA, regionInfoB);
793       }
794     });
795   }
796 
797   public boolean preBalance() throws IOException {
798     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
799       @Override
800       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
801           throws IOException {
802         oserver.preBalance(ctx);
803       }
804     });
805   }
806 
807   public void postBalance(final List<RegionPlan> plans) throws IOException {
808     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
809       @Override
810       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
811           throws IOException {
812         oserver.postBalance(ctx, plans);
813       }
814     });
815   }
816 
817   public boolean preSetSplitOrMergeEnabled(final boolean newValue,
818       final Admin.MasterSwitchType switchType) throws IOException {
819     return execOperation(coprocessors.isEmpty() ? null :
820       new CoprocessorOperation() {
821       @Override
822       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
823           throws IOException {
824         oserver.preSetSplitOrMergeEnabled(ctx, newValue, switchType);
825       }
826     });
827   }
828 
829   public void postSetSplitOrMergeEnabled(final boolean newValue,
830       final Admin.MasterSwitchType switchType) throws IOException {
831     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
832       @Override
833       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
834           throws IOException {
835         oserver.postSetSplitOrMergeEnabled(ctx, newValue, switchType);
836       }
837     });
838   }
839 
840   public boolean preBalanceSwitch(final boolean b) throws IOException {
841     return execOperationWithResult(b, coprocessors.isEmpty() ? null :
842         new CoprocessorOperationWithResult<Boolean>() {
843       @Override
844       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
845           throws IOException {
846         setResult(oserver.preBalanceSwitch(ctx, getResult()));
847       }
848     });
849   }
850 
851   public void postBalanceSwitch(final boolean oldValue, final boolean newValue)
852       throws IOException {
853     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
854       @Override
855       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
856           throws IOException {
857         oserver.postBalanceSwitch(ctx, oldValue, newValue);
858       }
859     });
860   }
861 
862   public void preShutdown() throws IOException {
863     // While stopping the cluster all coprocessors method should be executed first then the
864     // coprocessor should be cleaned up.
865     execShutdown(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
866       @Override
867       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
868           throws IOException {
869         oserver.preShutdown(ctx);
870       }
871       @Override
872       public void postEnvCall(MasterEnvironment env) {
873         // invoke coprocessor stop method
874         shutdown(env);
875       }
876     });
877   }
878 
879   public void preStopMaster() throws IOException {
880     // While stopping master all coprocessors method should be executed first then the coprocessor
881     // environment should be cleaned up.
882     execShutdown(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
883       @Override
884       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
885           throws IOException {
886         oserver.preStopMaster(ctx);
887       }
888       @Override
889       public void postEnvCall(MasterEnvironment env) {
890         // invoke coprocessor stop method
891         shutdown(env);
892       }
893     });
894   }
895 
896   public void preMasterInitialization() throws IOException {
897     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
898       @Override
899       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
900           throws IOException {
901         oserver.preMasterInitialization(ctx);
902       }
903     });
904   }
905 
906   public void postStartMaster() throws IOException {
907     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
908       @Override
909       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
910           throws IOException {
911         oserver.postStartMaster(ctx);
912       }
913     });
914   }
915 
916   public void preSnapshot(final SnapshotDescription snapshot,
917       final HTableDescriptor hTableDescriptor) throws IOException {
918     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
919       @Override
920       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
921           throws IOException {
922         oserver.preSnapshot(ctx, snapshot, hTableDescriptor);
923       }
924     });
925   }
926 
927   public void postSnapshot(final SnapshotDescription snapshot,
928       final HTableDescriptor hTableDescriptor) throws IOException {
929     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
930       @Override
931       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
932           throws IOException {
933         oserver.postSnapshot(ctx, snapshot, hTableDescriptor);
934       }
935     });
936   }
937 
938   public void preListSnapshot(final SnapshotDescription snapshot) throws IOException {
939     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
940       @Override
941       public void call(MasterObserver observer, ObserverContext<MasterCoprocessorEnvironment> ctx)
942           throws IOException {
943         observer.preListSnapshot(ctx, snapshot);
944       }
945     });
946   }
947 
948   public void postListSnapshot(final SnapshotDescription snapshot) throws IOException {
949     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
950       @Override
951       public void call(MasterObserver observer, ObserverContext<MasterCoprocessorEnvironment> ctx)
952           throws IOException {
953         observer.postListSnapshot(ctx, snapshot);
954       }
955     });
956   }
957 
958   public void preCloneSnapshot(final SnapshotDescription snapshot,
959       final HTableDescriptor hTableDescriptor) throws IOException {
960     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
961       @Override
962       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
963           throws IOException {
964         oserver.preCloneSnapshot(ctx, snapshot, hTableDescriptor);
965       }
966     });
967   }
968 
969   public void postCloneSnapshot(final SnapshotDescription snapshot,
970       final HTableDescriptor hTableDescriptor) throws IOException {
971     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
972       @Override
973       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
974           throws IOException {
975         oserver.postCloneSnapshot(ctx, snapshot, hTableDescriptor);
976       }
977     });
978   }
979 
980   public void preRestoreSnapshot(final SnapshotDescription snapshot,
981       final HTableDescriptor hTableDescriptor) throws IOException {
982     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
983       @Override
984       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
985           throws IOException {
986         oserver.preRestoreSnapshot(ctx, snapshot, hTableDescriptor);
987       }
988     });
989   }
990 
991   public void postRestoreSnapshot(final SnapshotDescription snapshot,
992       final HTableDescriptor hTableDescriptor) throws IOException {
993     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
994       @Override
995       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
996           throws IOException {
997         oserver.postRestoreSnapshot(ctx, snapshot, hTableDescriptor);
998       }
999     });
1000   }
1001 
1002   public void preDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
1003     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1004       @Override
1005       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1006           throws IOException {
1007         oserver.preDeleteSnapshot(ctx, snapshot);
1008       }
1009     });
1010   }
1011 
1012   public void postDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
1013     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1014       @Override
1015       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1016           throws IOException {
1017         oserver.postDeleteSnapshot(ctx, snapshot);
1018       }
1019     });
1020   }
1021 
1022   @Deprecated
1023   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
1024     final List<HTableDescriptor> descriptors) throws IOException {
1025     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1026       @Override
1027       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1028           throws IOException {
1029         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors);
1030       }
1031     });
1032   }
1033 
1034   @Deprecated
1035   public void postGetTableDescriptors(final List<HTableDescriptor> descriptors)
1036       throws IOException {
1037     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1038       @Override
1039       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1040           throws IOException {
1041         oserver.postGetTableDescriptors(ctx, descriptors);
1042       }
1043     });
1044   }
1045 
1046   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
1047       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
1048     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1049       @Override
1050       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1051           throws IOException {
1052         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
1053       }
1054     });
1055   }
1056 
1057   public void postGetTableDescriptors(final List<TableName> tableNamesList,
1058       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
1059     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1060       @Override
1061       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1062           throws IOException {
1063         oserver.postGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
1064       }
1065     });
1066   }
1067 
1068   public boolean preGetTableNames(final List<HTableDescriptor> descriptors,
1069       final String regex) throws IOException {
1070     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1071       @Override
1072       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1073           throws IOException {
1074         oserver.preGetTableNames(ctx, descriptors, regex);
1075       }
1076     });
1077   }
1078 
1079   public void postGetTableNames(final List<HTableDescriptor> descriptors,
1080       final String regex) throws IOException {
1081     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1082       @Override
1083       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1084           throws IOException {
1085         oserver.postGetTableNames(ctx, descriptors, regex);
1086       }
1087     });
1088   }
1089 
1090   public void preTableFlush(final TableName tableName) throws IOException {
1091     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1092       @Override
1093       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1094           throws IOException {
1095         oserver.preTableFlush(ctx, tableName);
1096       }
1097     });
1098   }
1099 
1100   public void postTableFlush(final TableName tableName) throws IOException {
1101     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1102       @Override
1103       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1104           throws IOException {
1105         oserver.postTableFlush(ctx, tableName);
1106       }
1107     });
1108   }
1109 
1110   public void preSetUserQuota(final String user, final Quotas quotas) throws IOException {
1111     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1112       @Override
1113       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1114           throws IOException {
1115         oserver.preSetUserQuota(ctx, user, quotas);
1116       }
1117     });
1118   }
1119 
1120   public void postSetUserQuota(final String user, final Quotas quotas) throws IOException {
1121     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1122       @Override
1123       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1124           throws IOException {
1125         oserver.postSetUserQuota(ctx, user, quotas);
1126       }
1127     });
1128   }
1129 
1130   public void preSetUserQuota(final String user, final TableName table, final Quotas quotas)
1131       throws IOException {
1132     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1133       @Override
1134       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1135           throws IOException {
1136         oserver.preSetUserQuota(ctx, user, table, quotas);
1137       }
1138     });
1139   }
1140 
1141   public void postSetUserQuota(final String user, final TableName table, final Quotas quotas)
1142       throws IOException {
1143     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1144       @Override
1145       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1146           throws IOException {
1147         oserver.postSetUserQuota(ctx, user, table, quotas);
1148       }
1149     });
1150   }
1151 
1152   public void preSetUserQuota(final String user, final String namespace, final Quotas quotas)
1153       throws IOException {
1154     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1155       @Override
1156       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1157           throws IOException {
1158         oserver.preSetUserQuota(ctx, user, namespace, quotas);
1159       }
1160     });
1161   }
1162 
1163   public void postSetUserQuota(final String user, final String namespace, final Quotas quotas)
1164       throws IOException {
1165     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1166       @Override
1167       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1168           throws IOException {
1169         oserver.postSetUserQuota(ctx, user, namespace, quotas);
1170       }
1171     });
1172   }
1173 
1174   public void preSetTableQuota(final TableName table, final Quotas quotas) throws IOException {
1175     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1176       @Override
1177       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1178           throws IOException {
1179         oserver.preSetTableQuota(ctx, table, quotas);
1180       }
1181     });
1182   }
1183 
1184   public void postSetTableQuota(final TableName table, final Quotas quotas) throws IOException {
1185     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1186       @Override
1187       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1188           throws IOException {
1189         oserver.postSetTableQuota(ctx, table, quotas);
1190       }
1191     });
1192   }
1193 
1194   public void preSetNamespaceQuota(final String namespace, final Quotas quotas) throws IOException {
1195     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1196       @Override
1197       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1198           throws IOException {
1199         oserver.preSetNamespaceQuota(ctx, namespace, quotas);
1200       }
1201     });
1202   }
1203 
1204   public void postSetNamespaceQuota(final String namespace, final Quotas quotas)
1205       throws IOException {
1206     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1207       @Override
1208       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1209           throws IOException {
1210         oserver.postSetNamespaceQuota(ctx, namespace, quotas);
1211       }
1212     });
1213   }
1214 
1215   public void preGetClusterStatus() throws IOException {
1216     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1217       @Override
1218       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1219               throws IOException {
1220         oserver.preGetClusterStatus(ctx);
1221       }
1222     });
1223   }
1224 
1225   public void postGetClusterStatus(final ClusterStatus status) throws IOException {
1226     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1227       @Override
1228       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1229               throws IOException {
1230         oserver.postGetClusterStatus(ctx, status);
1231       }
1232     });
1233   }
1234 
1235   public void preClearDeadServers() throws IOException {
1236     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1237       @Override
1238       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1239               throws IOException {
1240         oserver.preClearDeadServers(ctx);
1241       }
1242     });
1243   }
1244 
1245   public void postClearDeadServers(final List<ServerName> servers,
1246       final List<ServerName> notClearedServers) throws IOException {
1247     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1248       @Override
1249       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1250               throws IOException {
1251         oserver.postClearDeadServers(ctx, servers, notClearedServers);
1252       }
1253     });
1254   }
1255 
1256   public void preMoveServers(final Set<Address> servers, final String targetGroup)
1257       throws IOException {
1258     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1259       @Override
1260       public void call(MasterObserver oserver,
1261           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1262         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1263           oserver.preMoveServers(ctx, servers, targetGroup);
1264         }
1265       }
1266     });
1267   }
1268 
1269   public void postMoveServers(final Set<Address> servers, final String targetGroup)
1270       throws IOException {
1271     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1272       @Override
1273       public void call(MasterObserver oserver,
1274           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1275         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1276           oserver.postMoveServers(ctx, servers, targetGroup);
1277         }
1278       }
1279     });
1280   }
1281 
1282   public void preMoveTables(final Set<TableName> tables, final String targetGroup)
1283       throws IOException {
1284     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1285       @Override
1286       public void call(MasterObserver oserver,
1287           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1288         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1289           oserver.preMoveTables(ctx, tables, targetGroup);
1290         }
1291       }
1292     });
1293   }
1294 
1295   public void postMoveTables(final Set<TableName> tables, final String targetGroup)
1296       throws IOException {
1297     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1298       @Override
1299       public void call(MasterObserver oserver,
1300           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1301         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1302           oserver.postMoveTables(ctx, tables, targetGroup);
1303         }
1304       }
1305     });
1306   }
1307 
1308   public void preMoveServersAndTables(final Set<Address> servers, final Set<TableName> tables,
1309       final String targetGroup) throws IOException {
1310     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1311       @Override
1312       public void call(MasterObserver oserver,
1313                        ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1314         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1315           oserver.preMoveServersAndTables(ctx, servers, tables, targetGroup);
1316         }
1317       }
1318     });
1319   }
1320 
1321   public void postMoveServersAndTables(final Set<Address> servers, final Set<TableName> tables,
1322       final String targetGroup) throws IOException {
1323     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1324       @Override
1325       public void call(MasterObserver oserver,
1326                        ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1327         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1328           oserver.postMoveServersAndTables(ctx, servers, tables, targetGroup);
1329         }
1330       }
1331     });
1332   }
1333 
1334   public void preRemoveServers(final Set<Address> servers)
1335       throws IOException {
1336     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1337       @Override
1338       public void call(MasterObserver oserver,
1339           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1340         if(((MasterEnvironment)getEnvironment()).supportGroupCPs) {
1341           oserver.preRemoveServers(this, servers);
1342         }
1343       }
1344     });
1345   }
1346 
1347   public void postRemoveServers(final Set<Address> servers)
1348       throws IOException {
1349     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1350       @Override
1351       public void call(MasterObserver oserver,
1352           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1353         if(((MasterEnvironment)getEnvironment()).supportGroupCPs) {
1354           oserver.postRemoveServers(this, servers);
1355         }
1356       }
1357     });
1358   }
1359 
1360   public void preAddRSGroup(final String name)
1361       throws IOException {
1362     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1363       @Override
1364       public void call(MasterObserver oserver,
1365           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1366         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1367           oserver.preAddRSGroup(ctx, name);
1368         }
1369       }
1370     });
1371   }
1372 
1373   public void postAddRSGroup(final String name)
1374       throws IOException {
1375     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1376       @Override
1377       public void call(MasterObserver oserver,
1378           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1379         if (((MasterEnvironment) ctx.getEnvironment()).supportGroupCPs) {
1380           oserver.postAddRSGroup(ctx, name);
1381         }
1382       }
1383     });
1384   }
1385 
1386   public void preRemoveRSGroup(final String name)
1387       throws IOException {
1388     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1389       @Override
1390       public void call(MasterObserver oserver,
1391           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1392         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1393           oserver.preRemoveRSGroup(ctx, name);
1394         }
1395       }
1396     });
1397   }
1398 
1399   public void postRemoveRSGroup(final String name)
1400       throws IOException {
1401     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1402       @Override
1403       public void call(MasterObserver oserver,
1404           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1405         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1406           oserver.postRemoveRSGroup(ctx, name);
1407         }
1408       }
1409     });
1410   }
1411 
1412   public void preBalanceRSGroup(final String name)
1413       throws IOException {
1414     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1415       @Override
1416       public void call(MasterObserver oserver,
1417           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1418         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1419           oserver.preBalanceRSGroup(ctx, name);
1420         }
1421       }
1422     });
1423   }
1424 
1425   public void postBalanceRSGroup(final String name, final boolean balanceRan)
1426       throws IOException {
1427     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1428       @Override
1429       public void call(MasterObserver oserver,
1430           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1431         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1432           oserver.postBalanceRSGroup(ctx, name, balanceRan);
1433         }
1434       }
1435     });
1436   }
1437 
1438   public void preRenameRSGroup(final String oldName, final String newName)
1439       throws IOException {
1440     execOperation(coprocessors.isEmpty() ? null: new CoprocessorOperation() {
1441       @Override
1442       public void call(MasterObserver oserver,
1443           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1444         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1445           oserver.preRenameRSGroup(ctx, oldName, newName);
1446         }
1447       }
1448     });
1449   }
1450 
1451   public void postRenameRSGroup(final String oldName, final String newName)
1452       throws IOException {
1453     execOperation(coprocessors.isEmpty() ? null: new CoprocessorOperation() {
1454       @Override
1455       public void call(MasterObserver oserver,
1456           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1457         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1458           oserver.postRenameRSGroup(ctx, oldName, newName);
1459         }
1460       }
1461     });
1462   }
1463 
1464   private static abstract class CoprocessorOperation
1465       extends ObserverContext<MasterCoprocessorEnvironment> {
1466     public CoprocessorOperation() {
1467       this(RpcServer.getRequestUser());
1468     }
1469 
1470     public CoprocessorOperation(User user) {
1471       super(user);
1472     }
1473 
1474     public abstract void call(MasterObserver oserver,
1475         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException;
1476 
1477     public void postEnvCall(MasterEnvironment env) {
1478     }
1479   }
1480 
1481   private static abstract class CoprocessorOperationWithResult<T> extends CoprocessorOperation {
1482     private T result = null;
1483     public void setResult(final T result) { this.result = result; }
1484     public T getResult() { return this.result; }
1485   }
1486 
1487   private <T> T execOperationWithResult(final T defaultValue,
1488       final CoprocessorOperationWithResult<T> ctx) throws IOException {
1489     if (ctx == null) return defaultValue;
1490     ctx.setResult(defaultValue);
1491     execOperation(ctx);
1492     return ctx.getResult();
1493   }
1494 
1495   private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
1496     if (ctx == null) return false;
1497     boolean bypass = false;
1498     List<MasterEnvironment> envs = coprocessors.get();
1499     for (int i = 0; i < envs.size(); i++) {
1500       MasterEnvironment env = envs.get(i);
1501       if (env.getInstance() instanceof MasterObserver) {
1502         ctx.prepare(env);
1503         Thread currentThread = Thread.currentThread();
1504         ClassLoader cl = currentThread.getContextClassLoader();
1505         try {
1506           currentThread.setContextClassLoader(env.getClassLoader());
1507           ctx.call((MasterObserver)env.getInstance(), ctx);
1508         } catch (Throwable e) {
1509           handleCoprocessorThrowable(env, e);
1510         } finally {
1511           currentThread.setContextClassLoader(cl);
1512         }
1513         bypass |= ctx.shouldBypass();
1514         if (ctx.shouldComplete()) {
1515           break;
1516         }
1517       }
1518       ctx.postEnvCall(env);
1519     }
1520     return bypass;
1521   }
1522 
1523   /**
1524    * Master coprocessor classes can be configured in any order, based on that priority is set and
1525    * chained in a sorted order. For preStopMaster()/preShutdown(), coprocessor methods are invoked
1526    * in call() and environment is shutdown in postEnvCall(). <br>
1527    * Need to execute all coprocessor methods first then postEnvCall(), otherwise some coprocessors
1528    * may remain shutdown if any exception occurs during next coprocessor execution which prevent
1529    * Master stop or cluster shutdown. (Refer:
1530    * <a href="https://issues.apache.org/jira/browse/HBASE-16663">HBASE-16663</a>
1531    * @param ctx CoprocessorOperation
1532    * @return true if bypaas coprocessor execution, false if not.
1533    * @throws IOException
1534    */
1535   private boolean execShutdown(final CoprocessorOperation ctx) throws IOException {
1536     if (ctx == null) return false;
1537     boolean bypass = false;
1538     List<MasterEnvironment> envs = coprocessors.get();
1539     int envsSize = envs.size();
1540     // Iterate the coprocessors and execute CoprocessorOperation's call()
1541     for (int i = 0; i < envsSize; i++) {
1542       MasterEnvironment env = envs.get(i);
1543       if (env.getInstance() instanceof MasterObserver) {
1544         ctx.prepare(env);
1545         Thread currentThread = Thread.currentThread();
1546         ClassLoader cl = currentThread.getContextClassLoader();
1547         try {
1548           currentThread.setContextClassLoader(env.getClassLoader());
1549           ctx.call((MasterObserver) env.getInstance(), ctx);
1550         } catch (Throwable e) {
1551           handleCoprocessorThrowable(env, e);
1552         } finally {
1553           currentThread.setContextClassLoader(cl);
1554         }
1555         bypass |= ctx.shouldBypass();
1556         if (ctx.shouldComplete()) {
1557           break;
1558         }
1559       }
1560     }
1561 
1562     // Iterate the coprocessors and execute CoprocessorOperation's postEnvCall()
1563     for (int i = 0; i < envsSize; i++) {
1564       MasterEnvironment env = envs.get(i);
1565       ctx.postEnvCall(env);
1566     }
1567     return bypass;
1568   }
1569 
1570 }