HBASE-20119 Introduce a pojo class to carry coprocessor information in order to 
make TableDescriptorBuilder accept multiple cp at once

Signed-off-by: Ted Yu <[email protected]>
Signed-off-by: Michael Stack <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/95596e8b
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/95596e8b
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/95596e8b

Branch: refs/heads/branch-2
Commit: 95596e8ba7569d131573ebc7ab679ce9ef3fe655
Parents: 5ea0db0
Author: Chia-Ping Tsai <[email protected]>
Authored: Fri Mar 16 01:17:06 2018 +0800
Committer: Chia-Ping Tsai <[email protected]>
Committed: Fri Mar 16 01:26:08 2018 +0800

----------------------------------------------------------------------
 .../archetypes/exemplars/client/HelloHBase.java |   2 +-
 .../apache/hadoop/hbase/HTableDescriptor.java   |  25 +-
 .../hbase/client/CoprocessorDescriptor.java     |  51 ++++
 .../client/CoprocessorDescriptorBuilder.java    | 118 +++++++++
 .../hadoop/hbase/client/TableDescriptor.java    |   7 +-
 .../hbase/client/TableDescriptorBuilder.java    | 244 ++++++++++---------
 .../hbase/shaded/protobuf/ProtobufUtil.java     |   2 +-
 .../hbase/client/TestCoprocessorDescriptor.java | 100 ++++++++
 .../client/TestTableDescriptorBuilder.java      |  82 ++-----
 .../org/apache/hadoop/hbase/HConstants.java     |  19 +-
 .../hbase/coprocessor/TestClassLoading.java     |   2 +-
 .../hbase/coprocessor/TestSecureExport.java     |   6 +-
 .../client/example/ExportEndpointExample.java   |   4 +-
 .../example/TestScanModifyingObserver.java      |   4 +-
 .../example/TestValueReplacingCompaction.java   |   4 +-
 .../TestWriteHeavyIncrementObserver.java        |   4 +-
 ...IncrementObserverWithMemStoreCompaction.java |   4 +-
 .../TestZooKeeperScanPolicyObserver.java        |   4 +-
 .../hbase/IntegrationTestDDLMasterFailover.java |   2 +-
 .../hbase/chaos/actions/AddColumnAction.java    |   2 +-
 .../actions/TestChangeSplitPolicyAction.java    |   2 +-
 .../mapreduce/IntegrationTestBulkLoad.java      |   2 +-
 .../hadoop/hbase/mttr/IntegrationTestMTTR.java  |   2 +-
 .../mapreduce/TestCellBasedImportExport2.java   |  14 +-
 .../hbase/mapreduce/TestImportExport.java       |  14 +-
 .../replication/TestVerifyReplication.java      |   2 +-
 .../hbase/rsgroup/TestRSGroupsWithACL.java      |   2 +-
 .../hadoop/hbase/coprocessor/package-info.java  |   2 +-
 .../org/apache/hadoop/hbase/master/HMaster.java |   2 +-
 .../regionserver/RegionCoprocessorHost.java     |  71 +-----
 .../hbase/security/access/AccessController.java |   2 +-
 .../CoprocessorWhitelistMasterObserver.java     |  68 ++----
 .../hbase/tool/LoadIncrementalHFiles.java       |   2 +-
 .../hadoop/hbase/util/FSTableDescriptors.java   |  46 ++--
 .../org/apache/hadoop/hbase/util/HBaseFsck.java |   2 +-
 .../hadoop/hbase/util/RegionSplitter.java       |   2 +-
 .../hadoop/hbase/AcidGuaranteesTestBase.java    |   2 +-
 .../hadoop/hbase/AcidGuaranteesTestTool.java    |   2 +-
 .../hadoop/hbase/HBaseTestingUtility.java       |   6 +-
 .../org/apache/hadoop/hbase/TestZooKeeper.java  |   6 +-
 .../client/AbstractTestCIOperationTimeout.java  |   4 +-
 .../hbase/client/AbstractTestCIRpcTimeout.java  |   4 +-
 .../hadoop/hbase/client/TestAsyncAdminBase.java |   2 +-
 .../hbase/client/TestAsyncClusterAdminApi.java  |   2 +-
 .../hbase/client/TestAsyncRegionAdminApi.java   |   5 +-
 ...estAsyncReplicationAdminApiWithClusters.java |   4 +-
 .../hbase/client/TestAsyncTableAdminApi.java    |  10 +-
 .../hbase/client/TestAsyncTableAdminApi2.java   |  16 +-
 .../hbase/client/TestAsyncTableAdminApi3.java   |   2 +-
 .../hbase/client/TestAsyncTableBatch.java       |   2 +-
 .../apache/hadoop/hbase/client/TestCISleep.java |   9 +-
 .../hbase/client/TestDropTimeoutRequest.java    |   4 +-
 .../hbase/client/TestFromClientSide3.java       |   4 +-
 .../client/TestMalformedCellFromClient.java     |   2 +-
 .../hbase/client/TestReplicaWithCluster.java    |   6 +-
 .../hbase/client/TestResultFromCoprocessor.java |   4 +-
 .../hbase/client/TestServerLoadDurability.java  |   2 +-
 .../coprocessor/TestCoreRegionCoprocessor.java  |   2 +-
 .../TestPassCustomCellViaRegionObserver.java    |   4 +-
 .../hbase/coprocessor/TestWALObserver.java      |   8 +-
 .../master/TestAssignmentManagerMetrics.java    |  10 +-
 .../hadoop/hbase/master/TestCatalogJanitor.java |   2 +-
 .../master/assignment/MockMasterServices.java   |   2 +-
 .../assignment/TestRogueRSAssignment.java       |   2 +-
 .../TestFavoredStochasticBalancerPickers.java   |   2 +-
 .../master/cleaner/TestSnapshotFromMaster.java  |   3 +-
 .../MasterProcedureTestingUtility.java          |   2 +-
 .../procedure/TestMasterObserverPostCalls.java  |  12 +-
 .../master/procedure/TestProcedurePriority.java |   2 +-
 .../regionserver/TestCacheOnWriteInSchema.java  |   2 +-
 .../TestCompactionArchiveConcurrentClose.java   |   2 +-
 .../TestCompactionArchiveIOException.java       |   2 +-
 .../TestCompactionLifeCycleTracker.java         |   6 +-
 .../hbase/regionserver/TestDefaultMemStore.java |   2 +-
 .../regionserver/TestFlushLifeCycleTracker.java |   4 +-
 .../regionserver/TestHRegionReplayEvents.java   |   2 +-
 .../hadoop/hbase/regionserver/TestHStore.java   |   2 +-
 .../regionserver/TestMobStoreCompaction.java    |   2 +-
 .../regionserver/TestRegionServerMetrics.java   |   2 +-
 .../TestRegionServerReadRequestMetrics.java     |   8 +-
 .../regionserver/TestSplitWalDataLoss.java      |   2 +-
 .../TestStoreFileRefresherChore.java            |   2 +-
 .../regionserver/TestSwitchToStreamRead.java    |   2 +-
 .../TestWALMonotonicallyIncreasingSeqId.java    |   2 +-
 .../compactions/TestFIFOCompactionPolicy.java   |   8 +-
 .../TestCompactionWithThroughputController.java |   4 +-
 .../TestFlushWithThroughputController.java      |   2 +-
 .../regionserver/wal/AbstractTestFSWAL.java     |   8 +-
 .../wal/AbstractTestLogRolling.java             |   2 +-
 .../hbase/regionserver/wal/TestDurability.java  |   2 +-
 .../hbase/regionserver/wal/TestFSHLog.java      |   4 +-
 .../regionserver/wal/TestLogRollAbort.java      |   2 +-
 .../hbase/regionserver/wal/TestLogRolling.java  |   4 +-
 .../replication/TestMasterReplication.java      |   6 +-
 .../replication/TestNamespaceReplication.java   |   8 +-
 .../hbase/replication/TestReplicationBase.java  |   4 +-
 .../replication/TestReplicationSmallTests.java  |   2 +-
 .../hbase/security/access/SecureTestUtil.java   |   2 +-
 ...sibilityLabelsOnNewVersionBehaviorTable.java |   2 +-
 .../TestVisibilityLabelsWithDeletes.java        |   4 +-
 .../hbase/snapshot/MobSnapshotTestingUtils.java |   6 +-
 .../hbase/snapshot/SnapshotTestingUtils.java    |   4 +-
 .../hbase/tool/TestLoadIncrementalHFiles.java   |   4 +-
 .../TestLoadIncrementalHFilesSplitRecovery.java |   2 +-
 .../hbase/util/TestFSTableDescriptors.java      |   4 +-
 .../hadoop/hbase/wal/TestFSHLogProvider.java    |   8 +-
 .../apache/hadoop/hbase/wal/TestWALFactory.java |   4 +-
 .../hbase/wal/WALPerformanceEvaluation.java     |   2 +-
 hbase-shell/src/main/ruby/hbase/admin.rb        |   1 +
 109 files changed, 715 insertions(+), 496 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-archetypes/hbase-client-project/src/main/java/org/apache/hbase/archetypes/exemplars/client/HelloHBase.java
