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