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