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 org.apache.hadoop.classification.InterfaceAudience;
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.*;
25  import org.apache.hadoop.hbase.coprocessor.*;
26  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
27  
28  import java.io.IOException;
29  import java.util.List;
30  
31  /**
32   * Provides the coprocessor framework and environment for master oriented
33   * operations.  {@link HMaster} interacts with the loaded coprocessors
34   * through this class.
35   */
36  @InterfaceAudience.Private
37  public class MasterCoprocessorHost
38      extends CoprocessorHost<MasterCoprocessorHost.MasterEnvironment> {
39  
40    /**
41     * Coprocessor environment extension providing access to master related
42     * services.
43     */
44    static class MasterEnvironment extends CoprocessorHost.Environment
45        implements MasterCoprocessorEnvironment {
46      private MasterServices masterServices;
47  
48      public MasterEnvironment(final Class<?> implClass, final Coprocessor impl,
49          final int priority, final int seq, final Configuration conf,
50          final MasterServices services) {
51        super(impl, priority, seq, conf);
52        this.masterServices = services;
53      }
54  
55      public MasterServices getMasterServices() {
56        return masterServices;
57      }
58    }
59  
60    private MasterServices masterServices;
61  
62    MasterCoprocessorHost(final MasterServices services, final Configuration conf) {
63      super(services);
64      this.conf = conf;
65      this.masterServices = services;
66      loadSystemCoprocessors(conf, MASTER_COPROCESSOR_CONF_KEY);
67    }
68  
69    @Override
70    public MasterEnvironment createEnvironment(final Class<?> implClass,
71        final Coprocessor instance, final int priority, final int seq,
72        final Configuration conf) {
73      for (Class<?> c : implClass.getInterfaces()) {
74        if (CoprocessorService.class.isAssignableFrom(c)) {
75          masterServices.registerService(((CoprocessorService)instance).getService());
76        }
77      }
78      return new MasterEnvironment(implClass, instance, priority, seq, conf,
79          masterServices);
80    }
81  
82    public boolean preCreateNamespace(final NamespaceDescriptor ns) throws IOException {
83      return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
84        @Override
85        public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
86            throws IOException {
87          oserver.preCreateNamespace(ctx, ns);
88        }
89      });
90    }
91  
92    public void postCreateNamespace(final NamespaceDescriptor ns) throws IOException {
93      execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
94        @Override
95        public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
96            throws IOException {
97          oserver.postCreateNamespace(ctx, ns);
98        }
99      });
100   }
101 
102   public boolean preDeleteNamespace(final String namespaceName) throws IOException {
103     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
104       @Override
105       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
106           throws IOException {
107         oserver.preDeleteNamespace(ctx, namespaceName);
108       }
109     });
110   }
111 
112   public void postDeleteNamespace(final String namespaceName) throws IOException {
113     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
114       @Override
115       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
116           throws IOException {
117         oserver.postDeleteNamespace(ctx, namespaceName);
118       }
119     });
120   }
121 
122   public boolean preModifyNamespace(final NamespaceDescriptor ns) throws IOException {
123     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
124       @Override
125       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
126           throws IOException {
127         oserver.preModifyNamespace(ctx, ns);
128       }
129     });
130   }
131 
132   public void postModifyNamespace(final NamespaceDescriptor ns) throws IOException {
133     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
134       @Override
135       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
136           throws IOException {
137         oserver.postModifyNamespace(ctx, ns);
138       }
139     });
140   }
141 
142   /* Implementation of hooks for invoking MasterObservers */
143 
144   public void preCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
145       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.preCreateTable(ctx, htd, regions);
151       }
152     });
153   }
154 
155   public void postCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
156       throws IOException {
157     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
158       @Override
159       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
160           throws IOException {
161         oserver.postCreateTable(ctx, htd, regions);
162       }
163     });
164   }
165 
166   public void preCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions)
167       throws IOException {
168     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
169       @Override
170       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
171           throws IOException {
172         oserver.preCreateTableHandler(ctx, htd, regions);
173       }
174     });
175   }
176 
177   public void postCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions)
178       throws IOException {
179     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
180       @Override
181       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
182           throws IOException {
183         oserver.postCreateTableHandler(ctx, htd, regions);
184       }
185     });
186   }
187 
188   public void preDeleteTable(final TableName tableName) throws IOException {
189     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
190       @Override
191       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
192           throws IOException {
193         oserver.preDeleteTable(ctx, tableName);
194       }
195     });
196   }
197 
198   public void postDeleteTable(final TableName tableName) throws IOException {
199     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
200       @Override
201       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
202           throws IOException {
203         oserver.postDeleteTable(ctx, tableName);
204       }
205     });
206   }
207 
208   public void preDeleteTableHandler(final TableName tableName) throws IOException {
209     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
210       @Override
211       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
212           throws IOException {
213         oserver.preDeleteTableHandler(ctx, tableName);
214       }
215     });
216   }
217 
218   public void postDeleteTableHandler(final TableName tableName) throws IOException {
219     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
220       @Override
221       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
222           throws IOException {
223         oserver.postDeleteTableHandler(ctx, tableName);
224       }
225     });
226   }
227 
228   public void preTruncateTable(final TableName tableName) 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.preTruncateTable(ctx, tableName);
234       }
235     });
236   }
237 
238   public void postTruncateTable(final TableName tableName) throws IOException {
239     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
240       @Override
241       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
242           throws IOException {
243         oserver.postTruncateTable(ctx, tableName);
244       }
245     });
246   }
247 
248   public void preTruncateTableHandler(final TableName tableName) throws IOException {
249     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
250       @Override
251       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
252           throws IOException {
253         oserver.preTruncateTableHandler(ctx, tableName);
254       }
255     });
256   }
257 
258   public void postTruncateTableHandler(final TableName tableName) throws IOException {
259     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
260       @Override
261       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
262           throws IOException {
263         oserver.postTruncateTableHandler(ctx, tableName);
264       }
265     });
266   }
267 
268   public void preModifyTable(final TableName tableName, final HTableDescriptor htd)
269       throws IOException {
270     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
271       @Override
272       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
273           throws IOException {
274         oserver.preModifyTable(ctx, tableName, htd);
275       }
276     });
277   }
278 
279   public void postModifyTable(final TableName tableName, final HTableDescriptor htd)
280       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.postModifyTable(ctx, tableName, htd);
286       }
287     });
288   }
289 
290   public void preModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
291       throws IOException {
292     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
293       @Override
294       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
295           throws IOException {
296         oserver.preModifyTableHandler(ctx, tableName, htd);
297       }
298     });
299   }
300 
301   public void postModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
302       throws IOException {
303     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
304       @Override
305       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
306           throws IOException {
307         oserver.postModifyTableHandler(ctx, tableName, htd);
308       }
309     });
310   }
311 
312   public boolean preAddColumn(final TableName tableName, final HColumnDescriptor column)
313       throws IOException {
314     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
315       @Override
316       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
317           throws IOException {
318         oserver.preAddColumn(ctx, tableName, column);
319       }
320     });
321   }
322 
323   public void postAddColumn(final TableName tableName, final HColumnDescriptor column)
324       throws IOException {
325     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
326       @Override
327       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
328           throws IOException {
329         oserver.postAddColumn(ctx, tableName, column);
330       }
331     });
332   }
333 
334   public boolean preAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
335       throws IOException {
336     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
337       @Override
338       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
339           throws IOException {
340         oserver.preAddColumnHandler(ctx, tableName, column);
341       }
342     });
343   }
344 
345   public void postAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
346       throws IOException {
347     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
348       @Override
349       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
350           throws IOException {
351         oserver.postAddColumnHandler(ctx, tableName, column);
352       }
353     });
354   }
355 
356   public boolean preModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
357       throws IOException {
358     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
359       @Override
360       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
361           throws IOException {
362         oserver.preModifyColumn(ctx, tableName, descriptor);
363       }
364     });
365   }
366 
367   public void postModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
368       throws IOException {
369     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
370       @Override
371       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
372           throws IOException {
373         oserver.postModifyColumn(ctx, tableName, descriptor);
374       }
375     });
376   }
377 
378   public boolean preModifyColumnHandler(final TableName tableName,
379       final HColumnDescriptor descriptor) throws IOException {
380     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
381       @Override
382       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
383           throws IOException {
384         oserver.preModifyColumnHandler(ctx, tableName, descriptor);
385       }
386     });
387   }
388 
389   public void postModifyColumnHandler(final TableName tableName,
390       final HColumnDescriptor descriptor) throws IOException {
391     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
392       @Override
393       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
394           throws IOException {
395         oserver.postModifyColumnHandler(ctx, tableName, descriptor);
396       }
397     });
398   }
399 
400   public boolean preDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
401     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
402       @Override
403       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
404           throws IOException {
405         oserver.preDeleteColumn(ctx, tableName, c);
406       }
407     });
408   }
409 
410   public void postDeleteColumn(final TableName tableName, final byte [] c) 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.postDeleteColumn(ctx, tableName, c);
416       }
417     });
418   }
419 
420   public boolean preDeleteColumnHandler(final TableName tableName, final byte[] c)
421       throws IOException {
422     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
423       @Override
424       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
425           throws IOException {
426         oserver.preDeleteColumnHandler(ctx, tableName, c);
427       }
428     });
429   }
430 
431   public void postDeleteColumnHandler(final TableName tableName, final byte[] c)
432       throws IOException {
433     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
434       @Override
435       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
436           throws IOException {
437         oserver.postDeleteColumnHandler(ctx, tableName, c);
438       }
439     });
440   }
441 
442   public void preEnableTable(final TableName tableName) throws IOException {
443     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
444       @Override
445       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
446           throws IOException {
447         oserver.preEnableTable(ctx, tableName);
448       }
449     });
450   }
451 
452   public void postEnableTable(final TableName tableName) throws IOException {
453     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
454       @Override
455       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
456           throws IOException {
457         oserver.postEnableTable(ctx, tableName);
458       }
459     });
460   }
461 
462   public void preEnableTableHandler(final TableName tableName) 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.preEnableTableHandler(ctx, tableName);
468       }
469     });
470   }
471 
472   public void postEnableTableHandler(final TableName tableName) throws IOException {
473     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
474       @Override
475       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
476           throws IOException {
477         oserver.postEnableTableHandler(ctx, tableName);
478       }
479     });
480   }
481 
482   public void preDisableTable(final TableName tableName) 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.preDisableTable(ctx, tableName);
488       }
489     });
490   }
491 
492   public void postDisableTable(final TableName tableName) throws IOException {
493     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
494       @Override
495       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
496           throws IOException {
497         oserver.postDisableTable(ctx, tableName);
498       }
499     });
500   }
501 
502   public void preDisableTableHandler(final TableName tableName) throws IOException {
503     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
504       @Override
505       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
506           throws IOException {
507         oserver.preDisableTableHandler(ctx, tableName);
508       }
509     });
510   }
511 
512   public void postDisableTableHandler(final TableName tableName) 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.postDisableTableHandler(ctx, tableName);
518       }
519     });
520   }
521 
522   public boolean preMove(final HRegionInfo region, final ServerName srcServer,
523       final ServerName destServer) throws IOException {
524     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
525       @Override
526       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
527           throws IOException {
528         oserver.preMove(ctx, region, srcServer, destServer);
529       }
530     });
531   }
532 
533   public void postMove(final HRegionInfo region, final ServerName srcServer,
534       final ServerName destServer) 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.postMove(ctx, region, srcServer, destServer);
540       }
541     });
542   }
543 
544   public boolean preAssign(final HRegionInfo regionInfo) throws IOException {
545     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
546       @Override
547       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
548           throws IOException {
549         oserver.preAssign(ctx, regionInfo);
550       }
551     });
552   }
553 
554   public void postAssign(final HRegionInfo regionInfo) 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.postAssign(ctx, regionInfo);
560       }
561     });
562   }
563 
564   public boolean preUnassign(final HRegionInfo regionInfo, final boolean force)
565       throws IOException {
566     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
567       @Override
568       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
569           throws IOException {
570         oserver.preUnassign(ctx, regionInfo, force);
571       }
572     });
573   }
574 
575   public void postUnassign(final HRegionInfo regionInfo, final boolean force) throws IOException {
576     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
577       @Override
578       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
579           throws IOException {
580         oserver.postUnassign(ctx, regionInfo, force);
581       }
582     });
583   }
584 
585   public void preRegionOffline(final HRegionInfo regionInfo) throws IOException {
586     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
587       @Override
588       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
589           throws IOException {
590         oserver.preRegionOffline(ctx, regionInfo);
591       }
592     });
593   }
594 
595   public void postRegionOffline(final HRegionInfo regionInfo) throws IOException {
596     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
597       @Override
598       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
599           throws IOException {
600         oserver.postRegionOffline(ctx, regionInfo);
601       }
602     });
603   }
604 
605   public boolean preBalance() throws IOException {
606     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
607       @Override
608       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
609           throws IOException {
610         oserver.preBalance(ctx);
611       }
612     });
613   }
614 
615   public void postBalance(final List<RegionPlan> plans) throws IOException {
616     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
617       @Override
618       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
619           throws IOException {
620         oserver.postBalance(ctx, plans);
621       }
622     });
623   }
624 
625   public boolean preBalanceSwitch(final boolean b) throws IOException {
626     return execOperationWithResult(b, coprocessors.isEmpty() ? null :
627         new CoprocessorOperationWithResult<Boolean>() {
628       @Override
629       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
630           throws IOException {
631         setResult(oserver.preBalanceSwitch(ctx, getResult()));
632       }
633     });
634   }
635 
636   public void postBalanceSwitch(final boolean oldValue, final boolean newValue)
637       throws IOException {
638     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
639       @Override
640       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
641           throws IOException {
642         oserver.postBalanceSwitch(ctx, oldValue, newValue);
643       }
644     });
645   }
646 
647   public void preShutdown() throws IOException {
648     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
649       @Override
650       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
651           throws IOException {
652         oserver.preShutdown(ctx);
653       }
654       @Override
655       public void postEnvCall(MasterEnvironment env) {
656         // invoke coprocessor stop method
657         shutdown(env);
658       }
659     });
660   }
661 
662   public void preStopMaster() throws IOException {
663     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
664       @Override
665       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
666           throws IOException {
667         oserver.preStopMaster(ctx);
668       }
669       @Override
670       public void postEnvCall(MasterEnvironment env) {
671         // invoke coprocessor stop method
672         shutdown(env);
673       }
674     });
675   }
676 
677   public void preMasterInitialization() throws IOException {
678     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
679       @Override
680       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
681           throws IOException {
682         oserver.preMasterInitialization(ctx);
683       }
684     });
685   }
686 
687   public void postStartMaster() 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.postStartMaster(ctx);
693       }
694     });
695   }
696 
697   public void preSnapshot(final SnapshotDescription snapshot,
698       final HTableDescriptor hTableDescriptor) throws IOException {
699     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
700       @Override
701       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
702           throws IOException {
703         oserver.preSnapshot(ctx, snapshot, hTableDescriptor);
704       }
705     });
706   }
707 
708   public void postSnapshot(final SnapshotDescription snapshot,
709       final HTableDescriptor hTableDescriptor) 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.postSnapshot(ctx, snapshot, hTableDescriptor);
715       }
716     });
717   }
718 
719   public void preCloneSnapshot(final SnapshotDescription snapshot,
720       final HTableDescriptor hTableDescriptor) throws IOException {
721     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
722       @Override
723       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
724           throws IOException {
725         oserver.preCloneSnapshot(ctx, snapshot, hTableDescriptor);
726       }
727     });
728   }
729 
730   public void postCloneSnapshot(final SnapshotDescription snapshot,
731       final HTableDescriptor hTableDescriptor) throws IOException {
732     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
733       @Override
734       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
735           throws IOException {
736         oserver.postCloneSnapshot(ctx, snapshot, hTableDescriptor);
737       }
738     });
739   }
740 
741   public void preRestoreSnapshot(final SnapshotDescription snapshot,
742       final HTableDescriptor hTableDescriptor) throws IOException {
743     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
744       @Override
745       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
746           throws IOException {
747         oserver.preRestoreSnapshot(ctx, snapshot, hTableDescriptor);
748       }
749     });
750   }
751 
752   public void postRestoreSnapshot(final SnapshotDescription snapshot,
753       final HTableDescriptor hTableDescriptor) throws IOException {
754     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
755       @Override
756       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
757           throws IOException {
758         oserver.postRestoreSnapshot(ctx, snapshot, hTableDescriptor);
759       }
760     });
761   }
762 
763   public void preDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
764     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
765       @Override
766       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
767           throws IOException {
768         oserver.preDeleteSnapshot(ctx, snapshot);
769       }
770     });
771   }
772 
773   public void postDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
774     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
775       @Override
776       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
777           throws IOException {
778         oserver.postDeleteSnapshot(ctx, snapshot);
779       }
780     });
781   }
782 
783   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
784       final List<HTableDescriptor> descriptors) throws IOException {
785     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
786       @Override
787       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
788           throws IOException {
789         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors);
790       }
791     });
792   }
793 
794   public void postGetTableDescriptors(final List<HTableDescriptor> descriptors)
795       throws IOException {
796     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
797       @Override
798       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
799           throws IOException {
800         oserver.postGetTableDescriptors(ctx, descriptors);
801       }
802     });
803   }
804 
805   public void preTableFlush(final TableName tableName) throws IOException {
806     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
807       @Override
808       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
809           throws IOException {
810         oserver.preTableFlush(ctx, tableName);
811       }
812     });
813   }
814 
815   public void postTableFlush(final TableName tableName) throws IOException {
816     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
817       @Override
818       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
819           throws IOException {
820         oserver.postTableFlush(ctx, tableName);
821       }
822     });
823   }
824 
825   private static abstract class CoprocessorOperation
826       extends ObserverContext<MasterCoprocessorEnvironment> {
827     public CoprocessorOperation() {
828     }
829 
830     public abstract void call(MasterObserver oserver,
831         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException;
832 
833     public void postEnvCall(MasterEnvironment env) {
834     }
835   }
836 
837   private static abstract class CoprocessorOperationWithResult<T> extends CoprocessorOperation {
838     private T result = null;
839     public void setResult(final T result) { this.result = result; }
840     public T getResult() { return this.result; }
841   }
842 
843   private <T> T execOperationWithResult(final T defaultValue,
844       final CoprocessorOperationWithResult<T> ctx) throws IOException {
845     if (ctx == null) return defaultValue;
846     ctx.setResult(defaultValue);
847     execOperation(ctx);
848     return ctx.getResult();
849   }
850 
851   private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
852     if (ctx == null) return false;
853     boolean bypass = false;
854     for (MasterEnvironment env: coprocessors) {
855       if (env.getInstance() instanceof MasterObserver) {
856         ctx.prepare(env);
857         Thread currentThread = Thread.currentThread();
858         ClassLoader cl = currentThread.getContextClassLoader();
859         try {
860           currentThread.setContextClassLoader(env.getClassLoader());
861           ctx.call((MasterObserver)env.getInstance(), ctx);
862         } catch (Throwable e) {
863           handleCoprocessorThrowable(env, e);
864         } finally {
865           currentThread.setContextClassLoader(cl);
866         }
867         bypass |= ctx.shouldBypass();
868         if (ctx.shouldComplete()) {
869           break;
870         }
871       }
872       ctx.postEnvCall(env);
873     }
874     return bypass;
875   }
876 }