PHOENIX-5268 HBase 2.1/2.2 compatibility

add compatibility module system to handle HBase 2.x API changes
add compatibility module for HBase 2.0.1
add compatibility module for HBase 2.1.6
add compatibility module for HBase 2.2.1

see BUILDING.md for specifying HBase versions
diff --git a/BUILDING.md b/BUILDING.md
new file mode 100644
index 0000000..dd7e944
--- /dev/null
+++ b/BUILDING.md
@@ -0,0 +1,92 @@
+<!--
+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.
+-->
+
+![logo](http://phoenix.apache.org/images/logo.png)
+
+<b>[Apache Phoenix](http://phoenix.apache.org/)</b> is a SQL skin over HBase delivered as a
+client-embedded JDBC driver targeting low latency queries over HBase data. Visit the Apache
+Phoenix website <b>[here](http://phoenix.apache.org/)</b>.
+
+
+Building Apache Phoenix
+========================
+
+Phoenix uses Maven (3.X) to build all its necessary resources.
+
+Building from source
+--------------------
+
+On first setup, you may need to run `$ mvn install -DskipTests`
+to install the local jars. This is a side-effect of multi-module maven projects
+
+To re-generate the antlr based files:  
+`$ mvn process-sources`
+
+To build the jars and the assembly tarball:  
+`$ mvn package`
+and optionally, to just skip all the tests and build the jars:  
+`$ mvn package -DskipTests`
+
+Note: javadocs are generated in target/apidocs
+
+HBase version compatibility
+---------------------------
+
+As Phoenix uses *limited public* HBase APIs, which sometimes change even within a minor release,
+Phoenix may not build or work with older releases of HBase, or ones that were released after
+Phoenix, even within the same HBase minor release.
+
+By default, Phoenix will be built for the latest supported HBase 2.x release. You can specify the
+targeted HBase minor release by setting the `hbase.profile` system property for maven.
+
+You can also specify the exact HBase release to build Phoenix with by additionally
+setting the `hbase.version` system property.
+
+ * `mvn clean install` will build the for the latest known supported HBase 2.x relese
+ * `mvn clean install -Dhbase.profile=2.1` will use the latest known supported HBase 2.1 release
+ * `mvn clean install -Dhbase.profile=2.1 -Dhbase.version=2.1.7` will build with HBase 2.1.7
+
+Phoenix verifies the specified `hbase.profile` and `hbase.version` properties, and will reject
+combinations that are known not to work. You may disable this verification by adding
+`-Denforcer.skip=true` to the maven command line. (In case you are using an HBase package that
+modifies the canonical version number in a way that Phoenix cannot parse)
+
+*Note that the above reflects the intended behaviour for the 5.1 release. In the current
+development releases, we default to building with the old HBase 2.0.1 release.*
+
+Importing into eclipse
+----------------------
+
+Use the m2e eclipse plugin and do Import->Maven Project and just pick the root 'phoenix' directory.
+
+Running the tests
+-----------------
+
+All tests  
+`$ mvn clean test`
+
+Findbugs
+--------
+
+Findbugs report is generated in /target/site  
+`$ mvn site`
+
+Generate Apache Web Site
+------------------------
+
+checkout https://svn.apache.org/repos/asf/phoenix  
+`$ build.sh`
diff --git a/build.txt b/build.txt
deleted file mode 100644
index aac954c..0000000
--- a/build.txt
+++ /dev/null
@@ -1,64 +0,0 @@
-############################################################################
-#
-# 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.
-#
-############################################################################
-
-
-# Building Apache Phoenix
-=========================
-
-Phoenix uses Maven (3.X) to build all its necessary resources. 
-
-## Building from source
-=======================
-
-On first setup, you may need to run
-	$ mvn install -DskipTests
-to install the local jars. This is a side-effect of multi-module maven projects
-
-1. To re-generate the antlr based files:
-	$ mvn process-sources
-
-2. To build the jars
-	$ mvn package
-and optionally, to just skip all the tests and build the jars:
-	$ mvn package -DskipTests
-
-Note: javadocs are generated in target/apidocs
-
-## Importing into eclipse
-=========================
-
-Use the m2e eclipse plugin and do Import->Maven Project and just pick the root 'phoenix' directory.
-
-## Running the tests
-====================
-
-1. All tests 
-	$ mvn clean test
-
-## Findbugs
-===========
-Findbugs report is generated in /target/site
-	$ mvn site
-	
-
-## Generate Apache Web Site
-===========================
-checkout https://svn.apache.org/repos/asf/phoenix
-        $ build.sh
diff --git a/phoenix-assembly/pom.xml b/phoenix-assembly/pom.xml
index ec3f5da..b0d71fd 100644
--- a/phoenix-assembly/pom.xml
+++ b/phoenix-assembly/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.phoenix</groupId>
     <artifactId>phoenix</artifactId>
-    <version>5.1.0-HBase-2.0-SNAPSHOT</version>
+    <version>5.1.0-SNAPSHOT</version>
   </parent>
   <artifactId>phoenix-assembly</artifactId>
   <name>Phoenix Assembly</name>
@@ -52,8 +52,12 @@
               <workingDirectory>${project.basedir}/../phoenix-client/target</workingDirectory>
               <arguments>
                 <argument>-fnsv</argument>
-                <argument>phoenix-client-${project.version}.jar</argument>
-                <argument>phoenix-${project.version}-client.jar</argument>
+                <argument>
+                  phoenix-client-${project.version}-${hbase.profile.string}.jar
+                </argument>
+                <argument>
+                  phoenix-${project.version}-${hbase.profile.string}-client.jar
+                </argument>
               </arguments>
             </configuration>
           </execution>
@@ -81,7 +85,7 @@
               <goal>single</goal>
             </goals>
             <configuration>
-            <finalName>phoenix-${project.version}</finalName>
+            <finalName>phoenix-${project.version}-${hbase.profile.string}</finalName>
               <attach>false</attach>
               <tarLongFileMode>gnu</tarLongFileMode>
               <appendAssemblyId>false</appendAssemblyId>
diff --git a/phoenix-assembly/src/build/components/all-common-jars.xml b/phoenix-assembly/src/build/components/all-common-jars.xml
index a3a0c7e..56496f3 100644
--- a/phoenix-assembly/src/build/components/all-common-jars.xml
+++ b/phoenix-assembly/src/build/components/all-common-jars.xml
@@ -27,9 +27,9 @@
       <directory>${project.basedir}/../phoenix-client/target</directory>
       <outputDirectory>/</outputDirectory>
       <includes>
-        <include>phoenix-client-${project.version}.jar</include>
+        <include>phoenix-client-${project.version}-${hbase.compat.version.string}.jar</include>
         <!-- deprecated jar name, which we now have a symlink for -->
-        <include>phoenix-${project.version}-client.jar</include>
+        <include>phoenix-${project.version}-${hbase.compat.version.string}-client.jar</include>
       </includes>
     </fileSet>
     <fileSet>
@@ -68,5 +68,15 @@
       </includes>
       <fileMode>0644</fileMode>
     </fileSet>
+    <fileSet>
+      <directory>
+        ${project.basedir}/../phoenix-hbase-compat-${hbase.compat.version}/target/
+      </directory>
+      <outputDirectory>lib</outputDirectory>
+      <includes>
+        <include>phoenix-*.jar</include>
+      </includes>
+      <fileMode>0644</fileMode>
+    </fileSet>
   </fileSets>
 </component>
diff --git a/phoenix-client/pom.xml b/phoenix-client/pom.xml
index b8ee4a2..3cdfab1 100644
--- a/phoenix-client/pom.xml
+++ b/phoenix-client/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.phoenix</groupId>
     <artifactId>phoenix</artifactId>
-    <version>5.1.0-HBase-2.0-SNAPSHOT</version>
+    <version>5.1.0-SNAPSHOT</version>
   </parent>
   <artifactId>phoenix-client</artifactId>
   <name>Phoenix Client</name>
@@ -346,7 +346,8 @@
               <goal>shade</goal>
             </goals>
             <configuration>
-              <shadedArtifactAttached>false</shadedArtifactAttached>
+              <shadedClassifierName>${hbase.profile.string}</shadedClassifierName>
+              <shadedArtifactAttached>true</shadedArtifactAttached>
               <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
               <shadeTestJar>false</shadeTestJar>
               <createSourcesJar>true</createSourcesJar>
@@ -382,7 +383,7 @@
               <goal>shade</goal>
             </goals>
             <configuration>
-              <shadedClassifierName>embedded</shadedClassifierName>
+              <shadedClassifierName>${hbase.profile.string}-embedded</shadedClassifierName>
               <shadedArtifactAttached>true</shadedArtifactAttached>
               <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
               <shadeTestJar>false</shadeTestJar>
diff --git a/phoenix-core/pom.xml b/phoenix-core/pom.xml
index 27cadcf..81a1106 100644
--- a/phoenix-core/pom.xml
+++ b/phoenix-core/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.apache.phoenix</groupId>
     <artifactId>phoenix</artifactId>
-    <version>5.1.0-HBase-2.0-SNAPSHOT</version>
+    <version>5.1.0-SNAPSHOT</version>
   </parent>
   <artifactId>phoenix-core</artifactId>
   <name>Phoenix Core</name>
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/PermissionsCacheIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/PermissionsCacheIT.java
index 5703178..2833a23 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/PermissionsCacheIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/PermissionsCacheIT.java
@@ -28,8 +28,8 @@
 import org.apache.hadoop.hbase.AuthUtil;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.hadoop.hbase.security.access.AccessControlLists;
+import org.apache.hadoop.hbase.security.access.Permission;
 import org.apache.hadoop.hbase.security.access.Permission.Action;
-import org.apache.hadoop.hbase.security.access.TablePermission;
 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
 import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
 import org.apache.hadoop.hbase.zookeeper.ZNodePaths;
@@ -85,15 +85,16 @@
             Configuration conf = utility.getConfiguration();
             ZKWatcher zkw = HBaseTestingUtility.getZooKeeperWatcher(utility);
             String aclZnodeParent = conf.get("zookeeper.znode.acl.parent", "acl");
-            String aclZNode = ZNodePaths.joinZNode(zkw.znodePaths.baseZNode, aclZnodeParent);
+            String aclZNode = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, aclZnodeParent);
             String tableZNode = ZNodePaths.joinZNode(aclZNode, "@" + schema);
             byte[] data = ZKUtil.getData(zkw, tableZNode);
-            ListMultimap<String, TablePermission> userPermissions =
+            ListMultimap<String, ? extends Permission> userPermissions =
                     AccessControlLists.readPermissions(data, conf);
             assertTrue("User permissions not found in cache:",
                 userPermissions.containsKey(regularUser1.getName()));
-            List<TablePermission> tablePermissions = userPermissions.get(regularUser1.getName());
-            for (TablePermission tablePerm : tablePermissions) {
+            List<? extends Permission> tablePermissions =
+                    userPermissions.get(regularUser1.getName());
+            for (Permission tablePerm : tablePermissions) {
                 assertTrue("Table create permission don't exist", tablePerm.implies(Action.CREATE));
             }
         } catch (Exception e) {
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexSplitIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexSplitIT.java
index 08aecdc..4909d48 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexSplitIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexSplitIT.java
@@ -135,9 +135,12 @@
         List<RegionInfo> regionsOfUserTable = null;
         for(int i = 0; i <=1; i++) {
             boolean split = false;
-            for (int j = 0; j < 60 && !split; j++) {
+            for (int j = 0; j < 150 && !split; j++) {
                 try {
                     if (localIndex) {
+                        //With Hbase 2.2 the local index splits trigger longCompactions, and have
+                        //to wait for an RS_COMPACTED_FILES_DISCHARGER run before the second split
+                        //is successful
                         admin.split(TableName.valueOf(tableName),
                                 ByteUtil.concat(Bytes.toBytes(splitKeys[i])));
                     } else {
diff --git a/phoenix-core/src/main/java/org/apache/hadoop/hbase/ipc/PhoenixRpcScheduler.java b/phoenix-core/src/main/java/org/apache/hadoop/hbase/ipc/PhoenixRpcScheduler.java
index a27c205..486eb15 100644
--- a/phoenix-core/src/main/java/org/apache/hadoop/hbase/ipc/PhoenixRpcScheduler.java
+++ b/phoenix-core/src/main/java/org/apache/hadoop/hbase/ipc/PhoenixRpcScheduler.java
@@ -21,6 +21,7 @@
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.Abortable;
+import org.apache.phoenix.compat.hbase.CompatPhoenixRpcScheduler;
 import org.apache.phoenix.query.QueryServices;
 import org.apache.phoenix.query.QueryServicesOptions;
 
@@ -30,14 +31,13 @@
  * {@link RpcScheduler} that first checks to see if this is an index or metedata update before passing off the
  * call to the delegate {@link RpcScheduler}.
  */
-public class PhoenixRpcScheduler extends RpcScheduler {
+public class PhoenixRpcScheduler extends CompatPhoenixRpcScheduler {
 
     // copied from org.apache.hadoop.hbase.ipc.SimpleRpcScheduler in HBase 0.98.4
     private static final String CALL_QUEUE_HANDLER_FACTOR_CONF_KEY = "ipc.server.callqueue.handler.factor";
     private static final String CALLQUEUE_LENGTH_CONF_KEY = "ipc.server.max.callqueue.length";
     private static final int DEFAULT_MAX_CALLQUEUE_LENGTH_PER_HANDLER = 10;
 
-    private RpcScheduler delegate;
     private int indexPriority;
     private int metadataPriority;
     private RpcExecutor indexCallExecutor;
diff --git a/phoenix-core/src/main/java/org/apache/hadoop/hbase/regionserver/IndexHalfStoreFileReaderGenerator.java b/phoenix-core/src/main/java/org/apache/hadoop/hbase/regionserver/IndexHalfStoreFileReaderGenerator.java
index a6d057e..680eb3f 100644
--- a/phoenix-core/src/main/java/org/apache/hadoop/hbase/regionserver/IndexHalfStoreFileReaderGenerator.java
+++ b/phoenix-core/src/main/java/org/apache/hadoop/hbase/regionserver/IndexHalfStoreFileReaderGenerator.java
@@ -54,6 +54,7 @@
 import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.Pair;
+import org.apache.phoenix.compat.hbase.CompatUtil;
 import org.apache.phoenix.index.IndexMaintainer;
 import org.apache.phoenix.jdbc.PhoenixConnection;
 import org.apache.phoenix.query.QueryConstants;
@@ -116,29 +117,37 @@
                     result = scanner.next();
                 }
                 if (result == null || result.isEmpty()) {
-                    Pair<RegionInfo, RegionInfo> mergeRegions =
-                            MetaTableAccessor.getRegionsFromMergeQualifier(ctx.getEnvironment().getConnection(),
+                    List<RegionInfo> mergeRegions =
+                            CompatUtil.getMergeRegions(ctx.getEnvironment().getConnection(),
                                 region.getRegionInfo().getRegionName());
-                    if (mergeRegions == null || mergeRegions.getFirst() == null) return reader;
+                    if (mergeRegions == null || mergeRegions.isEmpty()){
+                        return reader;
+                    }
                     byte[] splitRow =
                             CellUtil.cloneRow(KeyValueUtil.createKeyValueFromKey(r.getSplitKey()));
                     // We need not change any thing in first region data because first region start key
                     // is equal to merged region start key. So returning same reader.
-                    if (Bytes.compareTo(mergeRegions.getFirst().getStartKey(), splitRow) == 0) {
-                        if (mergeRegions.getFirst().getStartKey().length == 0
-                                && region.getRegionInfo().getEndKey().length != mergeRegions
-                                        .getFirst().getEndKey().length) {
-                            childRegion = mergeRegions.getFirst();
+                    if (Bytes.compareTo(mergeRegions.get(0).getStartKey(), splitRow) == 0) {
+                        if (mergeRegions.get(0).getStartKey().length == 0
+                                 && region.getRegionInfo().getEndKey().length
+                                         != mergeRegions.get(0).getEndKey().length) {
+                            childRegion = mergeRegions.get(0);
                             regionStartKeyInHFile =
-                                    mergeRegions.getFirst().getStartKey().length == 0 ? new byte[mergeRegions
-                                            .getFirst().getEndKey().length] : mergeRegions.getFirst()
-                                            .getStartKey();
+                                    mergeRegions.get(0).getStartKey().length == 0
+                                            ? new byte[mergeRegions.get(0).getEndKey().length]
+                                            : mergeRegions.get(0).getStartKey();
                         } else {
                             return reader;
                         }
                     } else {
-                        childRegion = mergeRegions.getSecond();
-                        regionStartKeyInHFile = mergeRegions.getSecond().getStartKey();
+                        for (RegionInfo mergeRegion :
+                                mergeRegions.subList(1, mergeRegions.size())) {
+                            if (Bytes.compareTo(mergeRegion.getStartKey(), splitRow) == 0) {
+                                childRegion = mergeRegion;
+                                regionStartKeyInHFile = mergeRegion.getStartKey();
+                                break;
+                            }
+                        }
                     }
                     splitKey = KeyValueUtil.createFirstOnRow(region.getRegionInfo().getStartKey().length == 0 ?
                         new byte[region.getRegionInfo().getEndKey().length] :
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/PhoenixAccessController.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/PhoenixAccessController.java
index 1ab6e6d..d21005c 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/PhoenixAccessController.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/PhoenixAccessController.java
@@ -61,10 +61,10 @@
 import org.apache.hadoop.hbase.security.access.AuthResult;
 import org.apache.hadoop.hbase.security.access.Permission;
 import org.apache.hadoop.hbase.security.access.Permission.Action;
-import org.apache.hadoop.hbase.security.access.TableAuthManager;
 import org.apache.hadoop.hbase.security.access.UserPermission;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
+import org.apache.phoenix.compat.hbase.CompatPermissionUtil;
 import org.apache.phoenix.coprocessor.PhoenixMetaDataCoprocessorHost.PhoenixMetaDataControllerEnvironment;
 import org.apache.phoenix.query.QueryServices;
 import org.apache.phoenix.query.QueryServicesOptions;
@@ -79,6 +79,9 @@
 import com.google.protobuf.RpcCallback;
 import com.google.protobuf.RpcController;
 
+import static org.apache.phoenix.compat.hbase.CompatPermissionUtil.authorizeUserTable;
+import static org.apache.phoenix.compat.hbase.CompatPermissionUtil.getUserFromUP;
+import static org.apache.phoenix.compat.hbase.CompatPermissionUtil.getPermissionFromUP;
 
 public class PhoenixAccessController extends BaseMetaDataEndpointObserver {
 
@@ -158,7 +161,7 @@
     @Override
     public void stop(CoprocessorEnvironment env) throws IOException {
         if(accessChecker.getAuthManager() != null) {
-            TableAuthManager.release(accessChecker.getAuthManager());
+            CompatPermissionUtil.stopAccessChecker(accessChecker);
         }
     }
 
@@ -198,22 +201,22 @@
 
                 User user = getActiveUser();
                 List<UserPermission> permissionForUser = getPermissionForUser(
-                        getUserPermissions(index), Bytes.toBytes(user.getShortName()));
+                        getUserPermissions(index), user.getShortName());
                 Set<Action> requireAccess = new HashSet<>();
                 Set<Action> accessExists = new HashSet<>();
                 if (permissionForUser != null) {
                     for (UserPermission userPermission : permissionForUser) {
                         for (Action action : Arrays.asList(requiredActions)) {
-                            if (!userPermission.implies(action)) {
+                            if (!getPermissionFromUP(userPermission).implies(action)) {
                                 requireAccess.add(action);
                             }
                         }
                     }
                     if (!requireAccess.isEmpty()) {
                         for (UserPermission userPermission : permissionForUser) {
-                            accessExists.addAll(Arrays.asList(userPermission.getActions()));
+                            accessExists.addAll(Arrays.asList(
+                                getPermissionFromUP(userPermission).getActions()));
                         }
-
                     }
                 } else {
                     requireAccess.addAll(Arrays.asList(requiredActions));
@@ -286,15 +289,15 @@
                             Set<Action> requireAccess = new HashSet<Action>();
                             Set<Action> accessExists = new HashSet<Action>();
                             List<UserPermission> permsToTable = getPermissionForUser(permissionsOnTheTable,
-                                    userPermission.getUser());
+                                    getUserFromUP(userPermission));
                             for (Action action : requiredActionsOnTable) {
                                 boolean haveAccess=false;
-                                if (userPermission.implies(action)) {
+                                if (getPermissionFromUP(userPermission).implies(action)) {
                                     if (permsToTable == null) {
                                         requireAccess.add(action);
                                     } else {
                                         for (UserPermission permToTable : permsToTable) {
-                                            if (permToTable.implies(action)) {
+                                            if (getPermissionFromUP(permToTable).implies(action)) {
                                                 haveAccess=true;
                                             }
                                         }
@@ -307,19 +310,21 @@
                             if (permsToTable != null) {
                                 // Append access to already existing access for the user
                                 for (UserPermission permToTable : permsToTable) {
-                                    accessExists.addAll(Arrays.asList(permToTable.getActions()));
+                                    accessExists.addAll(Arrays.asList(
+                                        getPermissionFromUP(permToTable).getActions()));
                                 }
                             }
                             if (!requireAccess.isEmpty()) {
-                                if(AuthUtil.isGroupPrincipal(Bytes.toString(userPermission.getUser()))){
-                                    AUDITLOG.warn("Users of GROUP:" + Bytes.toString(userPermission.getUser())
+                                if(AuthUtil.isGroupPrincipal(getUserFromUP(userPermission))){
+                                    AUDITLOG.warn("Users of GROUP:" + getUserFromUP(userPermission)
                                             + " will not have following access " + requireAccess
                                             + " to the newly created index " + toTable
                                             + ", Automatic grant is not yet allowed on Groups");
                                     continue;
                                 }
-                                handleRequireAccessOnDependentTable(request, Bytes.toString(userPermission.getUser()),
-                                        toTable, toTable.getNameAsString(), requireAccess, accessExists);
+                                handleRequireAccessOnDependentTable(request,
+                                        getUserFromUP(userPermission), toTable,
+                                        toTable.getNameAsString(), requireAccess, accessExists);
                             }
                         }
                     }
@@ -329,13 +334,13 @@
         });
     }
 
-    private List<UserPermission> getPermissionForUser(List<UserPermission> perms, byte[] user) {
+    private List<UserPermission> getPermissionForUser(List<UserPermission> perms, String user) {
         if (perms != null) {
             // get list of permissions for the user as multiple implementation of AccessControl coprocessors can give
             // permissions for same users
             List<UserPermission> permissions = new ArrayList<>();
             for (UserPermission p : perms) {
-                if (Bytes.equals(p.getUser(),user)){
+                if (getUserFromUP(p).equals(user)){
                      permissions.add(p);
                 }
             }
@@ -464,12 +469,14 @@
          return userPermissions;
        }
 
+     //FIXME This seems to have no effect at all
      private void getUserDefinedPermissions(final TableName tableName,
              final List<UserPermission> userPermissions) throws IOException {
           User.runAsLoginUser(new PrivilegedExceptionAction<List<UserPermission>>() {
               @Override
               public List<UserPermission> run() throws Exception {
-                  final List<UserPermission> userPermissions = new ArrayList<UserPermission>();
+                 //FIXME We are masking the parameter list that we are supposed to add to
+                 final List<UserPermission> userPermissions = new ArrayList<UserPermission>();
                  try (Connection connection =
                          ConnectionFactory.createConnection(((CoprocessorEnvironment) env).getConfiguration())) {
                       for (MasterObserver service : getAccessControllers()) {
@@ -544,10 +551,7 @@
         User user = getActiveUser();
         AuthResult result = null;
         List<Action> requiredAccess = new ArrayList<Action>();
-        List<UserPermission> userPermissions = new ArrayList<>();
-        if(permissions.length > 0) {
-           getUserDefinedPermissions(tableName, userPermissions);
-        }
+
         for (Action permission : permissions) {
              if (hasAccess(getUserPermissions(tableName), tableName, permission, user)) {
                 result = AuthResult.allow(request, "Table permission granted", user, permission, tableName, null, null);
@@ -578,26 +582,23 @@
         }
         if (perms != null) {
             if (hbaseAccessControllerEnabled
-                    && accessChecker.getAuthManager().userHasAccess(user, table, action)) {
+                    && authorizeUserTable(accessChecker, user, table, action)) {
                 return true;
             }
-            List<UserPermission> permissionsForUser = getPermissionForUser(perms, user.getShortName().getBytes());
+            List<UserPermission> permissionsForUser =
+                    getPermissionForUser(perms, user.getShortName());
             if (permissionsForUser != null) {
                 for (UserPermission permissionForUser : permissionsForUser) {
-                    if (permissionForUser.implies(action)) { return true; }
+                    if (getPermissionFromUP(permissionForUser).implies(action)) { return true; }
                 }
             }
             String[] groupNames = user.getGroupNames();
             if (groupNames != null) {
               for (String group : groupNames) {
-                    List<UserPermission> groupPerms =
-                            getPermissionForUser(perms, (AuthUtil.toGroupEntry(group)).getBytes());
-                    if (hbaseAccessControllerEnabled && accessChecker.getAuthManager()
-                            .groupHasAccess(group, table, action)) {
-                        return true;
-                    }
+                List<UserPermission> groupPerms =
+                        getPermissionForUser(perms, (AuthUtil.toGroupEntry(group)));
                 if (groupPerms != null) for (UserPermission permissionForUser : groupPerms) {
-                    if (permissionForUser.implies(action)) { return true; }
+                    if (getPermissionFromUP(permissionForUser).implies(action)) { return true; }
                 }
               }
             }
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
index a3d83fc..a61fdf7 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
@@ -69,6 +69,7 @@
 import org.apache.hadoop.hbase.regionserver.Store;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.io.WritableUtils;
+import org.apache.phoenix.compat.hbase.OffsetCell;
 import org.apache.phoenix.compile.ColumnResolver;
 import org.apache.phoenix.compile.FromCompiler;
 import org.apache.phoenix.compile.IndexStatementRewriter;
@@ -604,102 +605,7 @@
         while (itr.hasNext()) {
             final Cell cell = itr.next();
             // TODO: Create DelegateCell class instead
-            Cell newCell = new Cell() {
-
-                @Override
-                public byte[] getRowArray() {
-                    return cell.getRowArray();
-                }
-
-                @Override
-                public int getRowOffset() {
-                    return cell.getRowOffset() + offset;
-                }
-
-                @Override
-                public short getRowLength() {
-                    return (short) (cell.getRowLength() - offset);
-                }
-
-                @Override
-                public byte[] getFamilyArray() {
-                    return cell.getFamilyArray();
-                }
-
-                @Override
-                public int getFamilyOffset() {
-                    return cell.getFamilyOffset();
-                }
-
-                @Override
-                public byte getFamilyLength() {
-                    return cell.getFamilyLength();
-                }
-
-                @Override
-                public byte[] getQualifierArray() {
-                    return cell.getQualifierArray();
-                }
-
-                @Override
-                public int getQualifierOffset() {
-                    return cell.getQualifierOffset();
-                }
-
-                @Override
-                public int getQualifierLength() {
-                    return cell.getQualifierLength();
-                }
-
-                @Override
-                public long getTimestamp() {
-                    return cell.getTimestamp();
-                }
-
-                @Override
-                public byte getTypeByte() {
-                    return cell.getTypeByte();
-                }
-
-                @Override public long getSequenceId() {
-                    return cell.getSequenceId();
-                }
-
-                @Override
-                public byte[] getValueArray() {
-                    return cell.getValueArray();
-                }
-
-                @Override
-                public int getValueOffset() {
-                    return cell.getValueOffset();
-                }
-
-                @Override
-                public int getValueLength() {
-                    return cell.getValueLength();
-                }
-
-                @Override
-                public byte[] getTagsArray() {
-                    return cell.getTagsArray();
-                }
-
-                @Override
-                public int getTagsOffset() {
-                    return cell.getTagsOffset();
-                }
-
-                @Override
-                public int getTagsLength() {
-                    return cell.getTagsLength();
-                }
-
-                @Override
-                public Type getType() {
-                    return cell.getType();
-                }
-            };
+            Cell newCell = new OffsetCell(cell, offset);
             itr.set(newCell);
         }
     }
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixKeyValueUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixKeyValueUtil.java
index bc94836..1c7519c 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixKeyValueUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixKeyValueUtil.java
@@ -35,6 +35,7 @@
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.Pair;
+import org.apache.phoenix.compat.hbase.CompatUtil;
 import org.apache.phoenix.execute.MutationState.MultiRowMutationState;
 import org.apache.phoenix.execute.MutationState.RowMutationState;
 import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
@@ -179,7 +180,7 @@
         long size = 0;
         for (Entry<byte [], List<Cell>> entry : m.getFamilyCellMap().entrySet()) {
             for (Cell c : entry.getValue()) {
-                size += org.apache.hadoop.hbase.KeyValueUtil.length(c);
+                size += CompatUtil.getCellSerializedSize(c);
             }
         }
         return size;
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/EncodedColumnQualifierCellsListTest.java b/phoenix-core/src/test/java/org/apache/phoenix/query/EncodedColumnQualifierCellsListTest.java
index 95e038b..67d2371 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/query/EncodedColumnQualifierCellsListTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/query/EncodedColumnQualifierCellsListTest.java
@@ -35,6 +35,7 @@
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.KeyValueUtil;
 import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.phoenix.compat.hbase.test.DelegateCell;
 import org.apache.phoenix.schema.tuple.EncodedColumnQualiferCellsList;
 import org.junit.Test;
 
@@ -474,113 +475,4 @@
         list.add(KeyValueUtil.createFirstOnRow(row, cf, FOUR_BYTE_QUALIFIERS.encode(14)));
         list.add(KeyValueUtil.createFirstOnRow(row, cf, FOUR_BYTE_QUALIFIERS.encode(11)));
     }
-    
-    private class DelegateCell implements Cell {
-        private final Cell delegate;
-        private final String name;
-        public DelegateCell(Cell delegate, String name) {
-            this.delegate = delegate;
-            this.name = name;
-        }
-
-        @Override
-        public int getValueOffset() {
-            return delegate.getValueOffset();
-        }
-
-        @Override
-        public int getValueLength() {
-            return delegate.getValueLength();
-        }
-
-        @Override
-        public byte[] getValueArray() {
-            return delegate.getValueArray();
-        }
-
-        @Override
-        public byte getTypeByte() {
-            return delegate.getTypeByte();
-        }
-
-        @Override
-        public long getTimestamp() {
-            return delegate.getTimestamp();
-        }
-
-        @Override
-        public int getTagsOffset() {
-            return delegate.getTagsOffset();
-        }
-
-        @Override
-        public byte[] getTagsArray() {
-            return delegate.getTagsArray();
-        }
-
-        @Override
-        public int getRowOffset() {
-            return delegate.getRowOffset();
-        }
-
-        @Override
-        public short getRowLength() {
-            return delegate.getRowLength();
-        }
-
-        @Override
-        public byte[] getRowArray() {
-            return delegate.getRowArray();
-        }
-
-        @Override
-        public int getQualifierOffset() {
-            return delegate.getQualifierOffset();
-        }
-
-        @Override
-        public int getQualifierLength() {
-            return delegate.getQualifierLength();
-        }
-
-        @Override
-        public byte[] getQualifierArray() {
-            return delegate.getQualifierArray();
-        }
-
-        @Override
-        public int getFamilyOffset() {
-            return delegate.getFamilyOffset();
-        }
-
-        @Override
-        public byte getFamilyLength() {
-            return delegate.getFamilyLength();
-        }
-
-        @Override
-        public byte[] getFamilyArray() {
-            return delegate.getFamilyArray();
-        }
-
-        @Override
-        public String toString() {
-            return name;
-        }
-
-        @Override
-        public long getSequenceId() {
-            return delegate.getSequenceId();
-        }
-
-        @Override
-        public int getTagsLength() {
-            return delegate.getTagsLength();
-        }
-
-        @Override
-        public Type getType() {
-            return delegate.getType();
-        }
-    }
 }
diff --git a/phoenix-hbase-compat-2.0.1/pom.xml b/phoenix-hbase-compat-2.0.1/pom.xml
new file mode 100644
index 0000000..cfa04e1
--- /dev/null
+++ b/phoenix-hbase-compat-2.0.1/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation=
+    "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+    <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>21</version>
+  </parent>
+  <groupId>org.apache.phoenix</groupId>
+  <artifactId>phoenix-hbase-compat-2.0.1</artifactId>
+  <version>5.1.0-SNAPSHOT</version>
+  <name>Phoenix Hbase 2.0.1 compatibility</name>
+  <description>Compatibility module for HBase 2.0.1 - 2.0.4 and 2.1.0 - 2.1.1</description>
+
+  <build>
+    <plugins>
+      <!-- Setup eclipse -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-eclipse-plugin</artifactId>
+        <version>2.9</version>
+        <configuration>
+          <buildcommands>
+            <buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
+          </buildcommands>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+       <!-- HBase dependencies -->
+      <dependency>
+        <groupId>org.apache.hbase</groupId>
+        <artifactId>hbase-endpoint</artifactId>
+        <version>2.0.1</version>
+        <scope>provided</scope>
+      </dependency>
+  </dependencies>
+
+  <reporting>
+      <plugins>
+          <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-project-info-reports-plugin</artifactId>
+          </plugin>
+          <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>findbugs-maven-plugin</artifactId>
+          </plugin>
+      </plugins>
+  </reporting>
+</project>
diff --git a/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPermissionUtil.java b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPermissionUtil.java
new file mode 100644
index 0000000..fdf572c
--- /dev/null
+++ b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPermissionUtil.java
@@ -0,0 +1,66 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.security.User;
+import org.apache.hadoop.hbase.security.access.AccessChecker;
+import org.apache.hadoop.hbase.security.access.Permission;
+import org.apache.hadoop.hbase.security.access.TableAuthManager;
+import org.apache.hadoop.hbase.security.access.UserPermission;
+import org.apache.hadoop.hbase.util.Bytes;
+
+public class CompatPermissionUtil {
+
+    private CompatPermissionUtil() {
+        //Nott to be instantiated
+    }
+
+    public static void stopAccessChecker(AccessChecker accessChecker) throws IOException {
+        if (accessChecker.getAuthManager() != null) {
+            TableAuthManager.release(accessChecker.getAuthManager());
+        }
+    }
+
+    public static String getUserFromUP(UserPermission userPermission) {
+        return Bytes.toString(userPermission.getUser());
+    }
+
+    public static Permission getPermissionFromUP(UserPermission userPermission) {
+        return userPermission;
+    }
+
+    public static boolean authorizeUserTable(AccessChecker accessChecker, User user, 
+            TableName table, Permission.Action action) {
+        if(accessChecker.getAuthManager().userHasAccess(user, table, action)) {
+            return true;
+        }
+        String[] groupNames = user.getGroupNames();
+        if (groupNames != null) {
+          for (String group : groupNames) {
+            if(accessChecker.getAuthManager().groupHasAccess(group, table, action)) {
+                return true;
+            }
+          }
+        }
+        return false;
+    }
+
+}
diff --git a/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPhoenixRpcScheduler.java b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPhoenixRpcScheduler.java
new file mode 100644
index 0000000..3187e23
--- /dev/null
+++ b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPhoenixRpcScheduler.java
@@ -0,0 +1,28 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import org.apache.hadoop.hbase.ipc.RpcScheduler;
+
+/**
+ * {@link RpcScheduler} that first checks to see if this is an index or metedata 
+ * update before passing off the call to the delegate {@link RpcScheduler}.
+ */
+public abstract class CompatPhoenixRpcScheduler extends RpcScheduler {
+    protected RpcScheduler delegate;
+}
diff --git a/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/CompatUtil.java b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/CompatUtil.java
new file mode 100644
index 0000000..117ff53
--- /dev/null
+++ b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/CompatUtil.java
@@ -0,0 +1,49 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.MetaTableAccessor;
+import org.apache.hadoop.hbase.client.Connection;
+import org.apache.hadoop.hbase.client.RegionInfo;
+import org.apache.hadoop.hbase.util.Pair;
+
+public class CompatUtil {
+
+    private CompatUtil() {
+        //Not to be instantiated
+    }
+
+    public static List<RegionInfo> getMergeRegions(Connection conn, byte[] regionName) 
+            throws IOException {
+        Pair<RegionInfo, RegionInfo> regionPair = 
+                MetaTableAccessor.getRegionsFromMergeQualifier(conn,regionName);
+        List<RegionInfo> regionList = new ArrayList<RegionInfo>(2);
+        regionList.add(regionPair.getFirst());
+        regionList.add(regionPair.getSecond());
+        return regionList;
+    }
+
+    public static int getCellSerializedSize(Cell cell) {
+        return org.apache.hadoop.hbase.KeyValueUtil.length(cell);
+    }
+}
diff --git a/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/OffsetCell.java b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/OffsetCell.java
new file mode 100644
index 0000000..e0e7258
--- /dev/null
+++ b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/OffsetCell.java
@@ -0,0 +1,126 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import org.apache.hadoop.hbase.Cell;
+
+public class OffsetCell implements Cell {
+
+    private Cell cell;
+    private int offset;
+
+    public OffsetCell(Cell cell, int offset) {
+        this.cell = cell;
+        this.offset = offset;
+    }
+
+    @Override
+    public byte[] getRowArray() {
+        return cell.getRowArray();
+    }
+
+    @Override
+    public int getRowOffset() {
+        return cell.getRowOffset() + offset;
+    }
+
+    @Override
+    public short getRowLength() {
+        return (short) (cell.getRowLength() - offset);
+    }
+
+    @Override
+    public byte[] getFamilyArray() {
+        return cell.getFamilyArray();
+    }
+
+    @Override
+    public int getFamilyOffset() {
+        return cell.getFamilyOffset();
+    }
+
+    @Override
+    public byte getFamilyLength() {
+        return cell.getFamilyLength();
+    }
+
+    @Override
+    public byte[] getQualifierArray() {
+        return cell.getQualifierArray();
+    }
+
+    @Override
+    public int getQualifierOffset() {
+        return cell.getQualifierOffset();
+    }
+
+    @Override
+    public int getQualifierLength() {
+        return cell.getQualifierLength();
+    }
+
+    @Override
+    public long getTimestamp() {
+        return cell.getTimestamp();
+    }
+
+    @Override
+    public byte getTypeByte() {
+        return cell.getTypeByte();
+    }
+
+    @Override public long getSequenceId() {
+        return cell.getSequenceId();
+    }
+
+    @Override
+    public byte[] getValueArray() {
+        return cell.getValueArray();
+    }
+
+    @Override
+    public int getValueOffset() {
+        return cell.getValueOffset();
+    }
+
+    @Override
+    public int getValueLength() {
+        return cell.getValueLength();
+    }
+
+    @Override
+    public byte[] getTagsArray() {
+        return cell.getTagsArray();
+    }
+
+    @Override
+    public int getTagsOffset() {
+        return cell.getTagsOffset();
+    }
+
+    @Override
+    public int getTagsLength() {
+        return cell.getTagsLength();
+    }
+
+    @Override
+    public Type getType() {
+        return cell.getType();
+    }
+
+}
diff --git a/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/test/DelegateCell.java b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/test/DelegateCell.java
new file mode 100644
index 0000000..ed0079d
--- /dev/null
+++ b/phoenix-hbase-compat-2.0.1/src/main/java/org/apache/phoenix/compat/hbase/test/DelegateCell.java
@@ -0,0 +1,129 @@
+/*
+ * 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.phoenix.compat.hbase.test;
+
+import org.apache.hadoop.hbase.Cell;
+
+public class DelegateCell implements Cell {
+    private final Cell delegate;
+    private final String name;
+    public DelegateCell(Cell delegate, String name) {
+        this.delegate = delegate;
+        this.name = name;
+    }
+
+    @Override
+    public int getValueOffset() {
+        return delegate.getValueOffset();
+    }
+
+    @Override
+    public int getValueLength() {
+        return delegate.getValueLength();
+    }
+
+    @Override
+    public byte[] getValueArray() {
+        return delegate.getValueArray();
+    }
+
+    @Override
+    public byte getTypeByte() {
+        return delegate.getTypeByte();
+    }
+
+    @Override
+    public long getTimestamp() {
+        return delegate.getTimestamp();
+    }
+
+    @Override
+    public int getTagsOffset() {
+        return delegate.getTagsOffset();
+    }
+
+    @Override
+    public byte[] getTagsArray() {
+        return delegate.getTagsArray();
+    }
+
+    @Override
+    public int getRowOffset() {
+        return delegate.getRowOffset();
+    }
+
+    @Override
+    public short getRowLength() {
+        return delegate.getRowLength();
+    }
+
+    @Override
+    public byte[] getRowArray() {
+        return delegate.getRowArray();
+    }
+
+    @Override
+    public int getQualifierOffset() {
+        return delegate.getQualifierOffset();
+    }
+
+    @Override
+    public int getQualifierLength() {
+        return delegate.getQualifierLength();
+    }
+
+    @Override
+    public byte[] getQualifierArray() {
+        return delegate.getQualifierArray();
+    }
+
+    @Override
+    public int getFamilyOffset() {
+        return delegate.getFamilyOffset();
+    }
+
+    @Override
+    public byte getFamilyLength() {
+        return delegate.getFamilyLength();
+    }
+
+    @Override
+    public byte[] getFamilyArray() {
+        return delegate.getFamilyArray();
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    @Override
+    public long getSequenceId() {
+        return delegate.getSequenceId();
+    }
+
+    @Override
+    public int getTagsLength() {
+        return delegate.getTagsLength();
+    }
+
+    @Override
+    public Type getType() {
+        return delegate.getType();
+    }
+}
diff --git a/phoenix-hbase-compat-2.1.6/pom.xml b/phoenix-hbase-compat-2.1.6/pom.xml
new file mode 100644
index 0000000..18a52ec
--- /dev/null
+++ b/phoenix-hbase-compat-2.1.6/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation=
+    "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+    <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>21</version>
+  </parent>
+  <groupId>org.apache.phoenix</groupId>
+  <artifactId>phoenix-hbase-compat-2.1.6</artifactId>
+  <version>5.1.0-SNAPSHOT</version>
+  <name>Phoenix Hbase 2.1.6 compatibility</name>
+  <description>Compatibility module for HBase 2.1.6+</description>
+
+  <build>
+    <plugins>
+      <!-- Setup eclipse -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-eclipse-plugin</artifactId>
+        <version>2.9</version>
+        <configuration>
+          <buildcommands>
+            <buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
+          </buildcommands>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+       <!-- HBase dependencies -->
+      <dependency>
+        <groupId>org.apache.hbase</groupId>
+        <artifactId>hbase-endpoint</artifactId>
+        <version>2.1.6</version>
+        <scope>provided</scope>
+      </dependency>
+  </dependencies>
+
+  <reporting>
+      <plugins>
+          <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-project-info-reports-plugin</artifactId>
+          </plugin>
+          <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>findbugs-maven-plugin</artifactId>
+          </plugin>
+      </plugins>
+  </reporting>
+</project>
diff --git a/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/CompatPermissionUtil.java b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/CompatPermissionUtil.java
new file mode 100644
index 0000000..fdf572c
--- /dev/null
+++ b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/CompatPermissionUtil.java
@@ -0,0 +1,66 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.security.User;
+import org.apache.hadoop.hbase.security.access.AccessChecker;
+import org.apache.hadoop.hbase.security.access.Permission;
+import org.apache.hadoop.hbase.security.access.TableAuthManager;
+import org.apache.hadoop.hbase.security.access.UserPermission;
+import org.apache.hadoop.hbase.util.Bytes;
+
+public class CompatPermissionUtil {
+
+    private CompatPermissionUtil() {
+        //Nott to be instantiated
+    }
+
+    public static void stopAccessChecker(AccessChecker accessChecker) throws IOException {
+        if (accessChecker.getAuthManager() != null) {
+            TableAuthManager.release(accessChecker.getAuthManager());
+        }
+    }
+
+    public static String getUserFromUP(UserPermission userPermission) {
+        return Bytes.toString(userPermission.getUser());
+    }
+
+    public static Permission getPermissionFromUP(UserPermission userPermission) {
+        return userPermission;
+    }
+
+    public static boolean authorizeUserTable(AccessChecker accessChecker, User user, 
+            TableName table, Permission.Action action) {
+        if(accessChecker.getAuthManager().userHasAccess(user, table, action)) {
+            return true;
+        }
+        String[] groupNames = user.getGroupNames();
+        if (groupNames != null) {
+          for (String group : groupNames) {
+            if(accessChecker.getAuthManager().groupHasAccess(group, table, action)) {
+                return true;
+            }
+          }
+        }
+        return false;
+    }
+
+}
diff --git a/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/CompatPhoenixRpcScheduler.java b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/CompatPhoenixRpcScheduler.java
new file mode 100644
index 0000000..af25975
--- /dev/null
+++ b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/CompatPhoenixRpcScheduler.java
@@ -0,0 +1,27 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import org.apache.hadoop.hbase.ipc.RpcScheduler;
+
+/**
+ * {@link RpcScheduler} that first checks to see if this is an index or metedata update before
+ * passing off the call to the delegate {@link RpcScheduler}.
+ */
+public abstract class CompatPhoenixRpcScheduler extends RpcScheduler {
+    protected RpcScheduler delegate;
+
+    @Override
+    public int getMetaPriorityQueueLength() {
+        return this.delegate.getMetaPriorityQueueLength();
+    }
+
+}
diff --git a/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/CompatUtil.java b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/CompatUtil.java
new file mode 100644
index 0000000..61dfeec
--- /dev/null
+++ b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/CompatUtil.java
@@ -0,0 +1,42 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.MetaTableAccessor;
+import org.apache.hadoop.hbase.client.Connection;
+import org.apache.hadoop.hbase.client.RegionInfo;
+
+public class CompatUtil {
+
+    private CompatUtil() {
+        //Not to be instantiated
+    }
+
+    public static List<RegionInfo> getMergeRegions(Connection conn, byte[] regionName) 
+            throws IOException {
+        return MetaTableAccessor.getMergeRegions(conn, regionName);
+    }
+
+    public static int getCellSerializedSize(Cell cell) {
+        return org.apache.hadoop.hbase.KeyValueUtil.length(cell);
+    }
+}
diff --git a/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/OffsetCell.java b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/OffsetCell.java
new file mode 100644
index 0000000..e0e7258
--- /dev/null
+++ b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/OffsetCell.java
@@ -0,0 +1,126 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import org.apache.hadoop.hbase.Cell;
+
+public class OffsetCell implements Cell {
+
+    private Cell cell;
+    private int offset;
+
+    public OffsetCell(Cell cell, int offset) {
+        this.cell = cell;
+        this.offset = offset;
+    }
+
+    @Override
+    public byte[] getRowArray() {
+        return cell.getRowArray();
+    }
+
+    @Override
+    public int getRowOffset() {
+        return cell.getRowOffset() + offset;
+    }
+
+    @Override
+    public short getRowLength() {
+        return (short) (cell.getRowLength() - offset);
+    }
+
+    @Override
+    public byte[] getFamilyArray() {
+        return cell.getFamilyArray();
+    }
+
+    @Override
+    public int getFamilyOffset() {
+        return cell.getFamilyOffset();
+    }
+
+    @Override
+    public byte getFamilyLength() {
+        return cell.getFamilyLength();
+    }
+
+    @Override
+    public byte[] getQualifierArray() {
+        return cell.getQualifierArray();
+    }
+
+    @Override
+    public int getQualifierOffset() {
+        return cell.getQualifierOffset();
+    }
+
+    @Override
+    public int getQualifierLength() {
+        return cell.getQualifierLength();
+    }
+
+    @Override
+    public long getTimestamp() {
+        return cell.getTimestamp();
+    }
+
+    @Override
+    public byte getTypeByte() {
+        return cell.getTypeByte();
+    }
+
+    @Override public long getSequenceId() {
+        return cell.getSequenceId();
+    }
+
+    @Override
+    public byte[] getValueArray() {
+        return cell.getValueArray();
+    }
+
+    @Override
+    public int getValueOffset() {
+        return cell.getValueOffset();
+    }
+
+    @Override
+    public int getValueLength() {
+        return cell.getValueLength();
+    }
+
+    @Override
+    public byte[] getTagsArray() {
+        return cell.getTagsArray();
+    }
+
+    @Override
+    public int getTagsOffset() {
+        return cell.getTagsOffset();
+    }
+
+    @Override
+    public int getTagsLength() {
+        return cell.getTagsLength();
+    }
+
+    @Override
+    public Type getType() {
+        return cell.getType();
+    }
+
+}
diff --git a/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/test/DelegateCell.java b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/test/DelegateCell.java
new file mode 100644
index 0000000..ed0079d
--- /dev/null
+++ b/phoenix-hbase-compat-2.1.6/src/main/java/org/apache/phoenix/compat/hbase/test/DelegateCell.java
@@ -0,0 +1,129 @@
+/*
+ * 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.phoenix.compat.hbase.test;
+
+import org.apache.hadoop.hbase.Cell;
+
+public class DelegateCell implements Cell {
+    private final Cell delegate;
+    private final String name;
+    public DelegateCell(Cell delegate, String name) {
+        this.delegate = delegate;
+        this.name = name;
+    }
+
+    @Override
+    public int getValueOffset() {
+        return delegate.getValueOffset();
+    }
+
+    @Override
+    public int getValueLength() {
+        return delegate.getValueLength();
+    }
+
+    @Override
+    public byte[] getValueArray() {
+        return delegate.getValueArray();
+    }
+
+    @Override
+    public byte getTypeByte() {
+        return delegate.getTypeByte();
+    }
+
+    @Override
+    public long getTimestamp() {
+        return delegate.getTimestamp();
+    }
+
+    @Override
+    public int getTagsOffset() {
+        return delegate.getTagsOffset();
+    }
+
+    @Override
+    public byte[] getTagsArray() {
+        return delegate.getTagsArray();
+    }
+
+    @Override
+    public int getRowOffset() {
+        return delegate.getRowOffset();
+    }
+
+    @Override
+    public short getRowLength() {
+        return delegate.getRowLength();
+    }
+
+    @Override
+    public byte[] getRowArray() {
+        return delegate.getRowArray();
+    }
+
+    @Override
+    public int getQualifierOffset() {
+        return delegate.getQualifierOffset();
+    }
+
+    @Override
+    public int getQualifierLength() {
+        return delegate.getQualifierLength();
+    }
+
+    @Override
+    public byte[] getQualifierArray() {
+        return delegate.getQualifierArray();
+    }
+
+    @Override
+    public int getFamilyOffset() {
+        return delegate.getFamilyOffset();
+    }
+
+    @Override
+    public byte getFamilyLength() {
+        return delegate.getFamilyLength();
+    }
+
+    @Override
+    public byte[] getFamilyArray() {
+        return delegate.getFamilyArray();
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    @Override
+    public long getSequenceId() {
+        return delegate.getSequenceId();
+    }
+
+    @Override
+    public int getTagsLength() {
+        return delegate.getTagsLength();
+    }
+
+    @Override
+    public Type getType() {
+        return delegate.getType();
+    }
+}
diff --git a/phoenix-hbase-compat-2.2.1/pom.xml b/phoenix-hbase-compat-2.2.1/pom.xml
new file mode 100644
index 0000000..f142a36
--- /dev/null
+++ b/phoenix-hbase-compat-2.2.1/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation=
+    "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+    <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>21</version>
+  </parent>
+  <groupId>org.apache.phoenix</groupId>
+  <artifactId>phoenix-hbase-compat-2.2.1</artifactId>
+  <version>5.1.0-SNAPSHOT</version>
+  <name>Phoenix Hbase 2.2.1 compatibility</name>
+  <description>Compatibility module for HBase 2.2.1+</description>
+
+  <build>
+    <plugins>
+      <!-- Setup eclipse -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-eclipse-plugin</artifactId>
+        <version>2.9</version>
+        <configuration>
+          <buildcommands>
+            <buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
+          </buildcommands>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+       <!-- HBase dependencies -->
+      <dependency>
+        <groupId>org.apache.hbase</groupId>
+        <artifactId>hbase-endpoint</artifactId>
+        <version>2.2.1</version>
+        <scope>provided</scope>
+      </dependency>
+  </dependencies>
+
+  <reporting>
+      <plugins>
+          <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-project-info-reports-plugin</artifactId>
+          </plugin>
+          <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>findbugs-maven-plugin</artifactId>
+          </plugin>
+      </plugins>
+  </reporting>
+</project>
diff --git a/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPermissionUtil.java b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPermissionUtil.java
new file mode 100644
index 0000000..84b304b
--- /dev/null
+++ b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPermissionUtil.java
@@ -0,0 +1,52 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.security.User;
+import org.apache.hadoop.hbase.security.access.AccessChecker;
+import org.apache.hadoop.hbase.security.access.Permission;
+import org.apache.hadoop.hbase.security.access.UserPermission;
+
+public class CompatPermissionUtil {
+
+    private CompatPermissionUtil() {
+        //Not to be instantiated
+    }
+
+    public static void stopAccessChecker(AccessChecker accessChecker) throws IOException {
+        accessChecker.stop();
+    }
+
+    public static String getUserFromUP(UserPermission userPermission) {
+        return userPermission.getUser();
+    }
+
+    public static Permission getPermissionFromUP(UserPermission userPermission) {
+        return userPermission.getPermission();
+    }
+
+    public static boolean authorizeUserTable(AccessChecker accessChecker, User user,
+            TableName table, Permission.Action action) {
+        // This also checks for group access
+        return accessChecker.getAuthManager().authorizeUserTable(user, table, action);
+    }
+
+}
diff --git a/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPhoenixRpcScheduler.java b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPhoenixRpcScheduler.java
new file mode 100644
index 0000000..059a39e
--- /dev/null
+++ b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/CompatPhoenixRpcScheduler.java
@@ -0,0 +1,47 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import org.apache.hadoop.hbase.ipc.RpcScheduler;
+
+/**
+ * {@link RpcScheduler} that first checks to see if this is an index or metedata update before
+ * passing off the call to the delegate {@link RpcScheduler}.
+ */
+public abstract class CompatPhoenixRpcScheduler extends RpcScheduler {
+    protected RpcScheduler delegate;
+
+    @Override
+    public int getMetaPriorityQueueLength() {
+        return this.delegate.getMetaPriorityQueueLength();
+    }
+
+    @Override
+    public int getActiveGeneralRpcHandlerCount() {
+        return this.delegate.getActiveGeneralRpcHandlerCount();
+    }
+
+    @Override
+    public int getActivePriorityRpcHandlerCount() {
+        return this.delegate.getActivePriorityRpcHandlerCount();
+    }
+
+    @Override
+    public int getActiveMetaPriorityRpcHandlerCount() {
+        return this.delegate.getActiveMetaPriorityRpcHandlerCount();
+    }
+
+    @Override
+    public int getActiveReplicationRpcHandlerCount() {
+        return this.delegate.getActiveReplicationRpcHandlerCount();
+    }
+
+}
diff --git a/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/CompatUtil.java b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/CompatUtil.java
new file mode 100644
index 0000000..4a9090c
--- /dev/null
+++ b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/CompatUtil.java
@@ -0,0 +1,42 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.MetaTableAccessor;
+import org.apache.hadoop.hbase.client.Connection;
+import org.apache.hadoop.hbase.client.RegionInfo;
+
+public class CompatUtil {
+
+    private CompatUtil() {
+        //Not to be instantiated
+    }
+
+    public static List<RegionInfo> getMergeRegions(Connection conn, byte[] regionName)
+            throws IOException {
+        return MetaTableAccessor.getMergeRegions(conn, regionName);
+    }
+
+    public static int getCellSerializedSize(Cell cell) {
+        return cell.getSerializedSize();
+    }
+}
diff --git a/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/OffsetCell.java b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/OffsetCell.java
new file mode 100644
index 0000000..c5485a5
--- /dev/null
+++ b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/OffsetCell.java
@@ -0,0 +1,136 @@
+/*
+ * 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.phoenix.compat.hbase;
+
+import org.apache.hadoop.hbase.Cell;
+
+public class OffsetCell implements Cell {
+
+    private Cell cell;
+    private int offset;
+
+    public OffsetCell(Cell cell, int offset) {
+        this.cell = cell;
+        this.offset = offset;
+    }
+
+    @Override
+    public byte[] getRowArray() {
+        return cell.getRowArray();
+    }
+
+    @Override
+    public int getRowOffset() {
+        return cell.getRowOffset() + offset;
+    }
+
+    @Override
+    public short getRowLength() {
+        return (short) (cell.getRowLength() - offset);
+    }
+
+    @Override
+    public byte[] getFamilyArray() {
+        return cell.getFamilyArray();
+    }
+
+    @Override
+    public int getFamilyOffset() {
+        return cell.getFamilyOffset();
+    }
+
+    @Override
+    public byte getFamilyLength() {
+        return cell.getFamilyLength();
+    }
+
+    @Override
+    public byte[] getQualifierArray() {
+        return cell.getQualifierArray();
+    }
+
+    @Override
+    public int getQualifierOffset() {
+        return cell.getQualifierOffset();
+    }
+
+    @Override
+    public int getQualifierLength() {
+        return cell.getQualifierLength();
+    }
+
+    @Override
+    public long getTimestamp() {
+        return cell.getTimestamp();
+    }
+
+    @Override
+    public byte getTypeByte() {
+        return cell.getTypeByte();
+    }
+
+    @Override public long getSequenceId() {
+        return cell.getSequenceId();
+    }
+
+    @Override
+    public byte[] getValueArray() {
+        return cell.getValueArray();
+    }
+
+    @Override
+    public int getValueOffset() {
+        return cell.getValueOffset();
+    }
+
+    @Override
+    public int getValueLength() {
+        return cell.getValueLength();
+    }
+
+    @Override
+    public byte[] getTagsArray() {
+        return cell.getTagsArray();
+    }
+
+    @Override
+    public int getTagsOffset() {
+        return cell.getTagsOffset();
+    }
+
+    @Override
+    public int getTagsLength() {
+        return cell.getTagsLength();
+    }
+
+    @Override
+    public Type getType() {
+        return cell.getType();
+    }
+
+    @Override
+    public long heapSize() {
+        return cell.heapSize();
+    }
+
+    @Override
+    public int getSerializedSize() {
+        return cell.getSerializedSize() - offset;
+    }
+
+}
diff --git a/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/test/DelegateCell.java b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/test/DelegateCell.java
new file mode 100644
index 0000000..0c7dfd8
--- /dev/null
+++ b/phoenix-hbase-compat-2.2.1/src/main/java/org/apache/phoenix/compat/hbase/test/DelegateCell.java
@@ -0,0 +1,139 @@
+/*
+ * 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.phoenix.compat.hbase.test;
+
+import org.apache.hadoop.hbase.Cell;
+
+public class DelegateCell implements Cell {
+    private final Cell delegate;
+    private final String name;
+    public DelegateCell(Cell delegate, String name) {
+        this.delegate = delegate;
+        this.name = name;
+    }
+
+    @Override
+    public int getValueOffset() {
+        return delegate.getValueOffset();
+    }
+
+    @Override
+    public int getValueLength() {
+        return delegate.getValueLength();
+    }
+
+    @Override
+    public byte[] getValueArray() {
+        return delegate.getValueArray();
+    }
+
+    @Override
+    public byte getTypeByte() {
+        return delegate.getTypeByte();
+    }
+
+    @Override
+    public long getTimestamp() {
+        return delegate.getTimestamp();
+    }
+
+    @Override
+    public int getTagsOffset() {
+        return delegate.getTagsOffset();
+    }
+
+    @Override
+    public byte[] getTagsArray() {
+        return delegate.getTagsArray();
+    }
+
+    @Override
+    public int getRowOffset() {
+        return delegate.getRowOffset();
+    }
+
+    @Override
+    public short getRowLength() {
+        return delegate.getRowLength();
+    }
+
+    @Override
+    public byte[] getRowArray() {
+        return delegate.getRowArray();
+    }
+
+    @Override
+    public int getQualifierOffset() {
+        return delegate.getQualifierOffset();
+    }
+
+    @Override
+    public int getQualifierLength() {
+        return delegate.getQualifierLength();
+    }
+
+    @Override
+    public byte[] getQualifierArray() {
+        return delegate.getQualifierArray();
+    }
+
+    @Override
+    public int getFamilyOffset() {
+        return delegate.getFamilyOffset();
+    }
+
+    @Override
+    public byte getFamilyLength() {
+        return delegate.getFamilyLength();
+    }
+
+    @Override
+    public byte[] getFamilyArray() {
+        return delegate.getFamilyArray();
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    @Override
+    public long getSequenceId() {
+        return delegate.getSequenceId();
+    }
+
+    @Override
+    public int getTagsLength() {
+        return delegate.getTagsLength();
+    }
+
+    @Override
+    public Type getType() {
+        return delegate.getType();
+    }
+
+    @Override
+    public long heapSize() {
+        return delegate.heapSize();
+    }
+
+    @Override
+    public int getSerializedSize() {
+        return delegate.getSerializedSize();
+    }
+}
diff --git a/phoenix-pherf/pom.xml b/phoenix-pherf/pom.xml
index 31bd638..b16db35 100644
--- a/phoenix-pherf/pom.xml
+++ b/phoenix-pherf/pom.xml
@@ -21,7 +21,7 @@
 	<parent>
 		<groupId>org.apache.phoenix</groupId>
 		<artifactId>phoenix</artifactId>
-		<version>5.1.0-HBase-2.0-SNAPSHOT</version>
+		<version>5.1.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>phoenix-pherf</artifactId>
diff --git a/phoenix-server/pom.xml b/phoenix-server/pom.xml
index d2a1648..b9395b5 100644
--- a/phoenix-server/pom.xml
+++ b/phoenix-server/pom.xml
@@ -24,7 +24,7 @@
   <parent>
     <groupId>org.apache.phoenix</groupId>
     <artifactId>phoenix</artifactId>
-    <version>5.1.0-HBase-2.0-SNAPSHOT</version>
+    <version>5.1.0-SNAPSHOT</version>
   </parent>
   <artifactId>phoenix-server</artifactId>
   <name>Phoenix Server</name>
@@ -94,7 +94,9 @@
               <goal>shade</goal>
             </goals>
             <configuration>
-                <finalName>phoenix-${project.version}-server</finalName>
+                <finalName>
+                  phoenix-${project.version}-${hbase.profile.string}-server
+                </finalName>
                 <shadedArtifactAttached>false</shadedArtifactAttached>
                 <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
                 <shadeTestJar>false</shadeTestJar>
diff --git a/phoenix-tracing-webapp/pom.xml b/phoenix-tracing-webapp/pom.xml
index 2f79c23..814bbb1 100755
--- a/phoenix-tracing-webapp/pom.xml
+++ b/phoenix-tracing-webapp/pom.xml
@@ -22,7 +22,7 @@
     <parent>
       <groupId>org.apache.phoenix</groupId>
       <artifactId>phoenix</artifactId>
-      <version>5.1.0-HBase-2.0-SNAPSHOT</version>
+      <version>5.1.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>phoenix-tracing-webapp</artifactId>
diff --git a/pom.xml b/pom.xml
index 6da9dc8..bc73823 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.phoenix</groupId>
   <artifactId>phoenix</artifactId>
-  <version>5.1.0-HBase-2.0-SNAPSHOT</version>
+  <version>5.1.0-SNAPSHOT</version>
   <packaging>pom</packaging>
   <name>Apache Phoenix</name>
   <description>A SQL layer over HBase</description>
@@ -40,6 +40,9 @@
   </organization>
 
   <modules>
+    <module>phoenix-hbase-compat-2.2.1</module>
+    <module>phoenix-hbase-compat-2.1.6</module>
+    <module>phoenix-hbase-compat-2.0.1</module>
     <module>phoenix-core</module>
     <module>phoenix-pherf</module>
     <module>phoenix-client</module>
@@ -68,16 +71,20 @@
   </scm>
 
   <properties>
+    <!-- The HBase compatibility module that that will be included in
+    the shaded JARs and the assembly -->
+    <hbase.profile>2.0</hbase.profile>
+    <hbase.profile.string>hbase-${hbase.profile}</hbase.profile.string>
+
+    <!-- Hadoop Version -->
+    <hadoop.version>3.0.0</hadoop.version>
+
     <!-- General Properties -->
     <antlr-input.dir>src/main/antlr3</antlr-input.dir>
     <antlr-output.dir>target/generated-sources/antlr3</antlr-output.dir>
     <test.output.tofile>true</test.output.tofile>
     <top.dir>${project.basedir}</top.dir>
 
-    <!-- Hadoop Versions -->
-    <hbase.version>2.0.1</hbase.version>
-    <hadoop.version>3.0.0</hadoop.version>
-
     <!-- Dependency versions -->
     <commons-cli.version>1.4</commons-cli.version>
     <jackson.version>1.9.2</jackson.version>
@@ -115,6 +122,7 @@
     <!-- Plugin versions -->
     <maven-eclipse-plugin.version>2.9</maven-eclipse-plugin.version>
     <maven-build-helper-plugin.version>1.9.1</maven-build-helper-plugin.version>
+    <maven-enforcer-plugin.version>3.0.0-M3</maven-enforcer-plugin.version>
 
     <!-- Plugin options -->
     <numForkedUT>8</numForkedUT>
@@ -134,6 +142,11 @@
       <plugins>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-enforcer-plugin</artifactId>
+          <version>${maven-enforcer-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <configuration>
             <source>1.8</source>
@@ -369,6 +382,54 @@
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-enforcer-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>check-hbase-compatibility</id>
+            <phase>validate</phase>
+            <goals>
+              <goal>enforce</goal>
+            </goals>
+            <configuration>
+              <rules>
+                <evaluateBeanshell>
+                 <condition>
+                   import java.util.regex.Pattern;
+                   import java.lang.Integer;
+
+                   versionPattern = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)[^.]*$");
+                   versionMatcher = versionPattern.matcher("${hbase.version}");
+                   versionMatcher.find();
+
+                   hbaseMajor = Integer.parseInt(versionMatcher.group(1));
+                   hbaseMinor = Integer.parseInt(versionMatcher.group(2));
+                   hbasePatch = Integer.parseInt(versionMatcher.group(3));
+
+                   hbaseMajor == 2 &amp;&amp; (
+                     ("${hbase.compat.version}".equals("2.0.1")
+                       &amp;&amp; hbaseMinor == 0
+                       &amp;&amp; hbasePatch &gt;=1
+                       &amp;&amp; hbasePatch &lt;=4)
+                     || ("${hbase.compat.version}".equals("2.0.1")
+                       &amp;&amp; hbaseMinor == 1
+                       &amp;&amp; hbasePatch &gt;=1
+                       &amp;&amp; hbasePatch &lt;=2)
+                     || ("${hbase.compat.version}".equals("2.1.6")
+                       &amp;&amp; hbaseMinor == 1
+                       &amp;&amp; hbasePatch &gt;=6)
+                     || ("${hbase.compat.version}".equals("2.2.1")
+                       &amp;&amp; hbaseMinor == 2
+                       &amp;&amp; hbasePatch &gt;=1)
+                   )
+                   </condition>
+                  </evaluateBeanshell>
+                </rules>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
         <version>3.1.0</version>
         <executions>
@@ -511,7 +572,21 @@
         <type>test-jar</type>
         <scope>test</scope>
       </dependency>
-
+      <dependency>
+        <groupId>org.apache.phoenix</groupId>
+        <artifactId>phoenix-hbase-compat-2.0.1</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.phoenix</groupId>
+        <artifactId>phoenix-hbase-compat-2.1.6</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.phoenix</groupId>
+        <artifactId>phoenix-hbase-compat-2.2.1</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <!-- HBase dependencies -->
       <dependency>
         <groupId>org.apache.hbase</groupId>
@@ -589,6 +664,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.hbase</groupId>
+        <artifactId>hbase-endpoint</artifactId>
+        <version>${hbase.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.hbase</groupId>
         <artifactId>hbase-server</artifactId>
         <version>${hbase.version}</version>
       </dependency>
@@ -1031,6 +1111,92 @@
         </plugins>
       </build>
     </profile>
+    <!-- See BUILDING.md for profile selection-->
+    <!-- 2.0 support should probably be removed for the 5.1 release -->
+    <profile>
+      <id>phoenix-hbase-compat-2.0.1-default</id>
+      <activation>
+        <property>
+          <name>!hbase.profile</name>
+        </property>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.phoenix</groupId>
+          <artifactId>phoenix-hbase-compat-2.0.1</artifactId>
+        </dependency>
+      </dependencies>
+      <properties>
+        <hbase.profile>2.0</hbase.profile>
+        <hbase.compat.version>2.0.1</hbase.compat.version>
+        <!-- this is currently set to 2.0.1 to match the non-modular version -->
+        <hbase.version>2.0.1</hbase.version>
+      </properties>
+    </profile>
+    <profile>
+      <id>phoenix-hbase-compat-2.0.1</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+        <property>
+          <name>hbase.profile</name>
+          <value>2.0</value>
+        </property>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.phoenix</groupId>
+          <artifactId>phoenix-hbase-compat-2.0.1</artifactId>
+        </dependency>
+      </dependencies>
+      <properties>
+        <hbase.profile>2.0</hbase.profile>
+        <hbase.compat.version>2.0.1</hbase.compat.version>
+        <hbase.version>2.0.4</hbase.version>
+      </properties>
+    </profile>
+    <profile>
+      <id>phoenix-hbase-compat-2.1.6</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+        <property>
+          <name>hbase.profile</name>
+          <value>2.1</value>
+        </property>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.phoenix</groupId>
+          <artifactId>phoenix-hbase-compat-2.1.6</artifactId>
+        </dependency>
+      </dependencies>
+      <properties>
+        <hbase.profile>2.1</hbase.profile>
+        <hbase.compat.version>2.1.6</hbase.compat.version>
+        <!-- Update to latest before release -->
+        <hbase.version>2.1.8</hbase.version>
+      </properties>
+    </profile>
+    <profile>
+      <id>phoenix-hbase-compat-2.2.1</id>
+      <activation>
+        <property>
+          <name>hbase.profile</name>
+          <value>2.2</value>
+        </property>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.phoenix</groupId>
+          <artifactId>phoenix-hbase-compat-2.2.1</artifactId>
+        </dependency>
+      </dependencies>
+      <properties>
+        <hbase.profile>2.2</hbase.profile>
+        <hbase.compat.version>2.2.1</hbase.compat.version>
+        <!-- Update to latest before release -->
+        <hbase.version>2.2.3</hbase.version>
+      </properties>
+    </profile>
   </profiles>
 
   <reporting>