Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id CCE67200D2F for ; Wed, 1 Nov 2017 16:16:55 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id CB7B1160C09; Wed, 1 Nov 2017 15:16:55 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id BC74D160BE6 for ; Wed, 1 Nov 2017 16:16:52 +0100 (CET) Received: (qmail 41751 invoked by uid 500); 1 Nov 2017 15:16:51 -0000 Mailing-List: contact commits-help@hbase.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@hbase.apache.org Delivered-To: mailing list commits@hbase.apache.org Received: (qmail 41524 invoked by uid 99); 1 Nov 2017 15:16:51 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 01 Nov 2017 15:16:51 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 84CCDE009D; Wed, 1 Nov 2017 15:16:50 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: git-site-role@apache.org To: commits@hbase.apache.org Date: Wed, 01 Nov 2017 15:16:54 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [05/51] [partial] hbase-site git commit: Published site at . archived-at: Wed, 01 Nov 2017 15:16:56 -0000 http://git-wip-us.apache.org/repos/asf/hbase-site/blob/93ae3fc9/devapidocs/src-html/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.ObserverOperationWithResult.html ---------------------------------------------------------------------- diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.ObserverOperationWithResult.html b/devapidocs/src-html/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.ObserverOperationWithResult.html index cb1b7e5..2bc02b6 100644 --- a/devapidocs/src-html/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.ObserverOperationWithResult.html +++ b/devapidocs/src-html/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.ObserverOperationWithResult.html @@ -7,728 +7,736 @@
001/*
-002 *
-003 * Licensed to the Apache Software Foundation (ASF) under one
-004 * or more contributor license agreements.  See the NOTICE file
-005 * distributed with this work for additional information
-006 * regarding copyright ownership.  The ASF licenses this file
-007 * to you under the Apache License, Version 2.0 (the
-008 * "License"); you may not use this file except in compliance
-009 * with the License.  You may obtain a copy of the License at
-010 *
-011 * http://www.apache.org/licenses/LICENSE-2.0
-012 *
-013 * Unless required by applicable law or agreed to in writing, software
-014 * distributed under the License is distributed on an "AS IS" BASIS,
-015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-016 * See the License for the specific language governing permissions and
-017 * limitations under the License.
-018 */
-019
-020package org.apache.hadoop.hbase.coprocessor;
-021
-022import java.io.IOException;
-023import java.util.ArrayList;
-024import java.util.Collections;
-025import java.util.Comparator;
-026import java.util.HashSet;
-027import java.util.List;
-028import java.util.Optional;
-029import java.util.Set;
-030import java.util.TreeSet;
-031import java.util.UUID;
-032import java.util.concurrent.ConcurrentSkipListSet;
-033import java.util.concurrent.atomic.AtomicInteger;
-034import java.util.function.Function;
-035
-036import org.apache.commons.logging.Log;
-037import org.apache.commons.logging.LogFactory;
-038import org.apache.yetus.audience.InterfaceAudience;
-039import org.apache.yetus.audience.InterfaceStability;
-040import org.apache.hadoop.conf.Configuration;
-041import org.apache.hadoop.fs.Path;
-042import org.apache.hadoop.hbase.Abortable;
-043import org.apache.hadoop.hbase.Coprocessor;
-044import org.apache.hadoop.hbase.CoprocessorEnvironment;
-045import org.apache.hadoop.hbase.DoNotRetryIOException;
-046import org.apache.hadoop.hbase.HBaseInterfaceAudience;
-047import org.apache.hadoop.hbase.HConstants;
-048import org.apache.hadoop.hbase.ipc.RpcServer;
-049import org.apache.hadoop.hbase.security.User;
-050import org.apache.hadoop.hbase.shaded.com.google.common.annotations.VisibleForTesting;
-051import org.apache.hadoop.hbase.util.CoprocessorClassLoader;
-052import org.apache.hadoop.hbase.util.SortedList;
-053
-054/**
-055 * Provides the common setup framework and runtime services for coprocessor
-056 * invocation from HBase services.
-057 * @param <C> type of specific coprocessor this host will handle
-058 * @param <E> type of specific coprocessor environment this host requires.
-059 * provides
-060 */
-061@InterfaceAudience.Private
-062public abstract class CoprocessorHost<C extends Coprocessor, E extends CoprocessorEnvironment<C>> {
-063  public static final String REGION_COPROCESSOR_CONF_KEY =
-064      "hbase.coprocessor.region.classes";
-065  public static final String REGIONSERVER_COPROCESSOR_CONF_KEY =
-066      "hbase.coprocessor.regionserver.classes";
-067  public static final String USER_REGION_COPROCESSOR_CONF_KEY =
-068      "hbase.coprocessor.user.region.classes";
-069  public static final String MASTER_COPROCESSOR_CONF_KEY =
-070      "hbase.coprocessor.master.classes";
-071  public static final String WAL_COPROCESSOR_CONF_KEY =
-072    "hbase.coprocessor.wal.classes";
-073  public static final String ABORT_ON_ERROR_KEY = "hbase.coprocessor.abortonerror";
-074  public static final boolean DEFAULT_ABORT_ON_ERROR = true;
-075  public static final String COPROCESSORS_ENABLED_CONF_KEY = "hbase.coprocessor.enabled";
-076  public static final boolean DEFAULT_COPROCESSORS_ENABLED = true;
-077  public static final String USER_COPROCESSORS_ENABLED_CONF_KEY =
-078    "hbase.coprocessor.user.enabled";
-079  public static final boolean DEFAULT_USER_COPROCESSORS_ENABLED = true;
-080
-081  private static final Log LOG = LogFactory.getLog(CoprocessorHost.class);
-082  protected Abortable abortable;
-083  /** Ordered set of loaded coprocessors with lock */
-084  protected final SortedList<E> coprocEnvironments =
-085      new SortedList<>(new EnvironmentPriorityComparator());
-086  protected Configuration conf;
-087  // unique file prefix to use for local copies of jars when classloading
-088  protected String pathPrefix;
-089  protected AtomicInteger loadSequence = new AtomicInteger();
-090
-091  public CoprocessorHost(Abortable abortable) {
-092    this.abortable = abortable;
-093    this.pathPrefix = UUID.randomUUID().toString();
-094  }
-095
-096  /**
-097   * Not to be confused with the per-object _coprocessors_ (above),
-098   * coprocessorNames is static and stores the set of all coprocessors ever
-099   * loaded by any thread in this JVM. It is strictly additive: coprocessors are
-100   * added to coprocessorNames, by checkAndLoadInstance() but are never removed, since
-101   * the intention is to preserve a history of all loaded coprocessors for
-102   * diagnosis in case of server crash (HBASE-4014).
-103   */
-104  private static Set<String> coprocessorNames =
-105      Collections.synchronizedSet(new HashSet<String>());
-106
-107  public static Set<String> getLoadedCoprocessors() {
-108    synchronized (coprocessorNames) {
-109      return new HashSet(coprocessorNames);
-110    }
-111  }
-112
-113  /**
-114   * Used to create a parameter to the HServerLoad constructor so that
-115   * HServerLoad can provide information about the coprocessors loaded by this
-116   * regionserver.
-117   * (HBASE-4070: Improve region server metrics to report loaded coprocessors
-118   * to master).
-119   */
-120  public Set<String> getCoprocessors() {
-121    Set<String> returnValue = new TreeSet<>();
-122    for (E e: coprocEnvironments) {
-123      returnValue.add(e.getInstance().getClass().getSimpleName());
-124    }
-125    return returnValue;
-126  }
-127
-128  /**
-129   * Load system coprocessors once only. Read the class names from configuration.
-130   * Called by constructor.
-131   */
-132  protected void loadSystemCoprocessors(Configuration conf, String confKey) {
-133    boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
-134      DEFAULT_COPROCESSORS_ENABLED);
-135    if (!coprocessorsEnabled) {
-136      return;
-137    }
-138
-139    Class<?> implClass;
-140
-141    // load default coprocessors from configure file
-142    String[] defaultCPClasses = conf.getStrings(confKey);
-143    if (defaultCPClasses == null || defaultCPClasses.length == 0)
-144      return;
-145
-146    int priority = Coprocessor.PRIORITY_SYSTEM;
-147    for (String className : defaultCPClasses) {
-148      className = className.trim();
-149      if (findCoprocessor(className) != null) {
-150        // If already loaded will just continue
-151        LOG.warn("Attempted duplicate loading of " + className + "; skipped");
-152        continue;
-153      }
-154      ClassLoader cl = this.getClass().getClassLoader();
-155      Thread.currentThread().setContextClassLoader(cl);
-156      try {
-157        implClass = cl.loadClass(className);
-158        // Add coprocessors as we go to guard against case where a coprocessor is specified twice
-159        // in the configuration
-160        E env = checkAndLoadInstance(implClass, priority, conf);
-161        if (env != null) {
-162          this.coprocEnvironments.add(env);
-163          LOG.info(
-164              "System coprocessor " + className + " was loaded " + "successfully with priority (" + priority + ").");
-165          ++priority;
-166        }
-167      } catch (Throwable t) {
-168        // We always abort if system coprocessors cannot be loaded
-169        abortServer(className, t);
-170      }
-171    }
-172  }
-173
-174  /**
-175   * Load a coprocessor implementation into the host
-176   * @param path path to implementation jar
-177   * @param className the main class name
-178   * @param priority chaining priority
-179   * @param conf configuration for coprocessor
-180   * @throws java.io.IOException Exception
-181   */
-182  public E load(Path path, String className, int priority,
-183      Configuration conf) throws IOException {
-184    String[] includedClassPrefixes = null;
-185    if (conf.get(HConstants.CP_HTD_ATTR_INCLUSION_KEY) != null){
-186      String prefixes = conf.get(HConstants.CP_HTD_ATTR_INCLUSION_KEY);
-187      includedClassPrefixes = prefixes.split(";");
-188    }
-189    return load(path, className, priority, conf, includedClassPrefixes);
-190  }
-191
-192  /**
-193   * Load a coprocessor implementation into the host
-194   * @param path path to implementation jar
-195   * @param className the main class name
-196   * @param priority chaining priority
-197   * @param conf configuration for coprocessor
-198   * @param includedClassPrefixes class name prefixes to include
-199   * @throws java.io.IOException Exception
-200   */
-201  public E load(Path path, String className, int priority,
-202      Configuration conf, String[] includedClassPrefixes) throws IOException {
-203    Class<?> implClass;
-204    LOG.debug("Loading coprocessor class " + className + " with path " +
-205        path + " and priority " + priority);
-206
-207    ClassLoader cl = null;
-208    if (path == null) {
-209      try {
-210        implClass = getClass().getClassLoader().loadClass(className);
-211      } catch (ClassNotFoundException e) {
-212        throw new IOException("No jar path specified for " + className);
-213      }
-214    } else {
-215      cl = CoprocessorClassLoader.getClassLoader(
-216        path, getClass().getClassLoader(), pathPrefix, conf);
-217      try {
-218        implClass = ((CoprocessorClassLoader)cl).loadClass(className, includedClassPrefixes);
-219      } catch (ClassNotFoundException e) {
-220        throw new IOException("Cannot load external coprocessor class " + className, e);
-221      }
-222    }
-223
-224    //load custom code for coprocessor
-225    Thread currentThread = Thread.currentThread();
-226    ClassLoader hostClassLoader = currentThread.getContextClassLoader();
-227    try{
-228      // switch temporarily to the thread classloader for custom CP
-229      currentThread.setContextClassLoader(cl);
-230      E cpInstance = checkAndLoadInstance(implClass, priority, conf);
-231      return cpInstance;
-232    } finally {
-233      // restore the fresh (host) classloader
-234      currentThread.setContextClassLoader(hostClassLoader);
-235    }
-236  }
-237
-238  @VisibleForTesting
-239  public void load(Class<? extends C> implClass, int priority, Configuration conf)
-240      throws IOException {
-241    E env = checkAndLoadInstance(implClass, priority, conf);
-242    coprocEnvironments.add(env);
-243  }
-244
-245  /**
-246   * @param implClass Implementation class
-247   * @param priority priority
-248   * @param conf configuration
-249   * @throws java.io.IOException Exception
-250   */
-251  public E checkAndLoadInstance(Class<?> implClass, int priority, Configuration conf)
-252      throws IOException {
-253    // create the instance
-254    C impl;
-255    try {
-256      impl = checkAndGetInstance(implClass);
-257      if (impl == null) {
-258        LOG.error("Cannot load coprocessor " + implClass.getSimpleName());
-259        return null;
-260      }
-261    } catch (InstantiationException|IllegalAccessException e) {
-262      throw new IOException(e);
-263    }
-264    // create the environment
-265    E env = createEnvironment(impl, priority, loadSequence.incrementAndGet(), conf);
-266    env.startup();
-267    // HBASE-4014: maintain list of loaded coprocessors for later crash analysis
-268    // if server (master or regionserver) aborts.
-269    coprocessorNames.add(implClass.getName());
-270    return env;
-271  }
-272
-273  /**
-274   * Called when a new Coprocessor class is loaded
-275   */
-276  public abstract E createEnvironment(C instance, int priority, int sequence, Configuration conf);
-277
-278  /**
-279   * Called when a new Coprocessor class needs to be loaded. Checks if type of the given class
-280   * is what the corresponding host implementation expects. If it is of correct type, returns an
-281   * instance of the coprocessor to be loaded. If not, returns null.
-282   * If an exception occurs when trying to create instance of a coprocessor, it's passed up and
-283   * eventually results into server aborting.
-284   */
-285  public abstract C checkAndGetInstance(Class<?> implClass)
-286      throws InstantiationException, IllegalAccessException;
-287
-288  public void shutdown(E e) {
-289    if (LOG.isDebugEnabled()) {
-290      LOG.debug("Stop coprocessor " + e.getInstance().getClass().getName());
-291    }
-292    e.shutdown();
-293  }
-294
-295  /**
-296   * Find coprocessors by full class name or simple name.
-297   */
-298  public C findCoprocessor(String className) {
-299    for (E env: coprocEnvironments) {
-300      if (env.getInstance().getClass().getName().equals(className) ||
-301          env.getInstance().getClass().getSimpleName().equals(className)) {
-302        return env.getInstance();
-303      }
-304    }
-305    return null;
-306  }
-307
-308  @VisibleForTesting
-309  public <T extends C> T findCoprocessor(Class<T> cls) {
-310    for (E env: coprocEnvironments) {
-311      if (cls.isAssignableFrom(env.getInstance().getClass())) {
-312        return (T) env.getInstance();
-313      }
-314    }
-315    return null;
-316  }
-317
-318  /**
-319   * Find list of coprocessors that extend/implement the given class/interface
-320   * @param cls the class/interface to look for
-321   * @return the list of coprocessors, or null if not found
-322   */
-323  public <T extends C> List<T> findCoprocessors(Class<T> cls) {
-324    ArrayList<T> ret = new ArrayList<>();
+002 * Licensed to the Apache Software Foundation (ASF) under one
+003 * or more contributor license agreements.  See the NOTICE file
+004 * distributed with this work for additional information
+005 * regarding copyright ownership.  The ASF licenses this file
+006 * to you under the Apache License, Version 2.0 (the
+007 * "License"); you may not use this file except in compliance
+008 * with the License.  You may obtain a copy of the License at
+009 *
+010 * http://www.apache.org/licenses/LICENSE-2.0
+011 *
+012 * Unless required by applicable law or agreed to in writing, software
+013 * distributed under the License is distributed on an "AS IS" BASIS,
+014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+015 * See the License for the specific language governing permissions and
+016 * limitations under the License.
+017 */
+018
+019package org.apache.hadoop.hbase.coprocessor;
+020
+021import java.io.IOException;
+022import java.util.ArrayList;
+023import java.util.Collections;
+024import java.util.Comparator;
+025import java.util.HashSet;
+026import java.util.List;
+027import java.util.Optional;
+028import java.util.Set;
+029import java.util.TreeSet;
+030import java.util.UUID;
+031import java.util.concurrent.ConcurrentSkipListSet;
+032import java.util.concurrent.atomic.AtomicInteger;
+033import java.util.function.Function;
+034
+035import org.apache.commons.logging.Log;
+036import org.apache.commons.logging.LogFactory;
+037import org.apache.yetus.audience.InterfaceAudience;
+038import org.apache.hadoop.conf.Configuration;
+039import org.apache.hadoop.fs.Path;
+040import org.apache.hadoop.hbase.Abortable;
+041import org.apache.hadoop.hbase.Coprocessor;
+042import org.apache.hadoop.hbase.CoprocessorEnvironment;
+043import org.apache.hadoop.hbase.DoNotRetryIOException;
+044import org.apache.hadoop.hbase.HConstants;
+045import org.apache.hadoop.hbase.ipc.RpcServer;
+046import org.apache.hadoop.hbase.security.User;
+047import org.apache.hadoop.hbase.shaded.com.google.common.annotations.VisibleForTesting;
+048import org.apache.hadoop.hbase.util.CoprocessorClassLoader;
+049import org.apache.hadoop.hbase.util.SortedList;
+050
+051/**
+052 * Provides the common setup framework and runtime services for coprocessor
+053 * invocation from HBase services.
+054 * @param <C> type of specific coprocessor this host will handle
+055 * @param <E> type of specific coprocessor environment this host requires.
+056 * provides
+057 */
+058@InterfaceAudience.Private
+059public abstract class CoprocessorHost<C extends Coprocessor, E extends CoprocessorEnvironment<C>> {
+060  public static final String REGION_COPROCESSOR_CONF_KEY =
+061      "hbase.coprocessor.region.classes";
+062  public static final String REGIONSERVER_COPROCESSOR_CONF_KEY =
+063      "hbase.coprocessor.regionserver.classes";
+064  public static final String USER_REGION_COPROCESSOR_CONF_KEY =
+065      "hbase.coprocessor.user.region.classes";
+066  public static final String MASTER_COPROCESSOR_CONF_KEY =
+067      "hbase.coprocessor.master.classes";
+068  public static final String WAL_COPROCESSOR_CONF_KEY =
+069    "hbase.coprocessor.wal.classes";
+070  public static final String ABORT_ON_ERROR_KEY = "hbase.coprocessor.abortonerror";
+071  public static final boolean DEFAULT_ABORT_ON_ERROR = true;
+072  public static final String COPROCESSORS_ENABLED_CONF_KEY = "hbase.coprocessor.enabled";
+073  public static final boolean DEFAULT_COPROCESSORS_ENABLED = true;
+074  public static final String USER_COPROCESSORS_ENABLED_CONF_KEY =
+075    "hbase.coprocessor.user.enabled";
+076  public static final boolean DEFAULT_USER_COPROCESSORS_ENABLED = true;
+077
+078  private static final Log LOG = LogFactory.getLog(CoprocessorHost.class);
+079  protected Abortable abortable;
+080  /** Ordered set of loaded coprocessors with lock */
+081  protected final SortedList<E> coprocEnvironments =
+082      new SortedList<>(new EnvironmentPriorityComparator());
+083  protected Configuration conf;
+084  // unique file prefix to use for local copies of jars when classloading
+085  protected String pathPrefix;
+086  protected AtomicInteger loadSequence = new AtomicInteger();
+087
+088  public CoprocessorHost(Abortable abortable) {
+089    this.abortable = abortable;
+090    this.pathPrefix = UUID.randomUUID().toString();
+091  }
+092
+093  /**
+094   * Not to be confused with the per-object _coprocessors_ (above),
+095   * coprocessorNames is static and stores the set of all coprocessors ever
+096   * loaded by any thread in this JVM. It is strictly additive: coprocessors are
+097   * added to coprocessorNames, by checkAndLoadInstance() but are never removed, since
+098   * the intention is to preserve a history of all loaded coprocessors for
+099   * diagnosis in case of server crash (HBASE-4014).
+100   */
+101  private static Set<String> coprocessorNames =
+102      Collections.synchronizedSet(new HashSet<String>());
+103
+104  public static Set<String> getLoadedCoprocessors() {
+105    synchronized (coprocessorNames) {
+106      return new HashSet(coprocessorNames);
+107    }
+108  }
+109
+110  /**
+111   * Used to create a parameter to the HServerLoad constructor so that
+112   * HServerLoad can provide information about the coprocessors loaded by this
+113   * regionserver.
+114   * (HBASE-4070: Improve region server metrics to report loaded coprocessors
+115   * to master).
+116   */
+117  public Set<String> getCoprocessors() {
+118    Set<String> returnValue = new TreeSet<>();
+119    for (E e: coprocEnvironments) {
+120      returnValue.add(e.getInstance().getClass().getSimpleName());
+121    }
+122    return returnValue;
+123  }
+124
+125  /**
+126   * Load system coprocessors once only. Read the class names from configuration.
+127   * Called by constructor.
+128   */
+129  protected void loadSystemCoprocessors(Configuration conf, String confKey) {
+130    boolean coprocessorsEnabled = conf.getBoolean(COPROCESSORS_ENABLED_CONF_KEY,
+131      DEFAULT_COPROCESSORS_ENABLED);
+132    if (!coprocessorsEnabled) {
+133      return;
+134    }
+135
+136    Class<?> implClass;
+137
+138    // load default coprocessors from configure file
+139    String[] defaultCPClasses = conf.getStrings(confKey);
+140    if (defaultCPClasses == null || defaultCPClasses.length == 0)
+141      return;
+142
+143    int priority = Coprocessor.PRIORITY_SYSTEM;
+144    for (String className : defaultCPClasses) {
+145      className = className.trim();
+146      if (findCoprocessor(className) != null) {
+147        // If already loaded will just continue
+148        LOG.warn("Attempted duplicate loading of " + className + "; skipped");
+149        continue;
+150      }
+151      ClassLoader cl = this.getClass().getClassLoader();
+152      Thread.currentThread().setContextClassLoader(cl);
+153      try {
+154        implClass = cl.loadClass(className);
+155        // Add coprocessors as we go to guard against case where a coprocessor is specified twice
+156        // in the configuration
+157        E env = checkAndLoadInstance(implClass, priority, conf);
+158        if (env != null) {
+159          this.coprocEnvironments.add(env);
+160          LOG.info(
+161              "System coprocessor " + className + " was loaded " + "successfully with priority (" + priority + ").");
+162          ++priority;
+163        }
+164      } catch (Throwable t) {
+165        // We always abort if system coprocessors cannot be loaded
+166        abortServer(className, t);
+167      }
+168    }
+169  }
+170
+171  /**
+172   * Load a coprocessor implementation into the host
+173   * @param path path to implementation jar
+174   * @param className the main class name
+175   * @param priority chaining priority
+176   * @param conf configuration for coprocessor
+177   * @throws java.io.IOException Exception
+178   */
+179  public E load(Path path, String className, int priority,
+180      Configuration conf) throws IOException {
+181    String[] includedClassPrefixes = null;
+182    if (conf.get(HConstants.CP_HTD_ATTR_INCLUSION_KEY) != null){
+183      String prefixes = conf.get(HConstants.CP_HTD_ATTR_INCLUSION_KEY);
+184      includedClassPrefixes = prefixes.split(";");
+185    }
+186    return load(path, className, priority, conf, includedClassPrefixes);
+187  }
+188
+189  /**
+190   * Load a coprocessor implementation into the host
+191   * @param path path to implementation jar
+192   * @param className the main class name
+193   * @param priority chaining priority
+194   * @param conf configuration for coprocessor
+195   * @param includedClassPrefixes class name prefixes to include
+196   * @throws java.io.IOException Exception
+197   */
+198  public E load(Path path, String className, int priority,
+199      Configuration conf, String[] includedClassPrefixes) throws IOException {
+200    Class<?> implClass;
+201    LOG.debug("Loading coprocessor class " + className + " with path " +
+202        path + " and priority " + priority);
+203
+204    ClassLoader cl = null;
+205    if (path == null) {
+206      try {
+207        implClass = getClass().getClassLoader().loadClass(className);
+208      } catch (ClassNotFoundException e) {
+209        throw new IOException("No jar path specified for " + className);
+210      }
+211    } else {
+212      cl = CoprocessorClassLoader.getClassLoader(
+213        path, getClass().getClassLoader(), pathPrefix, conf);
+214      try {
+215        implClass = ((CoprocessorClassLoader)cl).loadClass(className, includedClassPrefixes);
+216      } catch (ClassNotFoundException e) {
+217        throw new IOException("Cannot load external coprocessor class " + className, e);
+218      }
+219    }
+220
+221    //load custom code for coprocessor
+222    Thread currentThread = Thread.currentThread();
+223    ClassLoader hostClassLoader = currentThread.getContextClassLoader();
+224    try{
+225      // switch temporarily to the thread classloader for custom CP
+226      currentThread.setContextClassLoader(cl);
+227      E cpInstance = checkAndLoadInstance(implClass, priority, conf);
+228      return cpInstance;
+229    } finally {
+230      // restore the fresh (host) classloader
+231      currentThread.setContextClassLoader(hostClassLoader);
+232    }
+233  }
+234
+235  @VisibleForTesting
+236  public void load(Class<? extends C> implClass, int priority, Configuration conf)
+237      throws IOException {
+238    E env = checkAndLoadInstance(implClass, priority, conf);
+239    coprocEnvironments.add(env);
+240  }
+241
+242  /**
+243   * @param implClass Implementation class
+244   * @param priority priority
+245   * @param conf configuration
+246   * @throws java.io.IOException Exception
+247   */
+248  public E checkAndLoadInstance(Class<?> implClass, int priority, Configuration conf)
+249      throws IOException {
+250    // create the instance
+251    C impl;
+252    try {
+253      impl = checkAndGetInstance(implClass);
+254      if (impl == null) {
+255        LOG.error("Cannot load coprocessor " + implClass.getSimpleName());
+256        return null;
+257      }
+258    } catch (InstantiationException|IllegalAccessException e) {
+259      throw new IOException(e);
+260    }
+261    // create the environment
+262    E env = createEnvironment(impl, priority, loadSequence.incrementAndGet(), conf);
+263    env.startup();
+264    // HBASE-4014: maintain list of loaded coprocessors for later crash analysis
+265    // if server (master or regionserver) aborts.
+266    coprocessorNames.add(implClass.getName());
+267    return env;
+268  }
+269
+270  /**
+271   * Called when a new Coprocessor class is loaded
+272   */
+273  public abstract E createEnvironment(C instance, int priority, int sequence, Configuration conf);
+274
+275  /**
+276   * Called when a new Coprocessor class needs to be loaded. Checks if type of the given class
+277   * is what the corresponding host implementation expects. If it is of correct type, returns an
+278   * instance of the coprocessor to be loaded. If not, returns null.
+279   * If an exception occurs when trying to create instance of a coprocessor, it's passed up and
+280   * eventually results into server aborting.
+281   */
+282  public abstract C checkAndGetInstance(Class<?> implClass)
+283      throws InstantiationException, IllegalAccessException;
+284
+285  public void shutdown(E e) {
+286    if (LOG.isDebugEnabled()) {
+287      LOG.debug("Stop coprocessor " + e.getInstance().getClass().getName());
+288    }
+289    e.shutdown();
+290  }
+291
+292  /**
+293   * Find coprocessors by full class name or simple name.
+294   */
+295  public C findCoprocessor(String className) {
+296    for (E env: coprocEnvironments) {
+297      if (env.getInstance().getClass().getName().equals(className) ||
+298          env.getInstance().getClass().getSimpleName().equals(className)) {
+299        return env.getInstance();
+300      }
+301    }
+302    return null;
+303  }
+304
+305  @VisibleForTesting
+306  public <T extends C> T findCoprocessor(Class<T> cls) {
+307    for (E env: coprocEnvironments) {
+308      if (cls.isAssignableFrom(env.getInstance().getClass())) {
+309        return (T) env.getInstance();
+310      }
+311    }
+312    return null;
+313  }
+314
+315  /**
+316   * Find list of coprocessors that extend/implement the given class/interface
+317   * @param cls the class/interface to look for
+318   * @return the list of coprocessors, or null if not found
+319   */
+320  public <T extends C> List<T> findCoprocessors(Class<T> cls) {
+321    ArrayList<T> ret = new ArrayList<>();
+322
+323    for (E env: coprocEnvironments) {
+324      C cp = env.getInstance();
 325
-326    for (E env: coprocEnvironments) {
-327      C cp = env.getInstance();
-328
-329      if(cp != null) {
-330        if (cls.isAssignableFrom(cp.getClass())) {
-331          ret.add((T)cp);
-332        }
-333      }
-334    }
-335    return ret;
-336  }
-337
-338  /**
-339   * Find a coprocessor environment by class name
-340   * @param className the class name
-341   * @return the coprocessor, or null if not found
-342   */
-343  @VisibleForTesting
-344  public E findCoprocessorEnvironment(String className) {
-345    for (E env: coprocEnvironments) {
-346      if (env.getInstance().getClass().getName().equals(className) ||
-347          env.getInstance().getClass().getSimpleName().equals(className)) {
-348        return env;
-349      }
-350    }
-351    return null;
-352  }
-353
-354  /**
-355   * Retrieves the set of classloaders used to instantiate Coprocessor classes defined in external
-356   * jar files.
-357   * @return A set of ClassLoader instances
-358   */
-359  Set<ClassLoader> getExternalClassLoaders() {
-360    Set<ClassLoader> externalClassLoaders = new HashSet<>();
-361    final ClassLoader systemClassLoader = this.getClass().getClassLoader();
-362    for (E env : coprocEnvironments) {
-363      ClassLoader cl = env.getInstance().getClass().getClassLoader();
-364      if (cl != systemClassLoader){
-365        //do not include system classloader
-366        externalClassLoaders.add(cl);
-367      }
-368    }
-369    return externalClassLoaders;
-370  }
-371
-372  /**
-373   * Environment priority comparator.
-374   * Coprocessors are chained in sorted order.
-375   */
-376  static class EnvironmentPriorityComparator implements Comparator<CoprocessorEnvironment> {
-377    @Override
-378    public int compare(final CoprocessorEnvironment env1,
-379        final CoprocessorEnvironment env2) {
-380      if (env1.getPriority() < env2.getPriority()) {
-381        return -1;
-382      } else if (env1.getPriority() > env2.getPriority()) {
-383        return 1;
-384      }
-385      if (env1.getLoadSequence() < env2.getLoadSequence()) {
-386        return -1;
-387      } else if (env1.getLoadSequence() > env2.getLoadSequence()) {
-388        return 1;
-389      }
-390      return 0;
-391    }
-392  }
-393
-394  protected void abortServer(final E environment, final Throwable e) {
-395    abortServer(environment.getInstance().getClass().getName(), e);
-396  }
-397
-398  protected void abortServer(final String coprocessorName, final Throwable e) {
-399    String message = "The coprocessor " + coprocessorName + " threw " + e.toString();
-400    LOG.error(message, e);
-401    if (abortable != null) {
-402      abortable.abort(message, e);
-403    } else {
-404      LOG.warn("No available Abortable, process was not aborted");
-405    }
-406  }
-407
-408  /**
-409   * This is used by coprocessor hooks which are declared to throw IOException
-410   * (or its subtypes). For such hooks, we should handle throwable objects
-411   * depending on the Throwable's type. Those which are instances of
-412   * IOException should be passed on to the client. This is in conformance with
-413   * the HBase idiom regarding IOException: that it represents a circumstance
-414   * that should be passed along to the client for its own handling. For
-415   * example, a coprocessor that implements access controls would throw a
-416   * subclass of IOException, such as AccessDeniedException, in its preGet()
-417   * method to prevent an unauthorized client's performing a Get on a particular
-418   * table.
-419   * @param env Coprocessor Environment
-420   * @param e Throwable object thrown by coprocessor.
-421   * @exception IOException Exception
-422   */
-423  // Note to devs: Class comments of all observers ({@link MasterObserver}, {@link WALObserver},
-424  // etc) mention this nuance of our exception handling so that coprocessor can throw appropriate
-425  // exceptions depending on situation. If any changes are made to this logic, make sure to
-426  // update all classes' comments.
-427  protected void handleCoprocessorThrowable(final E env, final Throwable e) throws IOException {
-428    if (e instanceof IOException) {
-429      throw (IOException)e;
-430    }
-431    // If we got here, e is not an IOException. A loaded coprocessor has a
-432    // fatal bug, and the server (master or regionserver) should remove the
-433    // faulty coprocessor from its set of active coprocessors. Setting
-434    // 'hbase.coprocessor.abortonerror' to true will cause abortServer(),
-435    // which may be useful in development and testing environments where
-436    // 'failing fast' for error analysis is desired.
-437    if (env.getConfiguration().getBoolean(ABORT_ON_ERROR_KEY, DEFAULT_ABORT_ON_ERROR)) {
-438      // server is configured to abort.
-439      abortServer(env, e);
-440    } else {
-441      // If available, pull a table name out of the environment
-442      if(env instanceof RegionCoprocessorEnvironment) {
-443        String tableName = ((RegionCoprocessorEnvironment)env).getRegionInfo().getTable().getNameAsString();
-444        LOG.error("Removing coprocessor '" + env.toString() + "' from table '"+ tableName + "'", e);
-445      } else {
-446        LOG.error("Removing coprocessor '" + env.toString() + "' from " +
-447                "environment",e);
-448      }
-449
-450      coprocEnvironments.remove(env);
-451      try {
-452        shutdown(env);
-453      } catch (Exception x) {
-454        LOG.error("Uncaught exception when shutting down coprocessor '"
-455            + env.toString() + "'", x);
-456      }
-457      throw new DoNotRetryIOException("Coprocessor: '" + env.toString() +
-458          "' threw: '" + e + "' and has been removed from the active " +
-459          "coprocessor set.", e);
-460    }
-461  }
-462
-463  /**
-464   * Used to gracefully handle fallback to deprecated methods when we
-465   * evolve coprocessor APIs.
-466   *
-467   * When a particular Coprocessor API is updated to change methods, hosts can support fallback
-468   * to the deprecated API by using this method to determine if an instance implements the new API.
-469   * In the event that said support is partial, then in the face of a runtime issue that prevents
-470   * proper operation {@link #legacyWarning(Class, String)} should be used to let operators know.
-471   *
-472   * For examples of this in action, see the implementation of
-473   * <ul>
-474   *   <li>{@link org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost}
-475   *   <li>{@link org.apache.hadoop.hbase.regionserver.wal.WALCoprocessorHost}
-476   * </ul>
-477   *
-478   * @param clazz Coprocessor you wish to evaluate
-479   * @param methodName the name of the non-deprecated method version
-480   * @param parameterTypes the Class of the non-deprecated method's arguments in the order they are
-481   *     declared.
-482   */
-483  @InterfaceAudience.Private
-484  protected static boolean useLegacyMethod(final Class<? extends Coprocessor> clazz,
-485      final String methodName, final Class<?>... parameterTypes) {
-486    boolean useLegacy;
-487    // Use reflection to see if they implement the non-deprecated version
-488    try {
-489      clazz.getDeclaredMethod(methodName, parameterTypes);
-490      LOG.debug("Found an implementation of '" + methodName + "' that uses updated method " +
-491          "signature. Skipping legacy support for invocations in '" + clazz +"'.");
-492      useLegacy = false;
-493    } catch (NoSuchMethodException exception) {
-494      useLegacy = true;
-495    } catch (SecurityException exception) {
-496      LOG.warn("The Security Manager denied our attempt to detect if the coprocessor '" + clazz +
-497          "' requires legacy support; assuming it does. If you get later errors about legacy " +
-498          "coprocessor use, consider updating your security policy to allow access to the package" +
-499          " and declared members of your implementation.");
-500      LOG.debug("Details of Security Manager rejection.", exception);
-501      useLegacy = true;
-502    }
-503    return useLegacy;
-504  }
-505
-506  /**
-507   * Used to limit legacy handling to once per Coprocessor class per classloader.
-508   */
-509  private static final Set<Class<? extends Coprocessor>> legacyWarning =
-510      new ConcurrentSkipListSet<>(
-511          new Comparator<Class<? extends Coprocessor>>() {
-512            @Override
-513            public int compare(Class<? extends Coprocessor> c1, Class<? extends Coprocessor> c2) {
-514              if (c1.equals(c2)) {
-515                return 0;
-516              }
-517              return c1.getName().compareTo(c2.getName());
-518            }
-519          });
-520
-521  /**
-522   * limits the amount of logging to once per coprocessor class.
-523   * Used in concert with {@link #useLegacyMethod(Class, String, Class[])} when a runtime issue
-524   * prevents properly supporting the legacy version of a coprocessor API.
-525   * Since coprocessors can be in tight loops this serves to limit the amount of log spam we create.
-526   */
-527  @InterfaceAudience.Private
-528  protected void legacyWarning(final Class<? extends Coprocessor> clazz, final String message) {
-529    if(legacyWarning.add(clazz)) {
-530      LOG.error("You have a legacy coprocessor loaded and there are events we can't map to the " +
-531          " deprecated API. Your coprocessor will not see these events.  Please update '" + clazz +
-532          "'. Details of the problem: " + message);
-533    }
-534  }
-535
-536  /**
-537   * Implementations defined function to get an observer of type {@code O} from a coprocessor of
-538   * type {@code C}. Concrete implementations of CoprocessorHost define one getter for each
-539   * observer they can handle. For e.g. RegionCoprocessorHost will use 3 getters, one for
-540   * each of RegionObserver, EndpointObserver and BulkLoadObserver.
-541   * These getters are used by {@code ObserverOperation} to get appropriate observer from the
-542   * coprocessor.
-543   */
-544  @FunctionalInterface
-545  public interface ObserverGetter<C, O> extends Function<C, Optional<O>> {}
+326      if(cp != null) {
+327        if (cls.isAssignableFrom(cp.getClass())) {
+328          ret.add((T)cp);
+329        }
+330      }
+331    }
+332    return ret;
+333  }
+334
+335  /**
+336   * Find a coprocessor environment by class name
+337   * @param className the class name
+338   * @return the coprocessor, or null if not found
+339   */
+340  @VisibleForTesting
+341  public E findCoprocessorEnvironment(String className) {
+342    for (E env: coproc