----------------------------------------------------------------------
diff --git 
a/hbase-archetypes/hbase-client-project/src/main/java/org/apache/hbase/archetypes/exemplars/client/HelloHBase.java
 
b/hbase-archetypes/hbase-client-project/src/main/java/org/apache/hbase/archetypes/exemplars/client/HelloHBase.java
index ee2f034..5164ab2 100644
--- 
a/hbase-archetypes/hbase-client-project/src/main/java/org/apache/hbase/archetypes/exemplars/client/HelloHBase.java
+++ 
b/hbase-archetypes/hbase-client-project/src/main/java/org/apache/hbase/archetypes/exemplars/client/HelloHBase.java
@@ -112,7 +112,7 @@ public final class HelloHBase {
               + "], with one Column Family ["
               + Bytes.toString(MY_COLUMN_FAMILY_NAME) + "].");
       TableDescriptor desc = TableDescriptorBuilder.newBuilder(MY_TABLE_NAME)
-              
.addColumnFamily(ColumnFamilyDescriptorBuilder.of(MY_COLUMN_FAMILY_NAME))
+              
.setColumnFamily(ColumnFamilyDescriptorBuilder.of(MY_COLUMN_FAMILY_NAME))
               .build();
       admin.createTable(desc);
     }

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
----------------------------------------------------------------------
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
index e512b2c..e59ea45 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
@@ -20,6 +20,7 @@ package org.apache.hadoop.hbase;
 
 import java.io.IOException;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -27,6 +28,8 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.client.CoprocessorDescriptor;
+import org.apache.hadoop.hbase.client.CoprocessorDescriptorBuilder;
 import org.apache.yetus.audience.InterfaceAudience;
 import org.apache.hadoop.hbase.client.Durability;
 import org.apache.hadoop.hbase.client.TableDescriptor;
@@ -433,7 +436,7 @@ public class HTableDescriptor implements TableDescriptor, 
Comparable<HTableDescr
    * @param family HColumnDescriptor of family to add.
    */
   public HTableDescriptor addFamily(final HColumnDescriptor family) {
-    getDelegateeForModification().addColumnFamily(family);
+    getDelegateeForModification().setColumnFamily(family);
     return this;
   }
 
@@ -699,7 +702,7 @@ public class HTableDescriptor implements TableDescriptor, 
Comparable<HTableDescr
    * @throws IOException
    */
   public HTableDescriptor addCoprocessor(String className) throws IOException {
-    getDelegateeForModification().addCoprocessor(className);
+    getDelegateeForModification().setCoprocessor(className);
     return this;
   }
 
@@ -719,7 +722,12 @@ public class HTableDescriptor implements TableDescriptor, 
Comparable<HTableDescr
   public HTableDescriptor addCoprocessor(String className, Path jarFilePath,
                              int priority, final Map<String, String> kvs)
   throws IOException {
-    getDelegateeForModification().addCoprocessor(className, jarFilePath, 
priority, kvs);
+    getDelegateeForModification().setCoprocessor(
+      CoprocessorDescriptorBuilder.newBuilder(className)
+        .setJarPath(jarFilePath == null ? null : jarFilePath.toString())
+        .setPriority(priority)
+        .setProperties(kvs == null ? Collections.emptyMap() : kvs)
+        .build());
     return this;
   }
 
@@ -734,7 +742,7 @@ public class HTableDescriptor implements TableDescriptor, 
Comparable<HTableDescr
    * @throws IOException
    */
   public HTableDescriptor addCoprocessorWithSpec(final String specStr) throws 
IOException {
-    getDelegateeForModification().addCoprocessorWithSpec(specStr);
+    getDelegateeForModification().setCoprocessorWithSpec(specStr);
     return this;
   }
 
@@ -749,14 +757,19 @@ public class HTableDescriptor implements TableDescriptor, 
Comparable<HTableDescr
     return delegatee.hasCoprocessor(classNameToMatch);
   }
 
+  @Override
+  public Collection<CoprocessorDescriptor> getCoprocessorDescriptors() {
+    return delegatee.getCoprocessorDescriptors();
+  }
+
   /**
    * Return the list of attached co-processor represented by their name 
className
    *
    * @return The list of co-processors classNames
    */
