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