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