-  @Override
   public List<String> getCoprocessors() {
-    return delegatee.getCoprocessors();
+    return 
getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName)
+      .collect(Collectors.toList());
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/CoprocessorDescriptor.java
----------------------------------------------------------------------
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/CoprocessorDescriptor.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/CoprocessorDescriptor.java
new file mode 100644
index 0000000..72d588b
--- /dev/null
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/CoprocessorDescriptor.java
@@ -0,0 +1,51 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.client;
+
+import java.util.Map;
+import java.util.Optional;
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * CoprocessorDescriptor contains the details about how to build a coprocessor.
+ * This class is a pojo so there are no checks for the details carried by this 
class.
+ * Use {@link CoprocessorDescriptorBuilder} to instantiate a 
CoprocessorDescriptor
+ */
[email protected]
+public interface CoprocessorDescriptor {
+  /**
+   * @return the name of the class or interface represented by this object.
+   */
+  String getClassName();
+
+  /**
+   * @return Path of the jar file. If it's null, the class will be loaded from 
default classloader.
+   */
+  Optional<String> getJarPath();
+
+  /**
+   * @return The order to execute this coprocessor
+   */
+  int getPriority();
+
+  /**
+   * @return Arbitrary key-value parameter pairs passed into the  coprocessor.
+   */
+  Map<String, String> getProperties();
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/CoprocessorDescriptorBuilder.java
----------------------------------------------------------------------
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/CoprocessorDescriptorBuilder.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/CoprocessorDescriptorBuilder.java
new file mode 100644
index 0000000..71d1264
--- /dev/null
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/CoprocessorDescriptorBuilder.java
@@ -0,0 +1,118 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.client;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.TreeMap;
+import org.apache.hadoop.hbase.Coprocessor;
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * Used to build the {@link CoprocessorDescriptor}
+ */
[email protected]
+public final class CoprocessorDescriptorBuilder {
+
+  public static CoprocessorDescriptor of(String className) {
+    return new CoprocessorDescriptorBuilder(className).build();
+  }
+
+  public static CoprocessorDescriptorBuilder newBuilder(String className) {
+    return new CoprocessorDescriptorBuilder(className);
+  }
+
+  private final String className;
+  private String jarPath;
+  private int priority = Coprocessor.PRIORITY_USER;
+  private Map<String, String> properties = new TreeMap();
+
+  public CoprocessorDescriptorBuilder setJarPath(String jarPath) {
+    this.jarPath = jarPath;
+    return this;
+  }
+
+  public CoprocessorDescriptorBuilder setPriority(int priority) {
+    this.priority = priority;
+    return this;
+  }
+
+  public CoprocessorDescriptorBuilder setProperty(String key, String value) {
+    this.properties.put(key, value);
+    return this;
+  }
+
+  public CoprocessorDescriptorBuilder setProperties(Map<String, String> 
properties) {
+    this.properties.putAll(properties);
+    return this;
+  }
+
+  public CoprocessorDescriptor build() {
+    return new CoprocessorDescriptorImpl(className, jarPath, priority, 
properties);
+  }
+
+  private CoprocessorDescriptorBuilder(String className) {
+    this.className = Objects.requireNonNull(className);
+  }
+
+  private static final class CoprocessorDescriptorImpl implements 
CoprocessorDescriptor {
+    private final String className;
+    private final String jarPath;
+    private final int priority;
+    private final Map<String, String> properties;
+
+    private CoprocessorDescriptorImpl(String className, String jarPath, int 
priority,
+      Map<String, String> properties) {
+      this.className = className;
+      this.jarPath = jarPath;
+      this.priority = priority;
+      this.properties = properties;
+    }
+
+    @Override
+    public String getClassName() {
+      return className;
+    }
+
+    @Override
+    public Optional<String> getJarPath() {
+      return Optional.ofNullable(jarPath);
+    }
+
+    @Override
+    public int getPriority() {
+      return priority;
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+      return Collections.unmodifiableMap(properties);
+    }
+
+    @Override
+    public String toString() {
+      return "class:" + className
+        + ", jarPath:" + jarPath
+        + ", priority:" + priority
+        + ", properties:" + properties;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java
----------------------------------------------------------------------
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java
index 305b352..4c46a8f 100644
--- 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java
@@ -80,12 +80,11 @@ public interface TableDescriptor {
   int getColumnFamilyCount();
 
   /**
-   * Return the list of attached co-processor represented by their name
-   * className
+   * Return the list of attached co-processor represented
    *
-   * @return The list of co-processors classNames
+   * @return The list of CoprocessorDescriptor
    */
-  Collection<String> getCoprocessors();
+  Collection<CoprocessorDescriptor> getCoprocessorDescriptors();
 
   /**
    * Returns the durability setting for the table.

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java
----------------------------------------------------------------------
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java
index c1db64b..0f5d3ad 100644
--- 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java
@@ -27,12 +27,14 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.function.Function;
 import java.util.regex.Matcher;
-import org.apache.hadoop.fs.Path;
+import java.util.regex.Pattern;
 import org.apache.hadoop.hbase.Coprocessor;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
@@ -215,6 +217,24 @@ public class TableDescriptorBuilder {
   public final static byte[] NAMESPACE_COL_DESC_BYTES = Bytes.toBytes("d");
 
   /**
+   * <pre>
+   * Pattern that matches a coprocessor specification. Form is:
+   * {@code <coprocessor jar file location> '|' <class name> ['|' <priority> 
['|' <arguments>]]}
+   * where arguments are {@code <KEY> '=' <VALUE> [,...]}
+   * For example: {@code 
hdfs:///foo.jar|com.foo.FooRegionObserver|1001|arg1=1,arg2=2}
+   * </pre>
+   */
+  private static final Pattern CP_HTD_ATTR_VALUE_PATTERN =
+    Pattern.compile("(^[^\\|]*)\\|([^\\|]+)\\|[\\s]*([\\d]*)[\\s]*(\\|.*)?$");
+
+  private static final String CP_HTD_ATTR_VALUE_PARAM_KEY_PATTERN = "[^=,]+";
+  private static final String CP_HTD_ATTR_VALUE_PARAM_VALUE_PATTERN = "[^,]+";
+  private static final Pattern CP_HTD_ATTR_VALUE_PARAM_PATTERN = 
Pattern.compile(
+    "(" + CP_HTD_ATTR_VALUE_PARAM_KEY_PATTERN + ")=(" +
+      CP_HTD_ATTR_VALUE_PARAM_VALUE_PATTERN + "),?");
+  public static final Pattern CP_HTD_ATTR_KEY_PATTERN =
+    Pattern.compile("^coprocessor\\$([0-9]+)$", Pattern.CASE_INSENSITIVE);
+  /**
    * Table descriptor for namespace table
    */
   // TODO We used to set CacheDataInL1 for NS table. When we have BucketCache 
in file mode, now the
@@ -222,14 +242,14 @@ public class TableDescriptorBuilder {
   // rethink about adding back the setCacheDataInL1 for NS table.
   public static final TableDescriptor NAMESPACE_TABLEDESC
     = TableDescriptorBuilder.newBuilder(TableName.NAMESPACE_TABLE_NAME)
-                            
.addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(NAMESPACE_FAMILY_INFO_BYTES)
-                              // Ten is arbitrary number.  Keep versions to 
help debugging.
-                              .setMaxVersions(10)
-                              .setInMemory(true)
-                              .setBlocksize(8 * 1024)
-                              .setScope(HConstants.REPLICATION_SCOPE_LOCAL)
-                              .build())
-                            .build();
+      
.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(NAMESPACE_FAMILY_INFO_BYTES)
+        // Ten is arbitrary number.  Keep versions to help debugging.
+        .setMaxVersions(10)
+        .setInMemory(true)
+        .setBlocksize(8 * 1024)
+        .setScope(HConstants.REPLICATION_SCOPE_LOCAL)
+        .build())
+      .build();
   private final ModifyableTableDescriptor desc;
 
   /**
@@ -282,28 +302,36 @@ public class TableDescriptorBuilder {
     this.desc = new ModifyableTableDescriptor(desc);
   }
 
-  public TableDescriptorBuilder addCoprocessor(String className) throws 
IOException {
-    return addCoprocessor(className, null, Coprocessor.PRIORITY_USER, null);
+  public TableDescriptorBuilder setCoprocessor(String className) throws 
IOException {
+    return setCoprocessor(CoprocessorDescriptorBuilder.of(className));
+  }
+
+  public TableDescriptorBuilder setCoprocessor(CoprocessorDescriptor cpDesc) 
throws IOException {
+    desc.setCoprocessor(Objects.requireNonNull(cpDesc));
+    return this;
   }
 
-  public TableDescriptorBuilder addCoprocessor(String className, Path 
jarFilePath,
-          int priority, final Map<String, String> kvs) throws IOException {
-    desc.addCoprocessor(className, jarFilePath, priority, kvs);
+  public TableDescriptorBuilder 
setCoprocessors(Collection<CoprocessorDescriptor> cpDescs)
+    throws IOException {
+    for (CoprocessorDescriptor cpDesc : cpDescs) {
+      desc.setCoprocessor(cpDesc);
+    }
     return this;
   }
 
-  public TableDescriptorBuilder addCoprocessorWithSpec(final String specStr) 
throws IOException {
-    desc.addCoprocessorWithSpec(specStr);
+  public TableDescriptorBuilder setColumnFamily(final ColumnFamilyDescriptor 
family) {
+    desc.setColumnFamily(Objects.requireNonNull(family));
     return this;
   }
 
-  public TableDescriptorBuilder addColumnFamily(final ColumnFamilyDescriptor 
family) {
-    desc.addColumnFamily(family);
+  public TableDescriptorBuilder setColumnFamilies(
+    final Collection<ColumnFamilyDescriptor> families) {
+    families.forEach(desc::setColumnFamily);
     return this;
   }
 
   public TableDescriptorBuilder modifyColumnFamily(final 
ColumnFamilyDescriptor family) {
-    desc.modifyColumnFamily(family);
+    desc.modifyColumnFamily(Objects.requireNonNull(family));
     return this;
   }
 
@@ -421,7 +449,7 @@ public class TableDescriptorBuilder {
     newFamilies
         .forEach((cf, cfDesc) -> {
           desc.removeColumnFamily(cf);
-          
desc.addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(cfDesc).setScope(scope)
+          
desc.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(cfDesc).setScope(scope)
               .build());
         });
     return this;
@@ -839,7 +867,7 @@ public class TableDescriptorBuilder {
      * @param family to add.
      * @return the modifyable TD
      */
-    public ModifyableTableDescriptor addColumnFamily(final 
ColumnFamilyDescriptor family) {
+    public ModifyableTableDescriptor setColumnFamily(final 
ColumnFamilyDescriptor family) {
       if (family.getName() == null || family.getName().length <= 0) {
         throw new IllegalArgumentException("Family name cannot be null or 
empty");
       }
@@ -1154,8 +1182,10 @@ public class TableDescriptorBuilder {
      * @throws IOException
      * @return the modifyable TD
      */
-    public ModifyableTableDescriptor addCoprocessor(String className) throws 
IOException {
-      return addCoprocessor(className, null, Coprocessor.PRIORITY_USER, null);
+    public ModifyableTableDescriptor setCoprocessor(String className) throws 
IOException {
+      return setCoprocessor(
+        
CoprocessorDescriptorBuilder.newBuilder(className).setPriority(Coprocessor.PRIORITY_USER)
+          .build());
     }
 
     /**
@@ -1164,44 +1194,38 @@ public class TableDescriptorBuilder {
      * check if the class can be loaded or not. Whether a coprocessor is
      * loadable or not will be determined when a region is opened.
      *
-     * @param jarFilePath Path of the jar file. If it's null, the class will be
-     * loaded from default classloader.
-     * @param className Full class name.
-     * @param priority Priority
-     * @param kvs Arbitrary key-value parameter pairs passed into the
-     * coprocessor.
-     * @throws IOException
+     * @throws IOException any illegal parameter key/value
      * @return the modifyable TD
      */
-    public ModifyableTableDescriptor addCoprocessor(String className, Path 
jarFilePath,
-            int priority, final Map<String, String> kvs)
+    public ModifyableTableDescriptor setCoprocessor(CoprocessorDescriptor cp)
             throws IOException {
-      checkHasCoprocessor(className);
-
+      checkHasCoprocessor(cp.getClassName());
+      if (cp.getPriority() < 0) {
+        throw new IOException("Priority must be bigger than or equal with 
zero, current:"
+          + cp.getPriority());
+      }
       // Validate parameter kvs and then add key/values to kvString.
       StringBuilder kvString = new StringBuilder();
-      if (kvs != null) {
-        for (Map.Entry<String, String> e : kvs.entrySet()) {
-          if 
(!e.getKey().matches(HConstants.CP_HTD_ATTR_VALUE_PARAM_KEY_PATTERN)) {
-            throw new IOException("Illegal parameter key = " + e.getKey());
-          }
-          if 
(!e.getValue().matches(HConstants.CP_HTD_ATTR_VALUE_PARAM_VALUE_PATTERN)) {
-            throw new IOException("Illegal parameter (" + e.getKey()
-                    + ") value = " + e.getValue());
-          }
-          if (kvString.length() != 0) {
-            kvString.append(',');
-          }
-          kvString.append(e.getKey());
-          kvString.append('=');
-          kvString.append(e.getValue());
+      for (Map.Entry<String, String> e : cp.getProperties().entrySet()) {
+        if (!e.getKey().matches(CP_HTD_ATTR_VALUE_PARAM_KEY_PATTERN)) {
+          throw new IOException("Illegal parameter key = " + e.getKey());
+        }
+        if (!e.getValue().matches(CP_HTD_ATTR_VALUE_PARAM_VALUE_PATTERN)) {
+          throw new IOException("Illegal parameter (" + e.getKey()
+                  + ") value = " + e.getValue());
         }
+        if (kvString.length() != 0) {
+          kvString.append(',');
+        }
+        kvString.append(e.getKey());
+        kvString.append('=');
+        kvString.append(e.getValue());
       }
 
-      String value = ((jarFilePath == null) ? "" : jarFilePath.toString())
-              + "|" + className + "|" + Integer.toString(priority) + "|"
+      String value = cp.getJarPath().orElse("")
+              + "|" + cp.getClassName() + "|" + 
Integer.toString(cp.getPriority()) + "|"
               + kvString.toString();
-      return addCoprocessorToMap(value);
+      return setCoprocessorToMap(value);
     }
 
     /**
@@ -1211,18 +1235,19 @@ public class TableDescriptorBuilder {
      * loadable or not will be determined when a region is opened.
      *
      * @param specStr The Coprocessor specification all in in one String
-     * formatted so matches {@link HConstants#CP_HTD_ATTR_VALUE_PATTERN}
      * @throws IOException
      * @return the modifyable TD
+     * @deprecated used by HTableDescriptor and admin.rb.
+     *                       As of release 2.0.0, this will be removed in 
HBase 3.0.0.
      */
-    public ModifyableTableDescriptor addCoprocessorWithSpec(final String 
specStr) throws IOException {
-      String className = getCoprocessorClassNameFromSpecStr(specStr);
-      if (className == null) {
-        throw new IllegalArgumentException("Format does not match "
-                + HConstants.CP_HTD_ATTR_VALUE_PATTERN + ": " + specStr);
-      }
-      checkHasCoprocessor(className);
-      return addCoprocessorToMap(specStr);
+    @Deprecated
+    public ModifyableTableDescriptor setCoprocessorWithSpec(final String 
specStr)
+      throws IOException {
+      CoprocessorDescriptor cpDesc = 
toCoprocessorDescriptor(specStr).orElseThrow(
+        () -> new IllegalArgumentException(
+          "Format does not match " + CP_HTD_ATTR_VALUE_PATTERN + ": " + 
specStr));
+      checkHasCoprocessor(cpDesc.getClassName());
+      return setCoprocessorToMap(specStr);
     }
 
     private void checkHasCoprocessor(final String className) throws 
IOException {
@@ -1233,12 +1258,10 @@ public class TableDescriptorBuilder {
 
     /**
      * Add coprocessor to values Map
-     *
      * @param specStr The Coprocessor specification all in in one String
-     * formatted so matches {@link HConstants#CP_HTD_ATTR_VALUE_PATTERN}
      * @return Returns <code>this</code>
      */
-    private ModifyableTableDescriptor addCoprocessorToMap(final String 
specStr) {
+    private ModifyableTableDescriptor setCoprocessorToMap(final String 
specStr) {
       if (specStr == null) {
         return this;
       }
@@ -1246,7 +1269,7 @@ public class TableDescriptorBuilder {
       int maxCoprocessorNumber = 0;
       Matcher keyMatcher;
       for (Map.Entry<Bytes, Bytes> e : this.values.entrySet()) {
-        keyMatcher = 
HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(Bytes.toString(e.getKey().get()));
+        keyMatcher = 
CP_HTD_ATTR_KEY_PATTERN.matcher(Bytes.toString(e.getKey().get()));
         if (!keyMatcher.matches()) {
           continue;
         }
@@ -1266,24 +1289,8 @@ public class TableDescriptorBuilder {
      */
     @Override
     public boolean hasCoprocessor(String classNameToMatch) {
-      Matcher keyMatcher;
-      for (Map.Entry<Bytes, Bytes> e
-              : this.values.entrySet()) {
-        keyMatcher
-                = HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(
-                        Bytes.toString(e.getKey().get()));
-        if (!keyMatcher.matches()) {
-          continue;
-        }
-        String className = 
getCoprocessorClassNameFromSpecStr(Bytes.toString(e.getValue().get()));
-        if (className == null) {
-          continue;
-        }
-        if (className.equals(classNameToMatch.trim())) {
-          return true;
-        }
-      }
-      return false;
+      return getCoprocessorDescriptors().stream().anyMatch(cp -> 
cp.getClassName()
+        .equals(classNameToMatch));
     }
 
     /**
@@ -1293,36 +1300,19 @@ public class TableDescriptorBuilder {
      * @return The list of co-processors classNames
      */
     @Override
-    public List<String> getCoprocessors() {
-      List<String> result = new ArrayList<>(this.values.entrySet().size());
-      Matcher keyMatcher;
-      for (Map.Entry<Bytes, Bytes> e : this.values.entrySet()) {
-        keyMatcher = 
HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(Bytes.toString(e.getKey().get()));
-        if (!keyMatcher.matches()) {
-          continue;
-        }
-        String className = 
getCoprocessorClassNameFromSpecStr(Bytes.toString(e.getValue().get()));
-        if (className == null) {
-          continue;
+    public List<CoprocessorDescriptor> getCoprocessorDescriptors() {
+      List<CoprocessorDescriptor> result = new ArrayList<>();
+      for (Map.Entry<Bytes, Bytes> e: getValues().entrySet()) {
+        String key = Bytes.toString(e.getKey().get()).trim();
+        if (CP_HTD_ATTR_KEY_PATTERN.matcher(key).matches()) {
+          toCoprocessorDescriptor(Bytes.toString(e.getValue().get()).trim())
+            .ifPresent(result::add);
         }
-        result.add(className); // classname is the 2nd field
       }
       return result;
     }
 
     /**
-     * @param spec String formatted as per
-     * {@link HConstants#CP_HTD_ATTR_VALUE_PATTERN}
-     * @return Class parsed from passed in <code>spec</code> or null if no 
match
-     * or classpath found
-     */
-    private static String getCoprocessorClassNameFromSpecStr(final String 
spec) {
-      Matcher matcher = HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(spec);
-      // Classname is the 2nd field
-      return matcher != null && matcher.matches() ? matcher.group(2).trim() : 
null;
-    }
-
-    /**
      * Remove a coprocessor from those set on the table
      *
      * @param className Class name of the co-processor
@@ -1333,12 +1323,12 @@ public class TableDescriptorBuilder {
       Matcher valueMatcher;
       for (Map.Entry<Bytes, Bytes> e : this.values
               .entrySet()) {
-        keyMatcher = 
HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(Bytes.toString(e
+        keyMatcher = CP_HTD_ATTR_KEY_PATTERN.matcher(Bytes.toString(e
                 .getKey().get()));
         if (!keyMatcher.matches()) {
           continue;
         }
-        valueMatcher = HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(Bytes
+        valueMatcher = CP_HTD_ATTR_VALUE_PATTERN.matcher(Bytes
                 .toString(e.getValue().get()));
         if (!valueMatcher.matches()) {
           continue;
@@ -1413,4 +1403,40 @@ public class TableDescriptorBuilder {
     }
   }
 
+  private static Optional<CoprocessorDescriptor> 
toCoprocessorDescriptor(String spec) {
+    Matcher matcher = CP_HTD_ATTR_VALUE_PATTERN.matcher(spec);
+    if (matcher.matches()) {
+      // jar file path can be empty if the cp class can be loaded
+      // from class loader.
+      String path = matcher.group(1).trim().isEmpty() ?
+        null : matcher.group(1).trim();
+      String className = matcher.group(2).trim();
+      if (className.isEmpty()) {
+        return Optional.empty();
+      }
+      String priorityStr = matcher.group(3).trim();
+      int priority = priorityStr.isEmpty() ?
+        Coprocessor.PRIORITY_USER : Integer.parseInt(priorityStr);
+      String cfgSpec = null;
+      try {
+        cfgSpec = matcher.group(4);
+      } catch (IndexOutOfBoundsException ex) {
+        // ignore
+      }
+      Map<String, String> ourConf = new TreeMap<>();
+      if (cfgSpec != null && !cfgSpec.trim().equals("|")) {
+        cfgSpec = cfgSpec.substring(cfgSpec.indexOf('|') + 1);
+        Matcher m = CP_HTD_ATTR_VALUE_PARAM_PATTERN.matcher(cfgSpec);
+        while (m.find()) {
+          ourConf.put(m.group(1), m.group(2));
+        }
+      }
+      return Optional.of(CoprocessorDescriptorBuilder.newBuilder(className)
+        .setJarPath(path)
+        .setPriority(priority)
+        .setProperties(ourConf)
+        .build());
+    }
+    return Optional.empty();
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
----------------------------------------------------------------------
diff --git 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
index 520a4cd..564adef 100644
--- 
a/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
+++ 
b/hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java
@@ -2847,7 +2847,7 @@ public final class ProtobufUtil {
     ts.getColumnFamiliesList()
       .stream()
       .map(ProtobufUtil::toColumnFamilyDescriptor)
-      .forEach(builder::addColumnFamily);
+      .forEach(builder::setColumnFamily);
     ts.getAttributesList()
       .forEach(a -> builder.setValue(a.getFirst().toByteArray(), 
a.getSecond().toByteArray()));
     ts.getConfigurationList()

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestCoprocessorDescriptor.java
----------------------------------------------------------------------
diff --git 
a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestCoprocessorDescriptor.java
 
b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestCoprocessorDescriptor.java
new file mode 100644
index 0000000..b288f98
--- /dev/null
+++ 
b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestCoprocessorDescriptor.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.testclassification.MiscTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Category({ MiscTests.class, SmallTests.class })
+public class TestCoprocessorDescriptor {
+
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestCoprocessorDescriptor.class);
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(TestCoprocessorDescriptor.class);
+
+  @Rule
+  public TestName name = new TestName();
+
+  @Test
+  public void testBuild() {
+    String className = "className";
+    String path = "path";
+    int priority = 100;
+    String propertyKey = "propertyKey";
+    String propertyValue = "propertyValue";
+    CoprocessorDescriptor cp =
+      
CoprocessorDescriptorBuilder.newBuilder(className).setJarPath(path).setPriority(priority)
+        .setProperty(propertyKey, propertyValue).build();
+    assertEquals(className, cp.getClassName());
+    assertEquals(path, cp.getJarPath().get());
+    assertEquals(priority, cp.getPriority());
+    assertEquals(1, cp.getProperties().size());
+    assertEquals(propertyValue, cp.getProperties().get(propertyKey));
+  }
+
+  @Test
+  public void testSetCoprocessor() throws IOException {
+    String propertyKey = "propertyKey";
+    List<CoprocessorDescriptor> cps = new ArrayList<>();
+    for (String className : Arrays.asList("className0", "className1", 
"className2")) {
+      String path = "path";
+      int priority = Math.abs(className.hashCode());
+      String propertyValue = "propertyValue";
+      cps.add(
+        
CoprocessorDescriptorBuilder.newBuilder(className).setJarPath(path).setPriority(priority)
+          .setProperty(propertyKey, propertyValue).build());
+    }
+    TableDescriptor tableDescriptor =
+      
TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName()))
+        .setCoprocessors(cps).build();
+    for (CoprocessorDescriptor cp : cps) {
+      boolean match = false;
+      for (CoprocessorDescriptor that : 
tableDescriptor.getCoprocessorDescriptors()) {
+        if (cp.getClassName().equals(that.getClassName())) {
+          assertEquals(cp.getJarPath().get(), that.getJarPath().get());
+          assertEquals(cp.getPriority(), that.getPriority());
+          assertEquals(cp.getProperties().size(), that.getProperties().size());
+          assertEquals(cp.getProperties().get(propertyKey), 
that.getProperties().get(propertyKey));
+          match = true;
+          break;
+        }
+      }
+      if (!match) {
+        fail("expect:" + cp + ", actual:" + 
tableDescriptor.getCoprocessorDescriptors());
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestTableDescriptorBuilder.java
----------------------------------------------------------------------
diff --git 
a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestTableDescriptorBuilder.java
 
b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestTableDescriptorBuilder.java
index f83e13f..959ae91 100644
--- 
a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestTableDescriptorBuilder.java
+++ 
b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestTableDescriptorBuilder.java
@@ -60,50 +60,12 @@ public class TestTableDescriptorBuilder {
     String cpName = "a.b.c.d";
     TableDescriptor htd
       = TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME)
-            .addCoprocessor(cpName)
-            .addCoprocessor(cpName)
+            .setCoprocessor(cpName)
+            .setCoprocessor(cpName)
             .build();
   }
 
   @Test
-  public void testAddCoprocessorWithSpecStr() throws IOException {
-    String cpName = "a.b.c.d";
-    TableDescriptorBuilder builder
-      = TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME);
-
-    try {
-      builder.addCoprocessorWithSpec(cpName);
-      fail();
-    } catch (IllegalArgumentException iae) {
-      // Expected as cpName is invalid
-    }
-
-    // Try minimal spec.
-    try {
-      builder.addCoprocessorWithSpec("file:///some/path" + "|" + cpName);
-      fail();
-    } catch (IllegalArgumentException iae) {
-      // Expected to be invalid
-    }
-
-    // Try more spec.
-    String spec = 
"hdfs:///foo.jar|com.foo.FooRegionObserver|1001|arg1=1,arg2=2";
-    try {
-      builder.addCoprocessorWithSpec(spec);
-    } catch (IllegalArgumentException iae) {
-      fail();
-    }
-
-    // Try double add of same coprocessor
-    try {
-      builder.addCoprocessorWithSpec(spec);
-      fail();
-    } catch (IOException ioe) {
-      // Expect that the coprocessor already exists
-    }
-  }
-
-  @Test
   public void testPb() throws DeserializationException, IOException {
     final int v = 123;
     TableDescriptor htd
@@ -133,7 +95,7 @@ public class TestTableDescriptorBuilder {
     String className = 
"org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver";
     TableDescriptor desc
       = 
TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName()))
-         .addCoprocessor(className) // add and check that it is present
+         .setCoprocessor(className) // add and check that it is present
         .build();
     assertTrue(desc.hasCoprocessor(className));
     desc = TableDescriptorBuilder.newBuilder(desc)
@@ -151,40 +113,46 @@ public class TestTableDescriptorBuilder {
     TableDescriptor desc
       = 
TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())).build();
     // Check that any coprocessor is present.
-    assertTrue(desc.getCoprocessors().isEmpty());
+    assertTrue(desc.getCoprocessorDescriptors().isEmpty());
 
     // simple CP
     String className1 = 
"org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver";
     String className2 = 
"org.apache.hadoop.hbase.coprocessor.SampleRegionWALObserver";
     desc = TableDescriptorBuilder.newBuilder(desc)
-            .addCoprocessor(className1) // Add the 1 coprocessor and check if 
present.
+            .setCoprocessor(className1) // Add the 1 coprocessor and check if 
present.
             .build();
-    assertTrue(desc.getCoprocessors().size() == 1);
-    assertTrue(desc.getCoprocessors().contains(className1));
+    assertTrue(desc.getCoprocessorDescriptors().size() == 1);
+    
assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName)
+      .anyMatch(name -> name.equals(className1)));
 
     desc = TableDescriptorBuilder.newBuilder(desc)
             // Add the 2nd coprocessor and check if present.
             // remove it and check that it is gone
-            .addCoprocessor(className2)
+            .setCoprocessor(className2)
             .build();
-    assertTrue(desc.getCoprocessors().size() == 2);
-    assertTrue(desc.getCoprocessors().contains(className2));
+    assertTrue(desc.getCoprocessorDescriptors().size() == 2);
+    
assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName)
+      .anyMatch(name -> name.equals(className2)));
 
     desc = TableDescriptorBuilder.newBuilder(desc)
             // Remove one and check
             .removeCoprocessor(className1)
             .build();
-    assertTrue(desc.getCoprocessors().size() == 1);
-    assertFalse(desc.getCoprocessors().contains(className1));
-    assertTrue(desc.getCoprocessors().contains(className2));
+    assertTrue(desc.getCoprocessorDescriptors().size() == 1);
+    
assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName)
+      .anyMatch(name -> name.equals(className1)));
+    
assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName)
+      .anyMatch(name -> name.equals(className2)));
 
     desc = TableDescriptorBuilder.newBuilder(desc)
             // Remove the last and check
             .removeCoprocessor(className2)
             .build();
-    assertTrue(desc.getCoprocessors().isEmpty());
-    assertFalse(desc.getCoprocessors().contains(className1));
-    assertFalse(desc.getCoprocessors().contains(className2));
+    assertTrue(desc.getCoprocessorDescriptors().isEmpty());
+    
assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName)
+      .anyMatch(name -> name.equals(className1)));
+    
assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName)
+      .anyMatch(name -> name.equals(className2)));
   }
 
   /**
@@ -292,7 +260,7 @@ public class TestTableDescriptorBuilder {
             .build();
     TableDescriptor htd
       = 
TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName()))
-              .addColumnFamily(hcd)
+              .setColumnFamily(hcd)
               .build();
 
     assertEquals(1000, htd.getColumnFamily(familyName).getBlocksize());
@@ -325,14 +293,14 @@ public class TestTableDescriptorBuilder {
             .setBlocksize(1000)
             .build();
     TableDescriptor htd = 
TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(hcd)
+            .setColumnFamily(hcd)
             .build();
     assertEquals(1000, htd.getColumnFamily(familyName).getBlocksize());
     hcd = ColumnFamilyDescriptorBuilder.newBuilder(familyName)
             .setBlocksize(2000)
             .build();
     // add duplicate column
-    TableDescriptorBuilder.newBuilder(htd).addColumnFamily(hcd).build();
+    TableDescriptorBuilder.newBuilder(htd).setColumnFamily(hcd).build();
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java 
b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
index d826ca0..372d9b1 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
@@ -953,6 +953,10 @@ public final class HConstants {
     */
   public static final float HBASE_CLUSTER_MINIMUM_MEMORY_THRESHOLD = 0.2f;
 
+  /**
+   * @deprecated  It is used internally. As of release 2.0.0, this will be 
removed in HBase 3.0.0.
+   */
+  @Deprecated
   public static final Pattern CP_HTD_ATTR_KEY_PATTERN =
       Pattern.compile("^coprocessor\\$([0-9]+)$", Pattern.CASE_INSENSITIVE);
 
@@ -963,12 +967,25 @@ public final class HConstants {
    * where arguments are {@code <KEY> '=' <VALUE> [,...]}
    * For example: {@code 
hdfs:///foo.jar|com.foo.FooRegionObserver|1001|arg1=1,arg2=2}
    * </pre>
+   * @deprecated  It is used internally. As of release 2.0.0, this will be 
removed in HBase 3.0.0.
    */
+  @Deprecated
   public static final Pattern CP_HTD_ATTR_VALUE_PATTERN =
       
Pattern.compile("(^[^\\|]*)\\|([^\\|]+)\\|[\\s]*([\\d]*)[\\s]*(\\|.*)?$");
-
+  /**
+   * @deprecated  It is used internally. As of release 2.0.0, this will be 
removed in HBase 3.0.0.
+   */
+  @Deprecated
   public static final String CP_HTD_ATTR_VALUE_PARAM_KEY_PATTERN = "[^=,]+";
+  /**
+   * @deprecated  It is used internally. As of release 2.0.0, this will be 
removed in HBase 3.0.0.
+   */
+  @Deprecated
   public static final String CP_HTD_ATTR_VALUE_PARAM_VALUE_PATTERN = "[^,]+";
+  /**
+   * @deprecated  It is used internally. As of release 2.0.0, this will be 
removed in HBase 3.0.0.
+   */
+  @Deprecated
   public static final Pattern CP_HTD_ATTR_VALUE_PARAM_PATTERN = 
Pattern.compile(
       "(" + CP_HTD_ATTR_VALUE_PARAM_KEY_PATTERN + ")=(" +
       CP_HTD_ATTR_VALUE_PARAM_VALUE_PATTERN + "),?");

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestClassLoading.java
----------------------------------------------------------------------
diff --git 
a/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestClassLoading.java
 
b/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestClassLoading.java
index bc75881..1bf36f5 100644
--- 
a/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestClassLoading.java
+++ 
b/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestClassLoading.java
@@ -334,7 +334,7 @@ public class TestClassLoading {
     htd.setValue(cpKey2, cpValue2);
     htd.setValue(cpKey3, cpValue3);
 
-    // add 2 coprocessor by using new htd.addCoprocessor() api
+    // add 2 coprocessor by using new htd.setCoprocessor() api
     htd.addCoprocessor(cpName5, new Path(getLocalPath(jarFile5)),
         Coprocessor.PRIORITY_USER, null);
     Map<String, String> kvs = new HashMap<>();

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestSecureExport.java
----------------------------------------------------------------------
diff --git 
a/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestSecureExport.java
 
b/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestSecureExport.java
index 852f1ab..38c3081 100644
--- 
a/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestSecureExport.java
+++ 
b/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestSecureExport.java
@@ -260,7 +260,7 @@ public class TestSecureExport {
     final String exportTable = name.getMethodName();
     TableDescriptor exportHtd = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILYA))
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILYA))
             .setOwnerString(USER_OWNER)
             .build();
     SecureTestUtil.createTable(UTIL, exportHtd, new 
byte[][]{Bytes.toBytes("s")});
@@ -344,7 +344,7 @@ public class TestSecureExport {
     final String exportTable = name.getMethodName() + "_export";
     final String importTable = name.getMethodName() + "_import";
     final TableDescriptor exportHtd = 
TableDescriptorBuilder.newBuilder(TableName.valueOf(exportTable))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILYA))
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILYA))
             .setOwnerString(USER_OWNER)
             .build();
     SecureTestUtil.createTable(UTIL, exportHtd, new 
byte[][]{Bytes.toBytes("s")});
@@ -401,7 +401,7 @@ public class TestSecureExport {
       };
       SecureTestUtil.verifyAllowed(exportAction, getUserByLogin(USER_OWNER));
       final TableDescriptor importHtd = 
TableDescriptorBuilder.newBuilder(TableName.valueOf(importTable))
-              .addColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILYB))
+              .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILYB))
               .setOwnerString(USER_OWNER)
               .build();
       SecureTestUtil.createTable(UTIL, importHtd, new 
byte[][]{Bytes.toBytes("s")});

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-examples/src/main/java/org/apache/hadoop/hbase/client/example/ExportEndpointExample.java
----------------------------------------------------------------------
diff --git 
a/hbase-examples/src/main/java/org/apache/hadoop/hbase/client/example/ExportEndpointExample.java
 
b/hbase-examples/src/main/java/org/apache/hadoop/hbase/client/example/ExportEndpointExample.java
index cc06844..e15c993 100644
--- 
a/hbase-examples/src/main/java/org/apache/hadoop/hbase/client/example/ExportEndpointExample.java
+++ 
b/hbase-examples/src/main/java/org/apache/hadoop/hbase/client/example/ExportEndpointExample.java
@@ -56,8 +56,8 @@ public class ExportEndpointExample {
          Admin admin = con.getAdmin()) {
       TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
               // MUST mount the export endpoint
-              .addCoprocessor(Export.class.getName())
-              .addColumnFamily(ColumnFamilyDescriptorBuilder.of(family))
+              .setCoprocessor(Export.class.getName())
+              .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family))
               .build();
       admin.createTable(desc);
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestScanModifyingObserver.java
----------------------------------------------------------------------
diff --git 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestScanModifyingObserver.java
 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestScanModifyingObserver.java
index f90a0f4..76d9cb9 100644
--- 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestScanModifyingObserver.java
+++ 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestScanModifyingObserver.java
@@ -68,10 +68,10 @@ public class TestScanModifyingObserver {
     UTIL.startMiniCluster(1);
     UTIL.getAdmin()
         .createTable(TableDescriptorBuilder.newBuilder(NAME)
-            .addCoprocessor(ScanModifyingObserver.class.getName())
+            .setCoprocessor(ScanModifyingObserver.class.getName())
             .setValue(ScanModifyingObserver.FAMILY_TO_ADD_KEY, 
Bytes.toString(FAMILY))
             .setValue(ScanModifyingObserver.QUALIFIER_TO_ADD_KEY, 
Bytes.toString(IMPLICIT_QUAL))
-            .addColumnFamily(CFD).build());
+            .setColumnFamily(CFD).build());
   }
 
   @AfterClass

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestValueReplacingCompaction.java
----------------------------------------------------------------------
diff --git 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestValueReplacingCompaction.java
 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestValueReplacingCompaction.java
index 0dbdfe1..6974c20 100644
--- 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestValueReplacingCompaction.java
+++ 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestValueReplacingCompaction.java
@@ -67,10 +67,10 @@ public class TestValueReplacingCompaction {
     UTIL.startMiniCluster(1);
     UTIL.getAdmin()
         .createTable(TableDescriptorBuilder.newBuilder(NAME)
-            .addCoprocessor(ValueRewritingObserver.class.getName())
+            .setCoprocessor(ValueRewritingObserver.class.getName())
             .setValue(ValueRewritingObserver.ORIGINAL_VALUE_KEY, value)
             .setValue(ValueRewritingObserver.REPLACED_VALUE_KEY, replacedValue)
-            .addColumnFamily(CFD).build());
+            .setColumnFamily(CFD).build());
   }
 
   @AfterClass

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserver.java
----------------------------------------------------------------------
diff --git 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserver.java
 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserver.java
index 639461b..b76861d 100644
--- 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserver.java
+++ 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserver.java
@@ -47,8 +47,8 @@ public class TestWriteHeavyIncrementObserver extends 
WriteHeavyIncrementObserver
     WriteHeavyIncrementObserverTestBase.setUp();
     UTIL.getAdmin()
         .createTable(TableDescriptorBuilder.newBuilder(NAME)
-            .addCoprocessor(WriteHeavyIncrementObserver.class.getName())
-            
.addColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY)).build());
+            .setCoprocessor(WriteHeavyIncrementObserver.class.getName())
+            
.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY)).build());
     TABLE = UTIL.getConnection().getTable(NAME);
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserverWithMemStoreCompaction.java
----------------------------------------------------------------------
diff --git 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserverWithMemStoreCompaction.java
 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserverWithMemStoreCompaction.java
index ae93d88..60b032b 100644
--- 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserverWithMemStoreCompaction.java
+++ 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestWriteHeavyIncrementObserverWithMemStoreCompaction.java
@@ -45,10 +45,10 @@ public class 
TestWriteHeavyIncrementObserverWithMemStoreCompaction
     WriteHeavyIncrementObserverTestBase.setUp();
     UTIL.getAdmin()
         .createTable(TableDescriptorBuilder.newBuilder(NAME)
-            .addCoprocessor(WriteHeavyIncrementObserver.class.getName())
+            .setCoprocessor(WriteHeavyIncrementObserver.class.getName())
             .setValue(CompactingMemStore.COMPACTING_MEMSTORE_TYPE_KEY,
               MemoryCompactionPolicy.EAGER.name())
-            
.addColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY)).build());
+            
.setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY)).build());
     TABLE = UTIL.getConnection().getTable(NAME);
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestZooKeeperScanPolicyObserver.java
----------------------------------------------------------------------
diff --git 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestZooKeeperScanPolicyObserver.java
 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestZooKeeperScanPolicyObserver.java
index 3c89fa5..23c97dc 100644
--- 
a/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestZooKeeperScanPolicyObserver.java
+++ 
b/hbase-examples/src/test/java/org/apache/hadoop/hbase/coprocessor/example/TestZooKeeperScanPolicyObserver.java
@@ -64,11 +64,11 @@ public class TestZooKeeperScanPolicyObserver {
     UTIL.startMiniCluster(3);
     UTIL.getAdmin()
         .createTable(TableDescriptorBuilder.newBuilder(NAME)
-            .addCoprocessor(ZooKeeperScanPolicyObserver.class.getName())
+            .setCoprocessor(ZooKeeperScanPolicyObserver.class.getName())
             .setValue(ZooKeeperScanPolicyObserver.ZK_ENSEMBLE_KEY,
               "localhost:" + UTIL.getZkCluster().getClientPort())
             .setValue(ZooKeeperScanPolicyObserver.ZK_SESSION_TIMEOUT_KEY, 
"2000")
-            
.addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILY).build()).build());
+            
.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILY).build()).build());
     TABLE = UTIL.getConnection().getTable(NAME);
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-it/src/test/java/org/apache/hadoop/hbase/IntegrationTestDDLMasterFailover.java
----------------------------------------------------------------------
diff --git 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/IntegrationTestDDLMasterFailover.java
 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/IntegrationTestDDLMasterFailover.java
