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.MasterSwitchType;
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 preCreateTableAction(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         oserver.preCreateTableAction(ctx, htd, regions);
251       }
252     });
253   }
254
255   public void postCompletedCreateTableAction(
256       final HTableDescriptor htd, final HRegionInfo[] regions) throws IOException {
257     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
258       @Override
259       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
260           throws IOException {
261         oserver.postCreateTableHandler(ctx, htd, regions);
262         oserver.postCompletedCreateTableAction(ctx, htd, regions);
263       }
264     });
265   }
266
267   public void preDeleteTable(final TableName tableName) throws IOException {
268     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
269       @Override
270       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
271           throws IOException {
272         oserver.preDeleteTable(ctx, tableName);
273       }
274     });
275   }
276
277   public void postDeleteTable(final TableName tableName) throws IOException {
278     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
279       @Override
280       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
281           throws IOException {
282         oserver.postDeleteTable(ctx, tableName);
283       }
284     });
285   }
286
287   public void preDeleteTableAction(final TableName tableName) throws IOException {
288     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
289       @Override
290       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
291           throws IOException {
292         oserver.preDeleteTableHandler(ctx, tableName);
293         oserver.preDeleteTableAction(ctx, tableName);
294       }
295     });
296   }
297
298   public void postCompletedDeleteTableAction(final TableName tableName) throws IOException {
299     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
300       @Override
301       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
302           throws IOException {
303         oserver.postDeleteTableHandler(ctx, tableName);
304         oserver.postCompletedDeleteTableAction(ctx, tableName);
305       }
306     });
307   }
308
309   public void preTruncateTable(final TableName tableName) throws IOException {
310     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
311       @Override
312       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
313           throws IOException {
314         oserver.preTruncateTable(ctx, tableName);
315       }
316     });
317   }
318
319   public void postTruncateTable(final TableName tableName) throws IOException {
320     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
321       @Override
322       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
323           throws IOException {
324         oserver.postTruncateTable(ctx, tableName);
325       }
326     });
327   }
328
329   public void preTruncateTableAction(final TableName tableName) throws IOException {
330     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
331       @Override
332       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
333           throws IOException {
334         oserver.preTruncateTableHandler(ctx, tableName);
335         oserver.preTruncateTableAction(ctx, tableName);
336       }
337     });
338   }
339
340   public void postCompletedTruncateTableAction(final TableName tableName) throws IOException {
341     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
342       @Override
343       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
344           throws IOException {
345         oserver.postTruncateTableHandler(ctx, tableName);
346         oserver.postCompletedTruncateTableAction(ctx, tableName);
347       }
348     });
349   }
350
351   public void preModifyTable(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.preModifyTable(ctx, tableName, htd);
358       }
359     });
360   }
361
362   public void postModifyTable(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.postModifyTable(ctx, tableName, htd);
369       }
370     });
371   }
372
373   public void preModifyTableAction(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.preModifyTableHandler(ctx, tableName, htd);
380         oserver.preModifyTableAction(ctx, tableName, htd);
381       }
382     });
383   }
384
385   public void postCompletedModifyTableAction(final TableName tableName, final HTableDescriptor htd)
386       throws IOException {
387     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
388       @Override
389       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
390           throws IOException {
391         oserver.postModifyTableHandler(ctx, tableName, htd);
392         oserver.postCompletedModifyTableAction(ctx, tableName, htd);
393       }
394     });
395   }
396
397   public boolean preAddColumn(final TableName tableName, final HColumnDescriptor columnFamily)
398       throws IOException {
399     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
400       @Override
401       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
402           throws IOException {
403         oserver.preAddColumn(ctx, tableName, columnFamily);
404         oserver.preAddColumnFamily(ctx, tableName, columnFamily);
405       }
406     });
407   }
408
409   public void postAddColumn(final TableName tableName, final HColumnDescriptor columnFamily)
410       throws IOException {
411     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
412       @Override
413       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
414           throws IOException {
415         oserver.postAddColumn(ctx, tableName, columnFamily);
416         oserver.postAddColumnFamily(ctx, tableName, columnFamily);
417       }
418     });
419   }
420
421   public boolean preAddColumnFamilyAction(
422       final TableName tableName,
423       final HColumnDescriptor columnFamily)
424       throws IOException {
425     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
426       @Override
427       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
428           throws IOException {
429         oserver.preAddColumnHandler(ctx, tableName, columnFamily);
430         oserver.preAddColumnFamilyAction(ctx, tableName, columnFamily);
431       }
432     });
433   }
434
435   public void postCompletedAddColumnFamilyAction(
436       final TableName tableName,
437       final HColumnDescriptor columnFamily)
438       throws IOException {
439     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
440       @Override
441       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
442           throws IOException {
443         oserver.postAddColumnHandler(ctx, tableName, columnFamily);
444         oserver.postCompletedAddColumnFamilyAction(ctx, tableName, columnFamily);
445       }
446     });
447   }
448
449   public boolean preModifyColumn(final TableName tableName, final HColumnDescriptor columnFamily)
450       throws IOException {
451     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
452       @Override
453       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
454           throws IOException {
455         oserver.preModifyColumn(ctx, tableName, columnFamily);
456         oserver.preModifyColumnFamily(ctx, tableName, columnFamily);
457       }
458     });
459   }
460
461   public void postModifyColumn(final TableName tableName, final HColumnDescriptor columnFamily)
462       throws IOException {
463     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
464       @Override
465       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
466           throws IOException {
467         oserver.postModifyColumn(ctx, tableName, columnFamily);
468         oserver.postModifyColumnFamily(ctx, tableName, columnFamily);
469       }
470     });
471   }
472
473   public boolean preModifyColumnFamilyAction(
474       final TableName tableName,
475       final HColumnDescriptor columnFamily) throws IOException {
476     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
477       @Override
478       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
479           throws IOException {
480         oserver.preModifyColumnHandler(ctx, tableName, columnFamily);
481         oserver.preModifyColumnFamilyAction(ctx, tableName, columnFamily);
482       }
483     });
484   }
485 
486   public void postCompletedModifyColumnFamilyAction(
487       final TableName tableName,
488       final HColumnDescriptor columnFamily) throws IOException {
489     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
490       @Override
491       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
492           throws IOException {
493         oserver.postModifyColumnHandler(ctx, tableName, columnFamily);
494         oserver.postCompletedModifyColumnFamilyAction(ctx, tableName, columnFamily);
495       }
496     });
497   }
498
499   public boolean preDeleteColumn(final TableName tableName, final byte[] columnFamily)
500       throws IOException {
501     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
502       @Override
503       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
504           throws IOException {
505         oserver.preDeleteColumn(ctx, tableName, columnFamily);
506         oserver.preDeleteColumnFamily(ctx, tableName, columnFamily);
507       }
508     });
509   }
510
511   public void postDeleteColumn(final TableName tableName, final byte[] columnFamily)
512       throws IOException {
513     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
514       @Override
515       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
516           throws IOException {
517         oserver.postDeleteColumn(ctx, tableName, columnFamily);
518         oserver.postDeleteColumnFamily(ctx, tableName, columnFamily);
519       }
520     });
521   }
522
523   public boolean preDeleteColumnFamilyAction(
524       final TableName tableName,
525       final byte[] columnFamily)
526       throws IOException {
527     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
528       @Override
529       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
530           throws IOException {
531         oserver.preDeleteColumnHandler(ctx, tableName, columnFamily);
532         oserver.preDeleteColumnFamilyAction(ctx, tableName, columnFamily);
533       }
534     });
535   }
536
537   public void postCompletedDeleteColumnFamilyAction(
538       final TableName tableName, final byte[] columnFamily) throws IOException {
539     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
540       @Override
541       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
542           throws IOException {
543         oserver.postDeleteColumnHandler(ctx, tableName, columnFamily);
544         oserver.postCompletedDeleteColumnFamilyAction(ctx, tableName, columnFamily);
545       }
546     });
547   }
548
549   public void preEnableTable(final TableName tableName) throws IOException {
550     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
551       @Override
552       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
553           throws IOException {
554         oserver.preEnableTable(ctx, tableName);
555       }
556     });
557   }
558
559   public void postEnableTable(final TableName tableName) throws IOException {
560     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
561       @Override
562       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
563           throws IOException {
564         oserver.postEnableTable(ctx, tableName);
565       }
566     });
567   }
568
569   public void preEnableTableAction(final TableName tableName) throws IOException {
570     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
571       @Override
572       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
573           throws IOException {
574         oserver.preEnableTableHandler(ctx, tableName);
575         oserver.preEnableTableAction(ctx, tableName);
576       }
577     });
578   }
579
580   public void postCompletedEnableTableAction(final TableName tableName) throws IOException {
581     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
582       @Override
583       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
584           throws IOException {
585         oserver.postEnableTableHandler(ctx, tableName);
586         oserver.postCompletedEnableTableAction(ctx, tableName);
587       }
588     });
589   }
590
591   public void preDisableTable(final TableName tableName) throws IOException {
592     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
593       @Override
594       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
595           throws IOException {
596         oserver.preDisableTable(ctx, tableName);
597       }
598     });
599   }
600
601   public void postDisableTable(final TableName tableName) throws IOException {
602     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
603       @Override
604       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
605           throws IOException {
606         oserver.postDisableTable(ctx, tableName);
607       }
608     });
609   }
610
611   public void preDisableTableAction(final TableName tableName) throws IOException {
612     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
613       @Override
614       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
615           throws IOException {
616         oserver.preDisableTableHandler(ctx, tableName);
617         oserver.preDisableTableAction(ctx, tableName);
618       }
619     });
620   }
621
622   public void postCompletedDisableTableAction(final TableName tableName) throws IOException {
623     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
624       @Override
625       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
626           throws IOException {
627         oserver.postDisableTableHandler(ctx, tableName);
628         oserver.postCompletedDisableTableAction(ctx, tableName);
629       }
630     });
631   }
632
633   public boolean preAbortProcedure(
634       final ProcedureExecutor<MasterProcedureEnv> procEnv,
635       final long procId) throws IOException {
636     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
637       @Override
638       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
639           throws IOException {
640         oserver.preAbortProcedure(ctx, procEnv, procId);
641       }
642     });
643   }
644
645   public void postAbortProcedure() throws IOException {
646     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
647       @Override
648       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
649           throws IOException {
650         oserver.postAbortProcedure(ctx);
651       }
652     });
653   }
654
655   public boolean preListProcedures() throws IOException {
656     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
657       @Override
658       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
659           throws IOException {
660         oserver.preListProcedures(ctx);
661       }
662     });
663   }
664
665   public void postListProcedures(final List<ProcedureInfo> procInfoList) throws IOException {
666     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
667       @Override
668       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
669           throws IOException {
670         oserver.postListProcedures(ctx, procInfoList);
671       }
672     });
673   }
674
675   public boolean preMove(final HRegionInfo region, final ServerName srcServer,
676       final ServerName destServer) throws IOException {
677     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
678       @Override
679       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
680           throws IOException {
681         oserver.preMove(ctx, region, srcServer, destServer);
682       }
683     });
684   }
685
686   public void postMove(final HRegionInfo region, final ServerName srcServer,
687       final ServerName destServer) throws IOException {
688     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
689       @Override
690       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
691           throws IOException {
692         oserver.postMove(ctx, region, srcServer, destServer);
693       }
694     });
695   }
696
697   public boolean preAssign(final HRegionInfo regionInfo) throws IOException {
698     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
699       @Override
700       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
701           throws IOException {
702         oserver.preAssign(ctx, regionInfo);
703       }
704     });
705   }
706
707   public void postAssign(final HRegionInfo regionInfo) throws IOException {
708     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
709       @Override
710       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
711           throws IOException {
712         oserver.postAssign(ctx, regionInfo);
713       }
714     });
715   }
716
717   public boolean preUnassign(final HRegionInfo regionInfo, final boolean force)
718       throws IOException {
719     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
720       @Override
721       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
722           throws IOException {
723         oserver.preUnassign(ctx, regionInfo, force);
724       }
725     });
726   }
727
728   public void postUnassign(final HRegionInfo regionInfo, final boolean force) throws IOException {
729     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
730       @Override
731       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
732           throws IOException {
733         oserver.postUnassign(ctx, regionInfo, force);
734       }
735     });
736   }
737
738   public void preRegionOffline(final HRegionInfo regionInfo) throws IOException {
739     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
740       @Override
741       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
742           throws IOException {
743         oserver.preRegionOffline(ctx, regionInfo);
744       }
745     });
746   }
747
748   public void postRegionOffline(final HRegionInfo regionInfo) throws IOException {
749     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
750       @Override
751       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
752           throws IOException {
753         oserver.postRegionOffline(ctx, regionInfo);
754       }
755     });
756   }
757
758   public void preDispatchMerge(final HRegionInfo regionInfoA, final HRegionInfo regionInfoB)
759       throws IOException {
760     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
761       @Override
762       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
763           throws IOException {
764         oserver.preDispatchMerge(ctx, regionInfoA, regionInfoB);
765       }
766     });
767   }
768
769   public void postDispatchMerge(final HRegionInfo regionInfoA, final HRegionInfo regionInfoB)
770       throws IOException {
771     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
772       @Override
773       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
774           throws IOException {
775         oserver.postDispatchMerge(ctx, regionInfoA, regionInfoB);
776       }
777     });
778   }
779
780   public boolean preBalance() throws IOException {
781     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
782       @Override
783       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
784           throws IOException {
785         oserver.preBalance(ctx);
786       }
787     });
788   }
789
790   public void postBalance(final List<RegionPlan> plans) throws IOException {
791     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
792       @Override
793       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
794           throws IOException {
795         oserver.postBalance(ctx, plans);
796       }
797     });
798   }
799
800   public boolean preSetSplitOrMergeEnabled(final boolean newValue,
801       final MasterSwitchType switchType) throws IOException {
802     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
803       @Override
804       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
805           throws IOException {
806         oserver.preSetSplitOrMergeEnabled(ctx, newValue, switchType);
807       }
808     });
809   }
810
811   public void postSetSplitOrMergeEnabled(final boolean newValue,
812       final MasterSwitchType switchType) 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.postSetSplitOrMergeEnabled(ctx, newValue, switchType);
818       }
819     });
820   }
821
822   public boolean preBalanceSwitch(final boolean b) throws IOException {
823     return execOperationWithResult(b, coprocessors.isEmpty() ? null :
824         new CoprocessorOperationWithResult<Boolean>() {
825       @Override
826       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
827           throws IOException {
828         setResult(oserver.preBalanceSwitch(ctx, getResult()));
829       }
830     });
831   }
832
833   public void postBalanceSwitch(final boolean oldValue, final boolean newValue)
834       throws IOException {
835     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
836       @Override
837       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
838           throws IOException {
839         oserver.postBalanceSwitch(ctx, oldValue, newValue);
840       }
841     });
842   }
843
844   public void preShutdown() throws IOException {
845     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
846       @Override
847       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
848           throws IOException {
849         oserver.preShutdown(ctx);
850       }
851       @Override
852       public void postEnvCall(MasterEnvironment env) {
853         // invoke coprocessor stop method
854         shutdown(env);
855       }
856     });
857   }
858
859   public void preStopMaster() throws IOException {
860     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
861       @Override
862       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
863           throws IOException {
864         oserver.preStopMaster(ctx);
865       }
866       @Override
867       public void postEnvCall(MasterEnvironment env) {
868         // invoke coprocessor stop method
869         shutdown(env);
870       }
871     });
872   }
873
874   public void preMasterInitialization() throws IOException {
875     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
876       @Override
877       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
878           throws IOException {
879         oserver.preMasterInitialization(ctx);
880       }
881     });
882   }
883
884   public void postStartMaster() throws IOException {
885     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
886       @Override
887       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
888           throws IOException {
889         oserver.postStartMaster(ctx);
890       }
891     });
892   }
893
894   public void preSnapshot(final SnapshotDescription snapshot,
895       final HTableDescriptor hTableDescriptor) throws IOException {
896     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
897       @Override
898       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
899           throws IOException {
900         oserver.preSnapshot(ctx, snapshot, hTableDescriptor);
901       }
902     });
903   }
904
905   public void postSnapshot(final SnapshotDescription snapshot,
906       final HTableDescriptor hTableDescriptor) throws IOException {
907     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
908       @Override
909       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
910           throws IOException {
911         oserver.postSnapshot(ctx, snapshot, hTableDescriptor);
912       }
913     });
914   }
915
916   public void preListSnapshot(final SnapshotDescription snapshot) throws IOException {
917     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
918       @Override
919       public void call(MasterObserver observer, ObserverContext<MasterCoprocessorEnvironment> ctx)
920           throws IOException {
921         observer.preListSnapshot(ctx, snapshot);
922       }
923     });
924   }
925
926   public void postListSnapshot(final SnapshotDescription snapshot) throws IOException {
927     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
928       @Override
929       public void call(MasterObserver observer, ObserverContext<MasterCoprocessorEnvironment> ctx)
930           throws IOException {
931         observer.postListSnapshot(ctx, snapshot);
932       }
933     });
934   }
935
936   public void preCloneSnapshot(final SnapshotDescription snapshot,
937       final HTableDescriptor hTableDescriptor) throws IOException {
938     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
939       @Override
940       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
941           throws IOException {
942         oserver.preCloneSnapshot(ctx, snapshot, hTableDescriptor);
943       }
944     });
945   }
946
947   public void postCloneSnapshot(final SnapshotDescription snapshot,
948       final HTableDescriptor hTableDescriptor) throws IOException {
949     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
950       @Override
951       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
952           throws IOException {
953         oserver.postCloneSnapshot(ctx, snapshot, hTableDescriptor);
954       }
955     });
956   }
957
958   public void preRestoreSnapshot(final SnapshotDescription snapshot,
959       final HTableDescriptor hTableDescriptor) throws IOException {
960     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
961       @Override
962       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
963           throws IOException {
964         oserver.preRestoreSnapshot(ctx, snapshot, hTableDescriptor);
965       }
966     });
967   }
968
969   public void postRestoreSnapshot(final SnapshotDescription snapshot,
970       final HTableDescriptor hTableDescriptor) throws IOException {
971     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
972       @Override
973       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
974           throws IOException {
975         oserver.postRestoreSnapshot(ctx, snapshot, hTableDescriptor);
976       }
977     });
978   }
979
980   public void preDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
981     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
982       @Override
983       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
984           throws IOException {
985         oserver.preDeleteSnapshot(ctx, snapshot);
986       }
987     });
988   }
989
990   public void postDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
991     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
992       @Override
993       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
994           throws IOException {
995         oserver.postDeleteSnapshot(ctx, snapshot);
996       }
997     });
998   }
999
1000   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
1001       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
1002     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1003       @Override
1004       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1005           throws IOException {
1006         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
1007       }
1008     });
1009   }
1010
1011   public void postGetTableDescriptors(final List<TableName> tableNamesList,
1012       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
1013     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1014       @Override
1015       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1016           throws IOException {
1017         oserver.postGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
1018       }
1019     });
1020   }
1021
1022   public boolean preGetTableNames(final List<HTableDescriptor> descriptors,
1023       final String regex) throws IOException {
1024     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1025       @Override
1026       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1027           throws IOException {
1028         oserver.preGetTableNames(ctx, descriptors, regex);
1029       }
1030     });
1031   }
1032
1033   public void postGetTableNames(final List<HTableDescriptor> descriptors,
1034       final String regex) throws IOException {
1035     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1036       @Override
1037       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1038           throws IOException {
1039         oserver.postGetTableNames(ctx, descriptors, regex);
1040       }
1041     });
1042   }
1043
1044   public void preTableFlush(final TableName tableName) throws IOException {
1045     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1046       @Override
1047       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1048           throws IOException {
1049         oserver.preTableFlush(ctx, tableName);
1050       }
1051     });
1052   }
1053
1054   public void postTableFlush(final TableName tableName) throws IOException {
1055     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1056       @Override
1057       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1058           throws IOException {
1059         oserver.postTableFlush(ctx, tableName);
1060       }
1061     });
1062   }
1063
1064   public void preSetUserQuota(final String user, final Quotas quotas) throws IOException {
1065     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1066       @Override
1067       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1068           throws IOException {
1069         oserver.preSetUserQuota(ctx, user, quotas);
1070       }
1071     });
1072   }
1073
1074   public void postSetUserQuota(final String user, final Quotas quotas) throws IOException {
1075     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1076       @Override
1077       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1078           throws IOException {
1079         oserver.postSetUserQuota(ctx, user, quotas);
1080       }
1081     });
1082   }
1083
1084   public void preSetUserQuota(final String user, final TableName table, final Quotas quotas)
1085       throws IOException {
1086     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1087       @Override
1088       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1089           throws IOException {
1090         oserver.preSetUserQuota(ctx, user, table, quotas);
1091       }
1092     });
1093   }
1094
1095   public void postSetUserQuota(final String user, final TableName table, final Quotas quotas)
1096       throws IOException {
1097     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1098       @Override
1099       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1100           throws IOException {
1101         oserver.postSetUserQuota(ctx, user, table, quotas);
1102       }
1103     });
1104   }
1105
1106   public void preSetUserQuota(final String user, final String namespace, final Quotas quotas)
1107       throws IOException {
1108     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1109       @Override
1110       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1111           throws IOException {
1112         oserver.preSetUserQuota(ctx, user, namespace, quotas);
1113       }
1114     });
1115   }
1116
1117   public void postSetUserQuota(final String user, final String namespace, final Quotas quotas)
1118       throws IOException {
1119     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1120       @Override
1121       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1122           throws IOException {
1123         oserver.postSetUserQuota(ctx, user, namespace, quotas);
1124       }
1125     });
1126   }
1127
1128   public void preSetTableQuota(final TableName table, final Quotas quotas) throws IOException {
1129     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1130       @Override
1131       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1132           throws IOException {
1133         oserver.preSetTableQuota(ctx, table, quotas);
1134       }
1135     });
1136   }
1137
1138   public void postSetTableQuota(final TableName table, final Quotas quotas) throws IOException {
1139     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1140       @Override
1141       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1142           throws IOException {
1143         oserver.postSetTableQuota(ctx, table, quotas);
1144       }
1145     });
1146   }
1147
1148   public void preSetNamespaceQuota(final String namespace, final Quotas quotas) throws IOException {
1149     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1150       @Override
1151       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1152           throws IOException {
1153         oserver.preSetNamespaceQuota(ctx, namespace, quotas);
1154       }
1155     });
1156   }
1157
1158   public void postSetNamespaceQuota(final String namespace, final Quotas quotas) throws IOException{
1159     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1160       @Override
1161       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
1162           throws IOException {
1163         oserver.postSetNamespaceQuota(ctx, namespace, quotas);
1164       }
1165     });
1166   }
1167
1168   private static abstract class CoprocessorOperation
1169       extends ObserverContext<MasterCoprocessorEnvironment> {
1170     public CoprocessorOperation() {
1171     }
1172
1173     public abstract void call(MasterObserver oserver,
1174         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException;
1175
1176     public void postEnvCall(MasterEnvironment env) {
1177     }
1178   }
1179
1180   private static abstract class CoprocessorOperationWithResult<T> extends CoprocessorOperation {
1181     private T result = null;
1182     public void setResult(final T result) { this.result = result; }
1183     public T getResult() { return this.result; }
1184   }
1185
1186   private <T> T execOperationWithResult(final T defaultValue,
1187       final CoprocessorOperationWithResult<T> ctx) throws IOException {
1188     if (ctx == null) return defaultValue;
1189     ctx.setResult(defaultValue);
1190     execOperation(ctx);
1191     return ctx.getResult();
1192   }
1193
1194   private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
1195     if (ctx == null) return false;
1196     boolean bypass = false;
1197     List<MasterEnvironment> envs = coprocessors.get();
1198     for (int i = 0; i < envs.size(); i++) {
1199       MasterEnvironment env = envs.get(i);
1200       if (env.getInstance() instanceof MasterObserver) {
1201         ctx.prepare(env);
1202         Thread currentThread = Thread.currentThread();
1203         ClassLoader cl = currentThread.getContextClassLoader();
1204         try {
1205           currentThread.setContextClassLoader(env.getClassLoader());
1206           ctx.call((MasterObserver)env.getInstance(), ctx);
1207         } catch (Throwable e) {
1208           handleCoprocessorThrowable(env, e);
1209         } finally {
1210           currentThread.setContextClassLoader(cl);
1211         }
1212         bypass |= ctx.shouldBypass();
1213         if (ctx.shouldComplete()) {
1214           break;
1215         }
1216       }
1217       ctx.postEnvCall(env);
1218     }
1219     return bypass;
1220   }
1221
1222   public void preMoveServers(final Set<HostAndPort> servers, final String targetGroup)
1223       throws IOException {
1224     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1225       @Override
1226       public void call(MasterObserver oserver,
1227           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1228         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1229           oserver.preMoveServers(ctx, servers, targetGroup);
1230         }
1231       }
1232     });
1233   }
1234
1235   public void postMoveServers(final Set<HostAndPort> servers, final String targetGroup)
1236       throws IOException {
1237     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1238       @Override
1239       public void call(MasterObserver oserver,
1240           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1241         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1242           oserver.postMoveServers(ctx, servers, targetGroup);
1243         }
1244       }
1245     });
1246   }
1247
1248   public void preMoveTables(final Set<TableName> tables, final String targetGroup)
1249       throws IOException {
1250     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1251       @Override
1252       public void call(MasterObserver oserver,
1253           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1254         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1255           oserver.preMoveTables(ctx, tables, targetGroup);
1256         }
1257       }
1258     });
1259   }
1260
1261   public void postMoveTables(final Set<TableName> tables, final String targetGroup)
1262       throws IOException {
1263     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1264       @Override
1265       public void call(MasterObserver oserver,
1266           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1267         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1268           oserver.postMoveTables(ctx, tables, targetGroup);
1269         }
1270       }
1271     });
1272   }
1273
1274   public void preAddRSGroup(final String name)
1275       throws IOException {
1276     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1277       @Override
1278       public void call(MasterObserver oserver,
1279           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1280         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1281           oserver.preAddRSGroup(ctx, name);
1282         }
1283       }
1284     });
1285   }
1286
1287   public void postAddRSGroup(final String name)
1288       throws IOException {
1289     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1290       @Override
1291       public void call(MasterObserver oserver,
1292           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1293         if (((MasterEnvironment) ctx.getEnvironment()).supportGroupCPs) {
1294           oserver.postAddRSGroup(ctx, name);
1295         }
1296       }
1297     });
1298   }
1299
1300   public void preRemoveRSGroup(final String name)
1301       throws IOException {
1302     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1303       @Override
1304       public void call(MasterObserver oserver,
1305           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1306         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1307           oserver.preRemoveRSGroup(ctx, name);
1308         }
1309       }
1310     });
1311   }
1312
1313   public void postRemoveRSGroup(final String name)
1314       throws IOException {
1315     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1316       @Override
1317       public void call(MasterObserver oserver,
1318           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1319         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1320           oserver.postRemoveRSGroup(ctx, name);
1321         }
1322       }
1323     });
1324   }
1325
1326   public void preBalanceRSGroup(final String name)
1327       throws IOException {
1328     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1329       @Override
1330       public void call(MasterObserver oserver,
1331           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1332         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1333           oserver.preBalanceRSGroup(ctx, name);
1334         }
1335       }
1336     });
1337   }
1338
1339   public void postBalanceRSGroup(final String name, final boolean balanceRan)
1340       throws IOException {
1341     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
1342       @Override
1343       public void call(MasterObserver oserver,
1344           ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
1345         if(((MasterEnvironment)ctx.getEnvironment()).supportGroupCPs) {
1346           oserver.postBalanceRSGroup(ctx, name, balanceRan);
1347         }
1348       }
1349     });
1350   }
1351
1352 }