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.hbase.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   public void preGetNamespaceDescriptor(final String namespaceName)
143       throws IOException {
144     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
145       @Override
146       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
147           throws IOException {
148         oserver.preGetNamespaceDescriptor(ctx, namespaceName);
149       }
150     });
151   }
152 
153   public void postGetNamespaceDescriptor(final NamespaceDescriptor ns)
154       throws IOException {
155     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
156       @Override
157       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
158           throws IOException {
159         oserver.postGetNamespaceDescriptor(ctx, ns);
160       }
161     });
162   }
163 
164   public boolean preListNamespaceDescriptors(final List<NamespaceDescriptor> descriptors)
165       throws IOException {
166     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
167       @Override
168       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
169           throws IOException {
170         oserver.preListNamespaceDescriptors(ctx, descriptors);
171       }
172     });
173   }
174 
175   public void postListNamespaceDescriptors(final List<NamespaceDescriptor> descriptors)
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.postListNamespaceDescriptors(ctx, descriptors);
182       }
183     });
184   }
185 
186   /* Implementation of hooks for invoking MasterObservers */
187 
188   public void preCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
189       throws IOException {
190     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
191       @Override
192       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
193           throws IOException {
194         oserver.preCreateTable(ctx, htd, regions);
195       }
196     });
197   }
198 
199   public void postCreateTable(final HTableDescriptor htd, final HRegionInfo[] regions)
200       throws IOException {
201     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
202       @Override
203       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
204           throws IOException {
205         oserver.postCreateTable(ctx, htd, regions);
206       }
207     });
208   }
209 
210   public void preCreateTableHandler(final HTableDescriptor htd, final HRegionInfo[] regions)
211       throws IOException {
212     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
213       @Override
214       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
215           throws IOException {
216         oserver.preCreateTableHandler(ctx, htd, regions);
217       }
218     });
219   }
220 
221   public void postCreateTableHandler(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.postCreateTableHandler(ctx, htd, regions);
228       }
229     });
230   }
231 
232   public void preDeleteTable(final TableName tableName) throws IOException {
233     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
234       @Override
235       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
236           throws IOException {
237         oserver.preDeleteTable(ctx, tableName);
238       }
239     });
240   }
241 
242   public void postDeleteTable(final TableName tableName) throws IOException {
243     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
244       @Override
245       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
246           throws IOException {
247         oserver.postDeleteTable(ctx, tableName);
248       }
249     });
250   }
251 
252   public void preDeleteTableHandler(final TableName tableName) throws IOException {
253     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
254       @Override
255       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
256           throws IOException {
257         oserver.preDeleteTableHandler(ctx, tableName);
258       }
259     });
260   }
261 
262   public void postDeleteTableHandler(final TableName tableName) throws IOException {
263     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
264       @Override
265       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
266           throws IOException {
267         oserver.postDeleteTableHandler(ctx, tableName);
268       }
269     });
270   }
271 
272   public void preTruncateTable(final TableName tableName) throws IOException {
273     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
274       @Override
275       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
276           throws IOException {
277         oserver.preTruncateTable(ctx, tableName);
278       }
279     });
280   }
281 
282   public void postTruncateTable(final TableName tableName) throws IOException {
283     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
284       @Override
285       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
286           throws IOException {
287         oserver.postTruncateTable(ctx, tableName);
288       }
289     });
290   }
291 
292   public void preTruncateTableHandler(final TableName tableName) throws IOException {
293     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
294       @Override
295       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
296           throws IOException {
297         oserver.preTruncateTableHandler(ctx, tableName);
298       }
299     });
300   }
301 
302   public void postTruncateTableHandler(final TableName tableName) throws IOException {
303     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
304       @Override
305       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
306           throws IOException {
307         oserver.postTruncateTableHandler(ctx, tableName);
308       }
309     });
310   }
311 
312   public void preModifyTable(final TableName tableName, final HTableDescriptor htd)
313       throws IOException {
314     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
315       @Override
316       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
317           throws IOException {
318         oserver.preModifyTable(ctx, tableName, htd);
319       }
320     });
321   }
322 
323   public void postModifyTable(final TableName tableName, final HTableDescriptor htd)
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.postModifyTable(ctx, tableName, htd);
330       }
331     });
332   }
333 
334   public void preModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
335       throws IOException {
336     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
337       @Override
338       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
339           throws IOException {
340         oserver.preModifyTableHandler(ctx, tableName, htd);
341       }
342     });
343   }
344 
345   public void postModifyTableHandler(final TableName tableName, final HTableDescriptor htd)
346       throws IOException {
347     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
348       @Override
349       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
350           throws IOException {
351         oserver.postModifyTableHandler(ctx, tableName, htd);
352       }
353     });
354   }
355 
356   public boolean preAddColumn(final TableName tableName, final HColumnDescriptor column)
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.preAddColumn(ctx, tableName, column);
363       }
364     });
365   }
366 
367   public void postAddColumn(final TableName tableName, final HColumnDescriptor column)
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.postAddColumn(ctx, tableName, column);
374       }
375     });
376   }
377 
378   public boolean preAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
379       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.preAddColumnHandler(ctx, tableName, column);
385       }
386     });
387   }
388 
389   public void postAddColumnHandler(final TableName tableName, final HColumnDescriptor column)
390       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.postAddColumnHandler(ctx, tableName, column);
396       }
397     });
398   }
399 
400   public boolean preModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
401       throws IOException {
402     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
403       @Override
404       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
405           throws IOException {
406         oserver.preModifyColumn(ctx, tableName, descriptor);
407       }
408     });
409   }
410 
411   public void postModifyColumn(final TableName tableName, final HColumnDescriptor descriptor)
412       throws IOException {
413     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
414       @Override
415       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
416           throws IOException {
417         oserver.postModifyColumn(ctx, tableName, descriptor);
418       }
419     });
420   }
421 
422   public boolean preModifyColumnHandler(final TableName tableName,
423       final HColumnDescriptor descriptor) throws IOException {
424     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
425       @Override
426       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
427           throws IOException {
428         oserver.preModifyColumnHandler(ctx, tableName, descriptor);
429       }
430     });
431   }
432 
433   public void postModifyColumnHandler(final TableName tableName,
434       final HColumnDescriptor descriptor) throws IOException {
435     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
436       @Override
437       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
438           throws IOException {
439         oserver.postModifyColumnHandler(ctx, tableName, descriptor);
440       }
441     });
442   }
443 
444   public boolean preDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
445     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
446       @Override
447       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
448           throws IOException {
449         oserver.preDeleteColumn(ctx, tableName, c);
450       }
451     });
452   }
453 
454   public void postDeleteColumn(final TableName tableName, final byte [] c) throws IOException {
455     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
456       @Override
457       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
458           throws IOException {
459         oserver.postDeleteColumn(ctx, tableName, c);
460       }
461     });
462   }
463 
464   public boolean preDeleteColumnHandler(final TableName tableName, final byte[] c)
465       throws IOException {
466     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
467       @Override
468       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
469           throws IOException {
470         oserver.preDeleteColumnHandler(ctx, tableName, c);
471       }
472     });
473   }
474 
475   public void postDeleteColumnHandler(final TableName tableName, final byte[] c)
476       throws IOException {
477     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
478       @Override
479       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
480           throws IOException {
481         oserver.postDeleteColumnHandler(ctx, tableName, c);
482       }
483     });
484   }
485 
486   public void preEnableTable(final TableName tableName) throws IOException {
487     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
488       @Override
489       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
490           throws IOException {
491         oserver.preEnableTable(ctx, tableName);
492       }
493     });
494   }
495 
496   public void postEnableTable(final TableName tableName) throws IOException {
497     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
498       @Override
499       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
500           throws IOException {
501         oserver.postEnableTable(ctx, tableName);
502       }
503     });
504   }
505 
506   public void preEnableTableHandler(final TableName tableName) throws IOException {
507     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
508       @Override
509       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
510           throws IOException {
511         oserver.preEnableTableHandler(ctx, tableName);
512       }
513     });
514   }
515 
516   public void postEnableTableHandler(final TableName tableName) throws IOException {
517     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
518       @Override
519       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
520           throws IOException {
521         oserver.postEnableTableHandler(ctx, tableName);
522       }
523     });
524   }
525 
526   public void preDisableTable(final TableName tableName) throws IOException {
527     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
528       @Override
529       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
530           throws IOException {
531         oserver.preDisableTable(ctx, tableName);
532       }
533     });
534   }
535 
536   public void postDisableTable(final TableName tableName) throws IOException {
537     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
538       @Override
539       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
540           throws IOException {
541         oserver.postDisableTable(ctx, tableName);
542       }
543     });
544   }
545 
546   public void preDisableTableHandler(final TableName tableName) throws IOException {
547     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
548       @Override
549       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
550           throws IOException {
551         oserver.preDisableTableHandler(ctx, tableName);
552       }
553     });
554   }
555 
556   public void postDisableTableHandler(final TableName tableName) throws IOException {
557     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
558       @Override
559       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
560           throws IOException {
561         oserver.postDisableTableHandler(ctx, tableName);
562       }
563     });
564   }
565 
566   public boolean preMove(final HRegionInfo region, final ServerName srcServer,
567       final ServerName destServer) throws IOException {
568     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
569       @Override
570       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
571           throws IOException {
572         oserver.preMove(ctx, region, srcServer, destServer);
573       }
574     });
575   }
576 
577   public void postMove(final HRegionInfo region, final ServerName srcServer,
578       final ServerName destServer) throws IOException {
579     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
580       @Override
581       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
582           throws IOException {
583         oserver.postMove(ctx, region, srcServer, destServer);
584       }
585     });
586   }
587 
588   public boolean preAssign(final HRegionInfo regionInfo) throws IOException {
589     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
590       @Override
591       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
592           throws IOException {
593         oserver.preAssign(ctx, regionInfo);
594       }
595     });
596   }
597 
598   public void postAssign(final HRegionInfo regionInfo) throws IOException {
599     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
600       @Override
601       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
602           throws IOException {
603         oserver.postAssign(ctx, regionInfo);
604       }
605     });
606   }
607 
608   public boolean preUnassign(final HRegionInfo regionInfo, final boolean force)
609       throws IOException {
610     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
611       @Override
612       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
613           throws IOException {
614         oserver.preUnassign(ctx, regionInfo, force);
615       }
616     });
617   }
618 
619   public void postUnassign(final HRegionInfo regionInfo, final boolean force) throws IOException {
620     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
621       @Override
622       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
623           throws IOException {
624         oserver.postUnassign(ctx, regionInfo, force);
625       }
626     });
627   }
628 
629   public void preRegionOffline(final HRegionInfo regionInfo) throws IOException {
630     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
631       @Override
632       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
633           throws IOException {
634         oserver.preRegionOffline(ctx, regionInfo);
635       }
636     });
637   }
638 
639   public void postRegionOffline(final HRegionInfo regionInfo) throws IOException {
640     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
641       @Override
642       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
643           throws IOException {
644         oserver.postRegionOffline(ctx, regionInfo);
645       }
646     });
647   }
648 
649   public boolean preBalance() throws IOException {
650     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
651       @Override
652       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
653           throws IOException {
654         oserver.preBalance(ctx);
655       }
656     });
657   }
658 
659   public void postBalance(final List<RegionPlan> plans) throws IOException {
660     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
661       @Override
662       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
663           throws IOException {
664         oserver.postBalance(ctx, plans);
665       }
666     });
667   }
668 
669   public boolean preBalanceSwitch(final boolean b) throws IOException {
670     return execOperationWithResult(b, coprocessors.isEmpty() ? null :
671         new CoprocessorOperationWithResult<Boolean>() {
672       @Override
673       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
674           throws IOException {
675         setResult(oserver.preBalanceSwitch(ctx, getResult()));
676       }
677     });
678   }
679 
680   public void postBalanceSwitch(final boolean oldValue, final boolean newValue)
681       throws IOException {
682     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
683       @Override
684       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
685           throws IOException {
686         oserver.postBalanceSwitch(ctx, oldValue, newValue);
687       }
688     });
689   }
690 
691   public void preShutdown() throws IOException {
692     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
693       @Override
694       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
695           throws IOException {
696         oserver.preShutdown(ctx);
697       }
698       @Override
699       public void postEnvCall(MasterEnvironment env) {
700         // invoke coprocessor stop method
701         shutdown(env);
702       }
703     });
704   }
705 
706   public void preStopMaster() throws IOException {
707     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
708       @Override
709       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
710           throws IOException {
711         oserver.preStopMaster(ctx);
712       }
713       @Override
714       public void postEnvCall(MasterEnvironment env) {
715         // invoke coprocessor stop method
716         shutdown(env);
717       }
718     });
719   }
720 
721   public void preMasterInitialization() throws IOException {
722     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
723       @Override
724       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
725           throws IOException {
726         oserver.preMasterInitialization(ctx);
727       }
728     });
729   }
730 
731   public void postStartMaster() 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.postStartMaster(ctx);
737       }
738     });
739   }
740 
741   public void preSnapshot(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.preSnapshot(ctx, snapshot, hTableDescriptor);
748       }
749     });
750   }
751 
752   public void postSnapshot(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.postSnapshot(ctx, snapshot, hTableDescriptor);
759       }
760     });
761   }
762 
763   public void preCloneSnapshot(final SnapshotDescription snapshot,
764       final HTableDescriptor hTableDescriptor) throws IOException {
765     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
766       @Override
767       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
768           throws IOException {
769         oserver.preCloneSnapshot(ctx, snapshot, hTableDescriptor);
770       }
771     });
772   }
773 
774   public void postCloneSnapshot(final SnapshotDescription snapshot,
775       final HTableDescriptor hTableDescriptor) throws IOException {
776     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
777       @Override
778       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
779           throws IOException {
780         oserver.postCloneSnapshot(ctx, snapshot, hTableDescriptor);
781       }
782     });
783   }
784 
785   public void preRestoreSnapshot(final SnapshotDescription snapshot,
786       final HTableDescriptor hTableDescriptor) throws IOException {
787     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
788       @Override
789       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
790           throws IOException {
791         oserver.preRestoreSnapshot(ctx, snapshot, hTableDescriptor);
792       }
793     });
794   }
795 
796   public void postRestoreSnapshot(final SnapshotDescription snapshot,
797       final HTableDescriptor hTableDescriptor) throws IOException {
798     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
799       @Override
800       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
801           throws IOException {
802         oserver.postRestoreSnapshot(ctx, snapshot, hTableDescriptor);
803       }
804     });
805   }
806 
807   public void preDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
808     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
809       @Override
810       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
811           throws IOException {
812         oserver.preDeleteSnapshot(ctx, snapshot);
813       }
814     });
815   }
816 
817   public void postDeleteSnapshot(final SnapshotDescription snapshot) throws IOException {
818     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
819       @Override
820       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
821           throws IOException {
822         oserver.postDeleteSnapshot(ctx, snapshot);
823       }
824     });
825   }
826 
827   @Deprecated
828   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
829     final List<HTableDescriptor> descriptors) throws IOException {
830     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
831       @Override
832       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
833           throws IOException {
834         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors);
835       }
836     });
837   }
838 
839   @Deprecated
840   public void postGetTableDescriptors(final List<HTableDescriptor> descriptors)
841       throws IOException {
842     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
843       @Override
844       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
845           throws IOException {
846         oserver.postGetTableDescriptors(ctx, descriptors);
847       }
848     });
849   }
850 
851   public boolean preGetTableDescriptors(final List<TableName> tableNamesList,
852       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
853     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
854       @Override
855       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
856           throws IOException {
857         oserver.preGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
858       }
859     });
860   }
861 
862   public void postGetTableDescriptors(final List<TableName> tableNamesList,
863       final List<HTableDescriptor> descriptors, final String regex) throws IOException {
864     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
865       @Override
866       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
867           throws IOException {
868         oserver.postGetTableDescriptors(ctx, tableNamesList, descriptors, regex);
869       }
870     });
871   }
872 
873   public boolean preGetTableNames(final List<HTableDescriptor> descriptors,
874       final String regex) throws IOException {
875     return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
876       @Override
877       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
878           throws IOException {
879         oserver.preGetTableNames(ctx, descriptors, regex);
880       }
881     });
882   }
883 
884   public void postGetTableNames(final List<HTableDescriptor> descriptors,
885       final String regex) throws IOException {
886     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
887       @Override
888       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
889           throws IOException {
890         oserver.postGetTableNames(ctx, descriptors, regex);
891       }
892     });
893   }
894 
895   public void preTableFlush(final TableName tableName) 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.preTableFlush(ctx, tableName);
901       }
902     });
903   }
904 
905   public void postTableFlush(final TableName tableName) throws IOException {
906     execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
907       @Override
908       public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
909           throws IOException {
910         oserver.postTableFlush(ctx, tableName);
911       }
912     });
913   }
914 
915   private static abstract class CoprocessorOperation
916       extends ObserverContext<MasterCoprocessorEnvironment> {
917     public CoprocessorOperation() {
918     }
919 
920     public abstract void call(MasterObserver oserver,
921         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException;
922 
923     public void postEnvCall(MasterEnvironment env) {
924     }
925   }
926 
927   private static abstract class CoprocessorOperationWithResult<T> extends CoprocessorOperation {
928     private T result = null;
929     public void setResult(final T result) { this.result = result; }
930     public T getResult() { return this.result; }
931   }
932 
933   private <T> T execOperationWithResult(final T defaultValue,
934       final CoprocessorOperationWithResult<T> ctx) throws IOException {
935     if (ctx == null) return defaultValue;
936     ctx.setResult(defaultValue);
937     execOperation(ctx);
938     return ctx.getResult();
939   }
940 
941   private boolean execOperation(final CoprocessorOperation ctx) throws IOException {
942     if (ctx == null) return false;
943     boolean bypass = false;
944     for (MasterEnvironment env: coprocessors) {
945       if (env.getInstance() instanceof MasterObserver) {
946         ctx.prepare(env);
947         Thread currentThread = Thread.currentThread();
948         ClassLoader cl = currentThread.getContextClassLoader();
949         try {
950           currentThread.setContextClassLoader(env.getClassLoader());
951           ctx.call((MasterObserver)env.getInstance(), ctx);
952         } catch (Throwable e) {
953           handleCoprocessorThrowable(env, e);
954         } finally {
955           currentThread.setContextClassLoader(cl);
956         }
957         bypass |= ctx.shouldBypass();
958         if (ctx.shouldComplete()) {
959           break;
960         }
961       }
962       ctx.postEnvCall(env);
963     }
964     return bypass;
965   }
966 }