index 4d0d7e0..2fb12c3 100644
--- 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/IntegrationTestDDLMasterFailover.java
+++ 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/IntegrationTestDDLMasterFailover.java
@@ -440,7 +440,7 @@ public class IntegrationTestDDLMasterFailover extends 
IntegrationTestBase {
       String tableName = String.format("ittable-%010d", RandomUtils.nextInt());
       String familyName = "cf-" + Math.abs(RandomUtils.nextInt());
       return TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName))
-          .addColumnFamily(ColumnFamilyDescriptorBuilder.of(familyName))
+          .setColumnFamily(ColumnFamilyDescriptorBuilder.of(familyName))
           .build();
     }
   }

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/AddColumnAction.java
----------------------------------------------------------------------
diff --git 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/AddColumnAction.java
 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/AddColumnAction.java
index 6c8554a..3473684 100644
--- 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/AddColumnAction.java
+++ 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/AddColumnAction.java
@@ -63,7 +63,7 @@ public class AddColumnAction extends Action {
     LOG.debug("Performing action: Adding " + columnDescriptor + " to " + 
tableName);
 
     TableDescriptor modifiedTable = 
TableDescriptorBuilder.newBuilder(tableDescriptor)
-        .addColumnFamily(columnDescriptor).build();
+        .setColumnFamily(columnDescriptor).build();
     admin.modifyTable(modifiedTable);
   }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/TestChangeSplitPolicyAction.java
----------------------------------------------------------------------
diff --git 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/TestChangeSplitPolicyAction.java
 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/TestChangeSplitPolicyAction.java
index 0bdc07c..66cdff4 100644
--- 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/TestChangeSplitPolicyAction.java
+++ 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/chaos/actions/TestChangeSplitPolicyAction.java
@@ -56,7 +56,7 @@ public class TestChangeSplitPolicyAction extends Action {
   public void setUp() throws Exception {
     this.admin = TEST_UTIL.getAdmin();
     TableDescriptorBuilder builder = 
TableDescriptorBuilder.newBuilder(tableName);
-    
admin.createTable(builder.addColumnFamily(ColumnFamilyDescriptorBuilder.of("fam")).build());
+    
admin.createTable(builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of("fam")).build());
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-it/src/test/java/org/apache/hadoop/hbase/mapreduce/IntegrationTestBulkLoad.java
----------------------------------------------------------------------
diff --git 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/mapreduce/IntegrationTestBulkLoad.java
 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/mapreduce/IntegrationTestBulkLoad.java
index ee410ca..2fa2229 100644
--- 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/mapreduce/IntegrationTestBulkLoad.java
+++ 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/mapreduce/IntegrationTestBulkLoad.java
@@ -212,7 +212,7 @@ public class IntegrationTestBulkLoad extends 
IntegrationTestBase {
     Admin admin = util.getAdmin();
     TableDescriptor desc = admin.getDescriptor(t);
     TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(desc);
-    builder.addCoprocessor(SlowMeCoproScanOperations.class.getName());
+    builder.setCoprocessor(SlowMeCoproScanOperations.class.getName());
     HBaseTestingUtility.modifyTableSync(admin, builder.build());
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-it/src/test/java/org/apache/hadoop/hbase/mttr/IntegrationTestMTTR.java
----------------------------------------------------------------------
diff --git 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/mttr/IntegrationTestMTTR.java 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/mttr/IntegrationTestMTTR.java
index 850e123..4c2e379 100644
--- 
a/hbase-it/src/test/java/org/apache/hadoop/hbase/mttr/IntegrationTestMTTR.java
+++ 
b/hbase-it/src/test/java/org/apache/hadoop/hbase/mttr/IntegrationTestMTTR.java
@@ -241,7 +241,7 @@ public class IntegrationTestMTTR {
     ColumnFamilyDescriptorBuilder colDescriptorBldr =
         ColumnFamilyDescriptorBuilder.newBuilder(FAMILY);
     colDescriptorBldr.setMaxVersions(1);
-    builder.addColumnFamily(colDescriptorBldr.build());
+    builder.setColumnFamily(colDescriptorBldr.build());
     util.getAdmin().createTable(builder.build());
 
     // Setup the table for LoadTestTool

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestCellBasedImportExport2.java
----------------------------------------------------------------------
diff --git 
a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestCellBasedImportExport2.java
 
b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestCellBasedImportExport2.java
index d52863e..4a22699 100644
--- 
a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestCellBasedImportExport2.java
+++ 
b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestCellBasedImportExport2.java
@@ -297,7 +297,7 @@ public class TestCellBasedImportExport2 {
    public void testExportScannerBatching() throws Throwable {
     TableDescriptor desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(1)
               .build())
             .build();
@@ -328,7 +328,7 @@ public class TestCellBasedImportExport2 {
   public void testWithDeletes() throws Throwable {
     TableDescriptor desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .setKeepDeletedCells(KeepDeletedCells.TRUE)
               .build())
@@ -362,7 +362,7 @@ public class TestCellBasedImportExport2 {
     final String IMPORT_TABLE = name.getMethodName() + "import";
     desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(IMPORT_TABLE))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .setKeepDeletedCells(KeepDeletedCells.TRUE)
               .build())
@@ -397,7 +397,7 @@ public class TestCellBasedImportExport2 {
     final TableName exportTable = TableName.valueOf(name.getMethodName());
     TableDescriptor desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .setKeepDeletedCells(KeepDeletedCells.TRUE)
               .build())
@@ -435,7 +435,7 @@ public class TestCellBasedImportExport2 {
     final String importTable = name.getMethodName() + "import";
     desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(importTable))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .setKeepDeletedCells(KeepDeletedCells.TRUE)
               .build())
@@ -477,7 +477,7 @@ public class TestCellBasedImportExport2 {
     // Create simple table to export
     TableDescriptor desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .build())
             .build();
@@ -505,7 +505,7 @@ public class TestCellBasedImportExport2 {
     final String IMPORT_TABLE = name.getMethodName() + "import";
     desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(IMPORT_TABLE))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .build())
             .build();

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestImportExport.java
----------------------------------------------------------------------
diff --git 
a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestImportExport.java
 
b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestImportExport.java
index 0dbf738..c7916de 100644
--- 
a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestImportExport.java
+++ 
b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/mapreduce/TestImportExport.java
@@ -297,7 +297,7 @@ public class TestImportExport {
    public void testExportScannerBatching() throws Throwable {
     TableDescriptor desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(1)
               .build())
             .build();
@@ -328,7 +328,7 @@ public class TestImportExport {
   public void testWithDeletes() throws Throwable {
     TableDescriptor desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .setKeepDeletedCells(KeepDeletedCells.TRUE)
               .build())
@@ -362,7 +362,7 @@ public class TestImportExport {
     final String IMPORT_TABLE = name.getMethodName() + "import";
     desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(IMPORT_TABLE))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .setKeepDeletedCells(KeepDeletedCells.TRUE)
               .build())
@@ -397,7 +397,7 @@ public class TestImportExport {
     final TableName exportTable = TableName.valueOf(name.getMethodName());
     TableDescriptor desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .setKeepDeletedCells(KeepDeletedCells.TRUE)
               .build())
@@ -435,7 +435,7 @@ public class TestImportExport {
     final String importTable = name.getMethodName() + "import";
     desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(importTable))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .setKeepDeletedCells(KeepDeletedCells.TRUE)
               .build())
@@ -477,7 +477,7 @@ public class TestImportExport {
     // Create simple table to export
     TableDescriptor desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(name.getMethodName()))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .build())
             .build();
@@ -505,7 +505,7 @@ public class TestImportExport {
     final String IMPORT_TABLE = name.getMethodName() + "import";
     desc = TableDescriptorBuilder
             .newBuilder(TableName.valueOf(IMPORT_TABLE))
-            .addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
+            .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILYA)
               .setMaxVersions(5)
               .build())
             .build();

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/replication/TestVerifyReplication.java
----------------------------------------------------------------------
diff --git 
a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/replication/TestVerifyReplication.java
 
b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/replication/TestVerifyReplication.java
index 1f080c8..e1fda4e 100644
--- 
a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/replication/TestVerifyReplication.java
+++ 
b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/replication/TestVerifyReplication.java
@@ -150,7 +150,7 @@ public class TestVerifyReplication extends 
TestReplicationBase {
       ColumnFamilyDescriptor fam = 
ColumnFamilyDescriptorBuilder.newBuilder(familyname)
           
.setMaxVersions(100).setScope(HConstants.REPLICATION_SCOPE_GLOBAL).build();
       TableDescriptor table =
-          
TableDescriptorBuilder.newBuilder(tableName).addColumnFamily(fam).build();
+          
TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(fam).build();
       scopes = new TreeMap<>(Bytes.BYTES_COMPARATOR);
       for (ColumnFamilyDescriptor f : table.getColumnFamilies()) {
         scopes.put(f.getName(), f.getScope());

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java
----------------------------------------------------------------------
diff --git 
a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java
 
b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java
index 30547ba..afdff71 100644
--- 
a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java
+++ 
b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java
@@ -140,7 +140,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil{
     TableDescriptorBuilder tableBuilder = 
TableDescriptorBuilder.newBuilder(TEST_TABLE);
     ColumnFamilyDescriptorBuilder cfd = 
ColumnFamilyDescriptorBuilder.newBuilder(TEST_FAMILY);
     cfd.setMaxVersions(100);
-    tableBuilder.addColumnFamily(cfd.build());
+    tableBuilder.setColumnFamily(cfd.build());
     tableBuilder.setValue(TableDescriptorBuilder.OWNER, 
USER_OWNER.getShortName());
     createTable(TEST_UTIL, tableBuilder.build(),
         new byte[][] { Bytes.toBytes("s") });

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/package-info.java
----------------------------------------------------------------------
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/package-info.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/package-info.java
index a6b5c4b..92eb121 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/package-info.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/package-info.java
@@ -256,7 +256,7 @@ policy implementations, perhaps) ahead of observers.
   // create a table that references the jar
   TableDescriptor htd = TableDescriptorBuilder
                         
.newBuilder(TableName.valueOf(getClass().getTableName()))
-                        
.addColumnFamily(ColumnFamilyDescriptorBuilder.of("test"))
+                        
.setColumnFamily(ColumnFamilyDescriptorBuilder.of("test"))
                         .setValue(Bytes.toBytes("Coprocessor$1", 
path.toString()+
                           ":" + classFullName +
                           ":" + Coprocessor.Priority.USER))

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
----------------------------------------------------------------------
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
index 1812d8c..0ce6681 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
@@ -2150,7 +2150,7 @@ public class HMaster extends HRegionServer implements 
MasterServices {
     }
 
     TableDescriptor newDesc = TableDescriptorBuilder
-        .newBuilder(old).addColumnFamily(column).build();
+        .newBuilder(old).setColumnFamily(column).build();
     return modifyTable(tableName, newDesc, nonceGroup, nonce);
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java
----------------------------------------------------------------------
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java
index b35f4fb..171be5f 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java
@@ -29,8 +29,7 @@ import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import java.util.regex.Matcher;
-
+import java.util.stream.Collectors;
 import org.apache.commons.collections4.map.AbstractReferenceMap;
 import org.apache.commons.collections4.map.ReferenceMap;
 import org.apache.hadoop.conf.Configuration;
@@ -38,9 +37,7 @@ import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CompareOperator;
-import org.apache.hadoop.hbase.Coprocessor;
 import org.apache.hadoop.hbase.HBaseConfiguration;
-import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.RawCellBuilder;
 import org.apache.hadoop.hbase.RawCellBuilderFactory;
 import org.apache.hadoop.hbase.ServerName;
@@ -82,8 +79,6 @@ import 
org.apache.hadoop.hbase.regionserver.compactions.CompactionLifeCycleTrack
 import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest;
 import org.apache.hadoop.hbase.regionserver.querymatcher.DeleteTracker;
 import org.apache.hadoop.hbase.security.User;
-import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
-import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.CoprocessorClassLoader;
 import org.apache.hadoop.hbase.util.Pair;
 import org.apache.hadoop.hbase.wal.WALEdit;
@@ -314,59 +309,19 @@ public class RegionCoprocessorHost
 
   static List<TableCoprocessorAttribute> 
getTableCoprocessorAttrsFromSchema(Configuration conf,
       TableDescriptor htd) {
-    List<TableCoprocessorAttribute> result = Lists.newArrayList();
-    for (Map.Entry<Bytes, Bytes> e: htd.getValues().entrySet()) {
-      String key = Bytes.toString(e.getKey().get()).trim();
-      if (HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(key).matches()) {
-        String spec = Bytes.toString(e.getValue().get()).trim();
-        // found one
-        try {
-          Matcher matcher = HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(spec);
-          if (matcher.matches()) {
-            // jar file path can be empty if the cp class can be loaded
-            // from class loader.
-            Path path = matcher.group(1).trim().isEmpty() ?
-                null : new Path(matcher.group(1).trim());
-            String className = matcher.group(2).trim();
-            if (className.isEmpty()) {
-              LOG.error("Malformed table coprocessor specification: key=" +
-                key + ", spec: " + spec);
-              continue;
-            }
-            String priorityStr = matcher.group(3).trim();
-            int priority = priorityStr.isEmpty() ?
-                Coprocessor.PRIORITY_USER : Integer.parseInt(priorityStr);
-            String cfgSpec = null;
-            try {
-              cfgSpec = matcher.group(4);
-            } catch (IndexOutOfBoundsException ex) {
-              // ignore
-            }
-            Configuration ourConf;
-            if (cfgSpec != null && !cfgSpec.trim().equals("|")) {
-              cfgSpec = cfgSpec.substring(cfgSpec.indexOf('|') + 1);
-              // do an explicit deep copy of the passed configuration
-              ourConf = new Configuration(false);
-              HBaseConfiguration.merge(ourConf, conf);
-              Matcher m = 
HConstants.CP_HTD_ATTR_VALUE_PARAM_PATTERN.matcher(cfgSpec);
-              while (m.find()) {
-                ourConf.set(m.group(1), m.group(2));
-              }
-            } else {
-              ourConf = conf;
-            }
-            result.add(new TableCoprocessorAttribute(path, className, 
priority, ourConf));
-          } else {
-            LOG.error("Malformed table coprocessor specification: key=" + key +
-              ", spec: " + spec);
-          }
-        } catch (Exception ioe) {
-          LOG.error("Malformed table coprocessor specification: key=" + key +
-            ", spec: " + spec);
-        }
+    return htd.getCoprocessorDescriptors().stream().map(cp -> {
+      Path path = cp.getJarPath().map(p -> new Path(p)).orElse(null);
+      Configuration ourConf;
+      if (!cp.getProperties().isEmpty()) {
+        // do an explicit deep copy of the passed configuration
+        ourConf = new Configuration(false);
+        HBaseConfiguration.merge(ourConf, conf);
+        cp.getProperties().forEach((k, v) -> ourConf.set(k, v));
+      } else {
+        ourConf = conf;
       }
-    }
-    return result;
+      return new TableCoprocessorAttribute(path, cp.getClassName(), 
cp.getPriority(), ourConf);
+    }).collect(Collectors.toList());
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/hbase/blob/95596e8b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
----------------------------------------------------------------------
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
index cfc0b91..90fdca6 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
@@ -1128,7 +1128,7 @@ public class AccessController implements 
MasterCoprocessor, RegionCoprocessor,
         setScope(HConstants.REPLICATION_SCOPE_LOCAL).build();
     TableDescriptor td =
         TableDescriptorBuilder.newBuilder(AccessControlLists.ACL_TABLE_NAME).
-        addColumnFamily(cfd).build();
+          setColumnFamily(cfd).build();
     admin.createTable(td);
   }
 

Reply via email to