You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by st...@apache.org on 2019/12/20 06:08:00 UTC

[phoenix-queryserver] branch master updated: PHOENIX-5641 Decouple phoenix-queryserver from phoenix-core

This is an automated email from the ASF dual-hosted git repository.

stoty pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/phoenix-queryserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 960289a  PHOENIX-5641 Decouple phoenix-queryserver from phoenix-core
960289a is described below

commit 960289a6ec6afd263d0e2faaf9ac1c585ce4d587
Author: Istvan Toth <st...@stoty.hu>
AuthorDate: Thu Dec 19 08:13:54 2019 +0100

    PHOENIX-5641 Decouple phoenix-queryserver from phoenix-core
---
 .../service/LoadBalanceZookeeperConfImpl.java      |  24 ++---
 pom.xml                                            | 112 +++++++++++----------
 .../phoenix/queryserver/client/ThinClientUtil.java |   2 +-
 queryserver-orchestrator/pom.xml                   |   5 +-
 queryserver/pom.xml                                |  17 ++--
 .../HttpParamImpersonationQueryServerIT.java       |   8 +-
 .../phoenix/end2end/QueryServerBasicsIT.java       |   3 +-
 .../end2end/SecureQueryServerPhoenixDBIT.java      |   5 +-
 .../phoenix/end2end/ServerCustomizersIT.java       |   3 +-
 .../phoenix/queryserver/QueryServerOptions.java    | 110 ++++++++++++++++++++
 .../phoenix/queryserver/QueryServerProperties.java |  79 +++++++++++++++
 .../queryserver/server/PhoenixMetaFactoryImpl.java |  83 ++++++++++++---
 .../phoenix/queryserver/server/QueryServer.java    |  90 ++++++++---------
 .../org/apache/phoenix/util/InstanceResolver.java  |  95 +++++++++++++++++
 14 files changed, 495 insertions(+), 141 deletions(-)

diff --git a/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java
index 98e2682..807295b 100644
--- a/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java
+++ b/load-balancer/src/main/java/org/apache/phoenix/loadbalancer/service/LoadBalanceZookeeperConfImpl.java
@@ -23,8 +23,8 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.net.HostAndPort;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseConfiguration;
-import org.apache.phoenix.query.QueryServices;
-import org.apache.phoenix.query.QueryServicesOptions;
+import org.apache.phoenix.queryserver.QueryServerOptions;
+import org.apache.phoenix.queryserver.QueryServerProperties;
 import org.apache.zookeeper.ZooDefs;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Id;
@@ -53,30 +53,30 @@ public class LoadBalanceZookeeperConfImpl implements LoadBalanceZookeeperConf {
 
         @Override
         public String getQueryServerBasePath(){
-            return configuration.get(QueryServices.PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH,
-                    QueryServicesOptions.DEFAULT_PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH);
+            return configuration.get(QueryServerProperties.PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH,
+                    QueryServerOptions.DEFAULT_PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH);
         }
 
         @Override
         public String getServiceName(){
-            return configuration.get(QueryServices.PHOENIX_QUERY_SERVER_SERVICE_NAME,
-                    QueryServicesOptions.DEFAULT_PHOENIX_QUERY_SERVER_SERVICE_NAME);
+            return configuration.get(QueryServerProperties.PHOENIX_QUERY_SERVER_SERVICE_NAME,
+                    QueryServerOptions.DEFAULT_PHOENIX_QUERY_SERVER_SERVICE_NAME);
         }
 
         @Override
         public String getZkConnectString(){
-            return String.format("%s:%s",configuration.get(QueryServices.ZOOKEEPER_QUORUM_ATTRIB,
-                    "localhost"),configuration.get(QueryServices.ZOOKEEPER_PORT_ATTRIB,"2181"));
+            return String.format("%s:%s",configuration.get(QueryServerProperties.ZOOKEEPER_QUORUM_ATTRIB,
+                    "localhost"),configuration.get(QueryServerProperties.ZOOKEEPER_PORT_ATTRIB,"2181"));
         }
 
         private String getZkLbUserName(){
-            return configuration.get(QueryServices.PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME,
-                    QueryServicesOptions.DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME);
+            return configuration.get(QueryServerProperties.PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME,
+                    QueryServerOptions.DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME);
         }
 
         private String getZkLbPassword(){
-            return configuration.get(QueryServices.PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD,
-                    QueryServicesOptions.DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD);
+            return configuration.get(QueryServerProperties.PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD,
+                    QueryServerOptions.DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD);
         }
 
         @Override
diff --git a/pom.xml b/pom.xml
index 21b6aec..cd3c003 100644
--- a/pom.xml
+++ b/pom.xml
@@ -313,18 +313,6 @@
             <!-- Intra-project dependencies -->
             <dependency>
                 <groupId>org.apache.phoenix</groupId>
-                <artifactId>phoenix-core</artifactId>
-                <version>${phoenix.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.phoenix</groupId>
-                <artifactId>phoenix-core</artifactId>
-                <version>${phoenix.version}</version>
-                <classifier>tests</classifier>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.phoenix</groupId>
                 <artifactId>queryserver</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -391,35 +379,6 @@
                 <scope>test</scope>
             </dependency>
 
-            <!-- Required for mini-cluster since hbase built against old version of hadoop -->
-            <dependency>
-                <groupId>org.apache.hadoop</groupId>
-                <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
-                <version>${hadoop-two.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.hadoop</groupId>
-                <artifactId>hadoop-client</artifactId>
-                <version>${hadoop-two.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.hadoop</groupId>
-                <artifactId>hadoop-hdfs</artifactId>
-                <version>${hadoop-two.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.hadoop</groupId>
-                <artifactId>hadoop-hdfs</artifactId>
-                <version>${hadoop-two.version}</version>
-                <type>test-jar</type> <!-- this does not work which is typical for maven.-->
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.hadoop</groupId>
-                <artifactId>hadoop-minikdc</artifactId>
-                <version>${hadoop-two.version}</version>
-            </dependency>
-
             <!-- General Dependencies -->
             <dependency>
                 <groupId>org.apache.curator</groupId>
@@ -469,22 +428,11 @@
                 <version>${sqlline.version}</version>
             </dependency>
             <dependency>
-                <groupId>junit</groupId>
-                <artifactId>junit</artifactId>
-                <version>${junit.version}</version>
-            </dependency>
-            <dependency>
                 <groupId>commons-logging</groupId>
                 <artifactId>commons-logging</artifactId>
                 <version>${commons-logging.version}</version>
             </dependency>
             <dependency>
-                <groupId>org.mockito</groupId>
-                <artifactId>mockito-all</artifactId>
-                <version>${mockito-all.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
                 <groupId>javax.servlet</groupId>
                 <artifactId>javax.servlet-api</artifactId>
                 <version>${servlet.api.version}</version>
@@ -499,6 +447,66 @@
                 <artifactId>argparse4j</artifactId>
                 <version>0.8.1</version>
             </dependency>
+
+            <!-- Test dependencies -->
+            <dependency>
+                <groupId>org.apache.phoenix</groupId>
+                <artifactId>phoenix-core</artifactId>
+                <version>${phoenix.version}</version>
+                <classifier>tests</classifier>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.phoenix</groupId>
+                <artifactId>phoenix-core</artifactId>
+                <version>${phoenix.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <version>${junit.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.mockito</groupId>
+                <artifactId>mockito-all</artifactId>
+                <version>${mockito-all.version}</version>
+                <scope>test</scope>
+            </dependency>
+
+            <!-- Required for mini-cluster since hbase built against old version of hadoop -->
+            <dependency>
+                <groupId>org.apache.hadoop</groupId>
+                <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
+                <version>${hadoop-two.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.hadoop</groupId>
+                <artifactId>hadoop-client</artifactId>
+                <version>${hadoop-two.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.hadoop</groupId>
+                <artifactId>hadoop-hdfs</artifactId>
+                <version>${hadoop-two.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.hadoop</groupId>
+                <artifactId>hadoop-hdfs</artifactId>
+                <version>${hadoop-two.version}</version>
+                <type>test-jar</type> <!-- this does not work which is typical for maven.-->
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.hadoop</groupId>
+                <artifactId>hadoop-minikdc</artifactId>
+                <version>${hadoop-two.version}</version>
+                <scope>test</scope>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 
diff --git a/queryserver-client/src/main/java/org/apache/phoenix/queryserver/client/ThinClientUtil.java b/queryserver-client/src/main/java/org/apache/phoenix/queryserver/client/ThinClientUtil.java
index 59fe093..1ea64e7 100644
--- a/queryserver-client/src/main/java/org/apache/phoenix/queryserver/client/ThinClientUtil.java
+++ b/queryserver-client/src/main/java/org/apache/phoenix/queryserver/client/ThinClientUtil.java
@@ -21,7 +21,7 @@ package org.apache.phoenix.queryserver.client;
  * Utilities for thin clients.
  */
 public final class ThinClientUtil {
-  // The default serialization is also defined in QueryServicesOptions. phoenix-queryserver-client
+  // The default serialization is also defined in QueryServerOptions. phoenix-queryserver-client
   // currently doesn't depend on phoenix-core so we have to deal with the duplication.
   private static final String DEFAULT_SERIALIZATION = "PROTOBUF";
 
diff --git a/queryserver-orchestrator/pom.xml b/queryserver-orchestrator/pom.xml
index 8efb324..12e559f 100644
--- a/queryserver-orchestrator/pom.xml
+++ b/queryserver-orchestrator/pom.xml
@@ -61,10 +61,7 @@
         <dependency>
             <groupId>org.apache.phoenix</groupId>
             <artifactId>phoenix-core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-all</artifactId>
+            <scope>compile</scope>
         </dependency>
     </dependencies>
 
diff --git a/queryserver/pom.xml b/queryserver/pom.xml
index dd8f758..d68d8e8 100644
--- a/queryserver/pom.xml
+++ b/queryserver/pom.xml
@@ -143,6 +143,10 @@
   </build>
 
   <dependencies>
+     <dependency>
+       <groupId>org.apache.hbase</groupId>
+       <artifactId>hbase-common</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.phoenix</groupId>
       <artifactId>queryserver-client</artifactId>
@@ -165,10 +169,6 @@
       <artifactId>avatica-server</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.phoenix</groupId>
-      <artifactId>phoenix-core</artifactId>
-    </dependency>
-    <dependency>
       <groupId>commons-logging</groupId>
       <artifactId>commons-logging</artifactId>
     </dependency>
@@ -178,14 +178,19 @@
     </dependency>
     <!-- for tests -->
     <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-all</artifactId>
+      <groupId>org.apache.phoenix</groupId>
+      <artifactId>phoenix-core</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.phoenix</groupId>
       <artifactId>phoenix-core</artifactId>
+      <scope>test</scope>
       <classifier>tests</classifier>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/queryserver/src/it/java/org/apache/phoenix/end2end/HttpParamImpersonationQueryServerIT.java b/queryserver/src/it/java/org/apache/phoenix/end2end/HttpParamImpersonationQueryServerIT.java
index e982a1e..e92a837 100644
--- a/queryserver/src/it/java/org/apache/phoenix/end2end/HttpParamImpersonationQueryServerIT.java
+++ b/queryserver/src/it/java/org/apache/phoenix/end2end/HttpParamImpersonationQueryServerIT.java
@@ -46,6 +46,8 @@ import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
 import org.apache.phoenix.query.QueryServices;
 import org.apache.phoenix.query.QueryServicesOptions;
+import org.apache.phoenix.queryserver.QueryServerOptions;
+import org.apache.phoenix.queryserver.QueryServerProperties;
 import org.apache.phoenix.queryserver.client.Driver;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -74,7 +76,7 @@ public class HttpParamImpersonationQueryServerIT extends AbstractKerberisedTest
         // user1 is allowed to impersonate others, user2 is not
         conf.set("hadoop.proxyuser.user1.groups", "*");
         conf.set("hadoop.proxyuser.user1.hosts", "*");
-        conf.setBoolean(QueryServices.QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB, true);
+        conf.setBoolean(QueryServerProperties.QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB, true);
 
         configureAndStartQueryServer(conf, 2);
     }
@@ -85,7 +87,7 @@ public class HttpParamImpersonationQueryServerIT extends AbstractKerberisedTest
         final Entry<String,File> user2 = getUser(2);
         // Build the JDBC URL by hand with the doAs
         final String doAsUrlTemplate = Driver.CONNECT_STRING_PREFIX + "url=http://localhost:" + PQS_PORT + "?"
-            + QueryServicesOptions.DEFAULT_QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM + "=%s;authentication=SPNEGO;serialization=PROTOBUF";
+            + QueryServerOptions.DEFAULT_QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM + "=%s;authentication=SPNEGO;serialization=PROTOBUF";
         final String tableName = "POSITIVE_IMPERSONATION";
         final int numRows = 5;
         final UserGroupInformation serviceUgi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(SERVICE_PRINCIPAL, KEYTAB.getAbsolutePath());
@@ -118,7 +120,7 @@ public class HttpParamImpersonationQueryServerIT extends AbstractKerberisedTest
         final Entry<String,File> user2 = getUser(2);
         // Build the JDBC URL by hand with the doAs
         final String doAsUrlTemplate = Driver.CONNECT_STRING_PREFIX + "url=http://localhost:" + PQS_PORT + "?"
-            + QueryServicesOptions.DEFAULT_QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM + "=%s;authentication=SPNEGO;serialization=PROTOBUF";
+            + QueryServerOptions.DEFAULT_QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM + "=%s;authentication=SPNEGO;serialization=PROTOBUF";
         final String tableName = "DISALLOWED_IMPERSONATION";
         final int numRows = 5;
         final UserGroupInformation serviceUgi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(SERVICE_PRINCIPAL, KEYTAB.getAbsolutePath());
diff --git a/queryserver/src/it/java/org/apache/phoenix/end2end/QueryServerBasicsIT.java b/queryserver/src/it/java/org/apache/phoenix/end2end/QueryServerBasicsIT.java
index ceb0a78..4ebec1b 100644
--- a/queryserver/src/it/java/org/apache/phoenix/end2end/QueryServerBasicsIT.java
+++ b/queryserver/src/it/java/org/apache/phoenix/end2end/QueryServerBasicsIT.java
@@ -43,6 +43,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.queryserver.QueryServerProperties;
 import org.apache.phoenix.queryserver.client.ThinClientUtil;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -67,7 +68,7 @@ public class QueryServerBasicsIT extends BaseHBaseManagedTimeIT {
   @BeforeClass
   public static void beforeClass() throws Exception {
     CONF = getTestClusterConfig();
-    CONF.setInt(QueryServices.QUERY_SERVER_HTTP_PORT_ATTRIB, 0);
+    CONF.setInt(QueryServerProperties.QUERY_SERVER_HTTP_PORT_ATTRIB, 0);
     String url = getUrl();
     AVATICA_SERVER = new QueryServerThread(new String[] { url }, CONF,
             QueryServerBasicsIT.class.getName());
diff --git a/queryserver/src/it/java/org/apache/phoenix/end2end/SecureQueryServerPhoenixDBIT.java b/queryserver/src/it/java/org/apache/phoenix/end2end/SecureQueryServerPhoenixDBIT.java
index 205a831..05f7f15 100644
--- a/queryserver/src/it/java/org/apache/phoenix/end2end/SecureQueryServerPhoenixDBIT.java
+++ b/queryserver/src/it/java/org/apache/phoenix/end2end/SecureQueryServerPhoenixDBIT.java
@@ -54,6 +54,7 @@ import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.authentication.util.KerberosName;
 import org.apache.phoenix.query.ConfigurationFactory;
 import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.queryserver.QueryServerProperties;
 import org.apache.phoenix.queryserver.client.ThinClientUtil;
 import org.apache.phoenix.queryserver.server.QueryServer;
 import org.apache.phoenix.util.InstanceResolver;
@@ -234,8 +235,8 @@ public class SecureQueryServerPhoenixDBIT {
         conf.set("phoenix.queryserver.http.keytab.file", KEYTAB.getAbsolutePath());
         conf.set("phoenix.queryserver.kerberos.principal", PQS_PRINCIPAL + "@" + KDC.getRealm());
         conf.set("phoenix.queryserver.keytab.file", KEYTAB.getAbsolutePath());
-        conf.setBoolean(QueryServices.QUERY_SERVER_DISABLE_KERBEROS_LOGIN, true);
-        conf.setInt(QueryServices.QUERY_SERVER_HTTP_PORT_ATTRIB, 0);
+        conf.setBoolean(QueryServerProperties.QUERY_SERVER_DISABLE_KERBEROS_LOGIN, true);
+        conf.setInt(QueryServerProperties.QUERY_SERVER_HTTP_PORT_ATTRIB, 0);
         // Required so that PQS can impersonate the end-users to HBase
         conf.set("hadoop.proxyuser.phoenixqs.groups", "*");
         conf.set("hadoop.proxyuser.phoenixqs.hosts", "*");
diff --git a/queryserver/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java b/queryserver/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java
index db08908..699000f 100644
--- a/queryserver/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java
+++ b/queryserver/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java
@@ -28,6 +28,7 @@ import org.apache.calcite.avatica.server.AvaticaServerConfiguration;
 import org.apache.calcite.avatica.server.ServerCustomizer;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.queryserver.QueryServerProperties;
 import org.apache.phoenix.queryserver.server.ServerCustomizersFactory;
 import org.apache.phoenix.util.InstanceResolver;
 import org.eclipse.jetty.security.ConstraintMapping;
@@ -60,7 +61,7 @@ public class ServerCustomizersIT extends BaseHBaseManagedTimeIT {
     @BeforeClass
     public static void setup() throws Exception {
         Configuration conf = getTestClusterConfig();
-        conf.set(QueryServices.QUERY_SERVER_CUSTOMIZERS_ENABLED, "true");
+        conf.set(QueryServerProperties.QUERY_SERVER_CUSTOMIZERS_ENABLED, "true");
         PQS_UTIL = new QueryServerTestUtil(conf);
         PQS_UTIL.startLocalHBaseCluster(ServerCustomizersIT.class);
         // Register a test jetty server customizer
diff --git a/queryserver/src/main/java/org/apache/phoenix/queryserver/QueryServerOptions.java b/queryserver/src/main/java/org/apache/phoenix/queryserver/QueryServerOptions.java
new file mode 100644
index 0000000..33f7771
--- /dev/null
+++ b/queryserver/src/main/java/org/apache/phoenix/queryserver/QueryServerOptions.java
@@ -0,0 +1,110 @@
+/*
+ * 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.queryserver;
+
+import static org.apache.phoenix.queryserver.QueryServerProperties.PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH;
+import static org.apache.phoenix.queryserver.QueryServerProperties.PHOENIX_QUERY_SERVER_LOADBALANCER_ENABLED;
+import static org.apache.phoenix.queryserver.QueryServerProperties.PHOENIX_QUERY_SERVER_SERVICE_NAME;
+import static org.apache.phoenix.queryserver.QueryServerProperties.PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD;
+import static org.apache.phoenix.queryserver.QueryServerProperties.PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+
+public class QueryServerOptions {
+
+    // QueryServer defaults -- ensure ThinClientUtil is also updated since
+    // phoenix-queryserver-client
+    // doesn't depend on phoenix-core.
+    public static final String DEFAULT_QUERY_SERVER_SERIALIZATION = "PROTOBUF";
+    public static final int DEFAULT_QUERY_SERVER_HTTP_PORT = 8765;
+    public static final long DEFAULT_QUERY_SERVER_UGI_CACHE_MAX_SIZE = 1000L;
+    public static final int DEFAULT_QUERY_SERVER_UGI_CACHE_INITIAL_SIZE = 100;
+    public static final int DEFAULT_QUERY_SERVER_UGI_CACHE_CONCURRENCY = 10;
+    public static final boolean DEFAULT_QUERY_SERVER_SPNEGO_AUTH_DISABLED = false;
+    public static final boolean DEFAULT_QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR = false;
+    public static final boolean DEFAULT_QUERY_SERVER_CUSTOM_AUTH_ENABLED = false;
+    public static final String DEFAULT_QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM = "doAs";
+    public static final boolean DEFAULT_QUERY_SERVER_DISABLE_KERBEROS_LOGIN = false;
+    public static final boolean DEFAULT_QUERY_SERVER_CUSTOMIZERS_ENABLED = false;
+
+    @SuppressWarnings("serial")
+    public static final Set<String> DEFAULT_QUERY_SERVER_SKIP_WORDS = new HashSet<String>() {
+        {
+            add("secret");
+            add("passwd");
+            add("password");
+            add("credential");
+        }
+    };
+
+    // Loadbalancer defaults
+    public static final boolean DEFAULT_PHOENIX_QUERY_SERVER_LOADBALANCER_ENABLED = false;
+    public static final String DEFAULT_PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH = "/phoenix";
+    public static final String DEFAULT_PHOENIX_QUERY_SERVER_SERVICE_NAME = "queryserver";
+    public static final String DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME = "phoenix";
+    public static final String DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD = "phoenix";
+
+    // Common defaults
+    public static final String DEFAULT_EXTRA_JDBC_ARGUMENTS = "";
+
+    private final Configuration config;
+
+    private QueryServerOptions(Configuration config) {
+        this.config = config;
+    }
+
+    public static QueryServerOptions withDefaults() {
+        Configuration config = HBaseConfiguration.create();
+        QueryServerOptions options =
+                new QueryServerOptions(config)
+                        .setIfUnset(PHOENIX_QUERY_SERVER_LOADBALANCER_ENABLED,
+                            DEFAULT_PHOENIX_QUERY_SERVER_LOADBALANCER_ENABLED)
+                        .setIfUnset(PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH,
+                            DEFAULT_PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH)
+                        .setIfUnset(PHOENIX_QUERY_SERVER_SERVICE_NAME,
+                            DEFAULT_PHOENIX_QUERY_SERVER_SERVICE_NAME)
+                        .setIfUnset(PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME,
+                            DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME)
+                        .setIfUnset(PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD,
+                            DEFAULT_PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD);
+
+        return options;
+    }
+
+    public Configuration getConfiguration() {
+        return config;
+    }
+
+    private QueryServerOptions setIfUnset(String name, int value) {
+        config.setIfUnset(name, Integer.toString(value));
+        return this;
+    }
+
+    private QueryServerOptions setIfUnset(String name, boolean value) {
+        config.setIfUnset(name, Boolean.toString(value));
+        return this;
+    }
+
+    private QueryServerOptions setIfUnset(String name, long value) {
+        config.setIfUnset(name, Long.toString(value));
+        return this;
+    }
+
+    private QueryServerOptions setIfUnset(String name, String value) {
+        config.setIfUnset(name, value);
+        return this;
+    }
+
+}
diff --git a/queryserver/src/main/java/org/apache/phoenix/queryserver/QueryServerProperties.java b/queryserver/src/main/java/org/apache/phoenix/queryserver/QueryServerProperties.java
new file mode 100644
index 0000000..aa081f6
--- /dev/null
+++ b/queryserver/src/main/java/org/apache/phoenix/queryserver/QueryServerProperties.java
@@ -0,0 +1,79 @@
+/*
+ * 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.queryserver;
+
+public class QueryServerProperties {
+
+    // queryserver configuration keys
+    public static final String QUERY_SERVER_SERIALIZATION_ATTRIB =
+            "phoenix.queryserver.serialization";
+    public static final String QUERY_SERVER_META_FACTORY_ATTRIB =
+            "phoenix.queryserver.metafactory.class";
+    public static final String QUERY_SERVER_HTTP_PORT_ATTRIB = "phoenix.queryserver.http.port";
+    public static final String QUERY_SERVER_ENV_LOGGING_ATTRIB =
+            "phoenix.queryserver.envvars.logging.disabled";
+    public static final String QUERY_SERVER_ENV_LOGGING_SKIPWORDS_ATTRIB =
+            "phoenix.queryserver.envvars.logging.skipwords";
+    public static final String QUERY_SERVER_KEYTAB_FILENAME_ATTRIB =
+            "phoenix.queryserver.keytab.file";
+    public static final String QUERY_SERVER_HTTP_KEYTAB_FILENAME_ATTRIB =
+            "phoenix.queryserver.http.keytab.file";
+    public static final String QUERY_SERVER_KERBEROS_PRINCIPAL_ATTRIB =
+            "phoenix.queryserver.kerberos.principal";
+    public static final String QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB_LEGACY =
+            "phoenix.queryserver.kerberos.http.principal";
+    public static final String QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB =
+            "phoenix.queryserver.http.kerberos.principal";
+    public static final String QUERY_SERVER_DNS_NAMESERVER_ATTRIB =
+            "phoenix.queryserver.dns.nameserver";
+    public static final String QUERY_SERVER_DNS_INTERFACE_ATTRIB =
+            "phoenix.queryserver.dns.interface";
+    public static final String QUERY_SERVER_HBASE_SECURITY_CONF_ATTRIB =
+            "hbase.security.authentication";
+    public static final String QUERY_SERVER_UGI_CACHE_MAX_SIZE =
+            "phoenix.queryserver.ugi.cache.max.size";
+    public static final String QUERY_SERVER_UGI_CACHE_INITIAL_SIZE =
+            "phoenix.queryserver.ugi.cache.initial.size";
+    public static final String QUERY_SERVER_UGI_CACHE_CONCURRENCY =
+            "phoenix.queryserver.ugi.cache.concurrency";
+    public static final String QUERY_SERVER_KERBEROS_ALLOWED_REALMS =
+            "phoenix.queryserver.kerberos.allowed.realms";
+    public static final String QUERY_SERVER_SPNEGO_AUTH_DISABLED_ATTRIB =
+            "phoenix.queryserver.spnego.auth.disabled";
+    public static final String QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB =
+            "phoenix.queryserver.withRemoteUserExtractor";
+    public static final String QUERY_SERVER_CUSTOMIZERS_ENABLED =
+            "phoenix.queryserver.customizers.enabled";
+    public static final String QUERY_SERVER_CUSTOM_AUTH_ENABLED =
+            "phoenix.queryserver.custom.auth.enabled";
+    public static final String QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM =
+            "phoenix.queryserver.remoteUserExtractor.param";
+    public static final String QUERY_SERVER_DISABLE_KERBEROS_LOGIN =
+            "phoenix.queryserver.disable.kerberos.login";
+
+    // keys for load balancer
+    public static final String PHOENIX_QUERY_SERVER_LOADBALANCER_ENABLED =
+            "phoenix.queryserver.loadbalancer.enabled";
+    public static final String PHOENIX_QUERY_SERVER_CLUSTER_BASE_PATH =
+            "phoenix.queryserver.base.path";
+    public static final String PHOENIX_QUERY_SERVER_SERVICE_NAME =
+            "phoenix.queryserver.service.name";
+    public static final String PHOENIX_QUERY_SERVER_ZK_ACL_USERNAME =
+            "phoenix.queryserver.zookeeper.acl.username";
+    public static final String PHOENIX_QUERY_SERVER_ZK_ACL_PASSWORD =
+            "phoenix.queryserver.zookeeper.acl.password";
+
+    // keys that are also used by phoenix-core
+    public static final String ZOOKEEPER_QUORUM_ATTRIB = "hbase.zookeeper.quorum";
+    public static final String ZOOKEEPER_PORT_ATTRIB = "hbase.zookeeper.property.clientPort";
+    public static final String EXTRA_JDBC_ARGUMENTS_ATTRIB = "phoenix.jdbc.extra.arguments";
+
+}
diff --git a/queryserver/src/main/java/org/apache/phoenix/queryserver/server/PhoenixMetaFactoryImpl.java b/queryserver/src/main/java/org/apache/phoenix/queryserver/server/PhoenixMetaFactoryImpl.java
index c74d2c9..88c577f 100644
--- a/queryserver/src/main/java/org/apache/phoenix/queryserver/server/PhoenixMetaFactoryImpl.java
+++ b/queryserver/src/main/java/org/apache/phoenix/queryserver/server/PhoenixMetaFactoryImpl.java
@@ -17,31 +17,28 @@
  */
 package org.apache.phoenix.queryserver.server;
 
-import com.google.common.base.Preconditions;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.jdbc.JdbcMeta;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.conf.Configured;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HConstants;
-import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.mapreduce.util.PhoenixConfigurationUtil;
-import org.apache.phoenix.util.QueryUtil;
+import org.apache.phoenix.queryserver.QueryServerOptions;
+import org.apache.phoenix.queryserver.QueryServerProperties;
 
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
+import com.google.common.base.Preconditions;
 
 /**
  * Bridge between Phoenix and Avatica.
  */
 public class PhoenixMetaFactoryImpl extends Configured implements PhoenixMetaFactory {
 
+
   // invoked via reflection
   public PhoenixMetaFactoryImpl() {
     super(HBaseConfiguration.create());
@@ -60,7 +57,7 @@ public class PhoenixMetaFactoryImpl extends Configured implements PhoenixMetaFac
     try {
       final String url;
       if (args.size() == 0) {
-        url = QueryUtil.getConnectionUrl(info, conf);
+        url = getConnectionUrl(info, conf);
       } else if (args.size() == 1) {
         url = args.get(0);
       } else {
@@ -73,4 +70,64 @@ public class PhoenixMetaFactoryImpl extends Configured implements PhoenixMetaFac
       throw new RuntimeException(e);
     }
   }
+
+  //The following are copied and adopted from the phoenix-core QueryUtil and PhoenixEmbedded classes
+
+  public final static String JDBC_PROTOCOL = "jdbc:phoenix";
+  public final static char JDBC_PROTOCOL_SEPARATOR = ':';
+  public final static char JDBC_PROTOCOL_TERMINATOR = ';';
+
+  /**
+   * @return connection url using the various properties set in props and conf.
+   */
+  public String getConnectionUrl(Properties props, Configuration conf)
+     throws ClassNotFoundException, SQLException {
+    // read the hbase properties from the configuration
+    int port = getInt(HConstants.ZOOKEEPER_CLIENT_PORT, HConstants.DEFAULT_ZOOKEPER_CLIENT_PORT, props, conf);
+    // Build the ZK quorum server string with "server:clientport" list, separated by ','
+    final String server = getString(HConstants.ZOOKEEPER_QUORUM, HConstants.LOCALHOST, props, conf);
+    String znodeParent = getString(HConstants.ZOOKEEPER_ZNODE_PARENT, HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT, props, conf);
+    String url = getUrl(server, port, znodeParent);
+    if (url.endsWith(JDBC_PROTOCOL_TERMINATOR + "")) {
+      url = url.substring(0, url.length() - 1);
+    }
+    // Mainly for testing to tack on the test=true part to ensure driver is found on server
+    String defaultExtraArgs =
+          conf != null
+                  ? conf.get(QueryServerProperties.EXTRA_JDBC_ARGUMENTS_ATTRIB,
+                      QueryServerOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS)
+                  : QueryServerOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS;
+    // If props doesn't have a default for extra args then use the extra args in conf as default
+    String extraArgs =
+          props.getProperty(QueryServerProperties.EXTRA_JDBC_ARGUMENTS_ATTRIB, defaultExtraArgs);
+    if (extraArgs.length() > 0) {
+      url += JDBC_PROTOCOL_TERMINATOR + extraArgs + JDBC_PROTOCOL_TERMINATOR;
+    } else {
+      url += JDBC_PROTOCOL_TERMINATOR;
+    }
+    return url;
+  }
+
+  private int getInt(String key, int defaultValue, Properties props, Configuration conf) {
+    if (conf == null) {
+      Preconditions.checkNotNull(props);
+      return Integer.parseInt(props.getProperty(key, String.valueOf(defaultValue)));
+    }
+    return conf.getInt(key, defaultValue);
+  }
+
+  private String getString(String key, String defaultValue, Properties props, Configuration conf) {
+      if (conf == null) {
+          Preconditions.checkNotNull(props);
+          return props.getProperty(key, defaultValue);
+      }
+      return conf.get(key, defaultValue);
+  }
+
+  private static String getUrl(String zookeeperQuorum, Integer port, String rootNode) {
+    return JDBC_PROTOCOL + JDBC_PROTOCOL_SEPARATOR
+            + zookeeperQuorum + (port == null ? "" : ":" + port)
+                  + (rootNode == null ? "" : ":" + rootNode)
+                  + JDBC_PROTOCOL_TERMINATOR;
+  }
 }
diff --git a/queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java b/queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
index 5f39362..8486a79 100644
--- a/queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
+++ b/queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
@@ -49,9 +49,9 @@ import org.apache.hadoop.security.authorize.AuthorizationException;
 import org.apache.hadoop.util.StringUtils;
 import org.apache.hadoop.util.Tool;
 import org.apache.hadoop.util.ToolRunner;
-import org.apache.phoenix.query.QueryServices;
-import org.apache.phoenix.query.QueryServicesOptions;
 import org.apache.phoenix.loadbalancer.service.LoadBalanceZookeeperConf;
+import org.apache.phoenix.queryserver.QueryServerOptions;
+import org.apache.phoenix.queryserver.QueryServerProperties;
 import org.apache.phoenix.queryserver.register.Registry;
 import org.apache.phoenix.util.InstanceResolver;
 import org.eclipse.jetty.server.Server;
@@ -77,8 +77,6 @@ import java.util.concurrent.TimeUnit;
 
 import javax.servlet.http.HttpServletRequest;
 
-import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_QUERY_SERVER_CUSTOM_AUTH_ENABLED;
-
 /**
  * A query server for Phoenix over Calcite's Avatica.
  */
@@ -116,12 +114,12 @@ public final class QueryServer extends Configured implements Tool, Runnable {
    */
   public static void logProcessInfo(Configuration conf) {
     // log environment variables unless asked not to
-    if (conf == null || !conf.getBoolean(QueryServices.QUERY_SERVER_ENV_LOGGING_ATTRIB, false)) {
+    if (conf == null || !conf.getBoolean(QueryServerProperties.QUERY_SERVER_ENV_LOGGING_ATTRIB, false)) {
       Set<String> skipWords = new HashSet<String>(
-          QueryServicesOptions.DEFAULT_QUERY_SERVER_SKIP_WORDS);
+          QueryServerOptions.DEFAULT_QUERY_SERVER_SKIP_WORDS);
       if (conf != null) {
         String[] confSkipWords = conf.getStrings(
-            QueryServices.QUERY_SERVER_ENV_LOGGING_SKIPWORDS_ATTRIB);
+            QueryServerProperties.QUERY_SERVER_ENV_LOGGING_SKIPWORDS_ATTRIB);
         if (confSkipWords != null) {
           skipWords.addAll(Arrays.asList(confSkipWords));
         }
@@ -192,38 +190,38 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   @Override
   public int run(String[] args) throws Exception {
     logProcessInfo(getConf());
-    final boolean loadBalancerEnabled = getConf().getBoolean(QueryServices.PHOENIX_QUERY_SERVER_LOADBALANCER_ENABLED,
-            QueryServicesOptions.DEFAULT_PHOENIX_QUERY_SERVER_LOADBALANCER_ENABLED);
+    final boolean loadBalancerEnabled = getConf().getBoolean(QueryServerProperties.PHOENIX_QUERY_SERVER_LOADBALANCER_ENABLED,
+            QueryServerOptions.DEFAULT_PHOENIX_QUERY_SERVER_LOADBALANCER_ENABLED);
     try {
       final boolean isKerberos = "kerberos".equalsIgnoreCase(getConf().get(
-          QueryServices.QUERY_SERVER_HBASE_SECURITY_CONF_ATTRIB));
-      final boolean disableSpnego = getConf().getBoolean(QueryServices.QUERY_SERVER_SPNEGO_AUTH_DISABLED_ATTRIB,
-              QueryServicesOptions.DEFAULT_QUERY_SERVER_SPNEGO_AUTH_DISABLED);
+          QueryServerProperties.QUERY_SERVER_HBASE_SECURITY_CONF_ATTRIB));
+      final boolean disableSpnego = getConf().getBoolean(QueryServerProperties.QUERY_SERVER_SPNEGO_AUTH_DISABLED_ATTRIB,
+              QueryServerOptions.DEFAULT_QUERY_SERVER_SPNEGO_AUTH_DISABLED);
       String hostname;
-      final boolean disableLogin = getConf().getBoolean(QueryServices.QUERY_SERVER_DISABLE_KERBEROS_LOGIN,
-              QueryServicesOptions.DEFAULT_QUERY_SERVER_DISABLE_KERBEROS_LOGIN);
+      final boolean disableLogin = getConf().getBoolean(QueryServerProperties.QUERY_SERVER_DISABLE_KERBEROS_LOGIN,
+              QueryServerOptions.DEFAULT_QUERY_SERVER_DISABLE_KERBEROS_LOGIN);
 
       // handle secure cluster credentials
       if (isKerberos && !disableLogin) {
         hostname = Strings.domainNamePointerToHostName(DNS.getDefaultHost(
-            getConf().get(QueryServices.QUERY_SERVER_DNS_INTERFACE_ATTRIB, "default"),
-            getConf().get(QueryServices.QUERY_SERVER_DNS_NAMESERVER_ATTRIB, "default")));
+            getConf().get(QueryServerProperties.QUERY_SERVER_DNS_INTERFACE_ATTRIB, "default"),
+            getConf().get(QueryServerProperties.QUERY_SERVER_DNS_NAMESERVER_ATTRIB, "default")));
         if (LOG.isDebugEnabled()) {
           LOG.debug("Login to " + hostname + " using " + getConf().get(
-              QueryServices.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB)
+              QueryServerProperties.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB)
               + " and principal " + getConf().get(
-                  QueryServices.QUERY_SERVER_KERBEROS_PRINCIPAL_ATTRIB) + ".");
+                  QueryServerProperties.QUERY_SERVER_KERBEROS_PRINCIPAL_ATTRIB) + ".");
         }
-        SecurityUtil.login(getConf(), QueryServices.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB,
-            QueryServices.QUERY_SERVER_KERBEROS_PRINCIPAL_ATTRIB, hostname);
+        SecurityUtil.login(getConf(), QueryServerProperties.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB,
+            QueryServerProperties.QUERY_SERVER_KERBEROS_PRINCIPAL_ATTRIB, hostname);
         LOG.info("Login successful.");
       } else {
         hostname = InetAddress.getLocalHost().getHostName();
         LOG.info(" Kerberos is off and hostname is : "+hostname);
       }
 
-      int port = getConf().getInt(QueryServices.QUERY_SERVER_HTTP_PORT_ATTRIB,
-          QueryServicesOptions.DEFAULT_QUERY_SERVER_HTTP_PORT);
+      int port = getConf().getInt(QueryServerProperties.QUERY_SERVER_HTTP_PORT_ATTRIB,
+          QueryServerOptions.DEFAULT_QUERY_SERVER_HTTP_PORT);
       LOG.debug("Listening on port " + port);
 
       // Update proxyuser configuration for impersonation
@@ -241,8 +239,8 @@ public final class QueryServer extends Configured implements Tool, Runnable {
       // RemoteUserCallbacks and RemoteUserExtractor are part of AvaticaServerConfiguration
       // Hence they should be customizable when using QUERY_SERVER_CUSTOM_AUTH_ENABLED
       // Handlers should be customized via ServerCustomizers
-      if (getConf().getBoolean(QueryServices.QUERY_SERVER_CUSTOM_AUTH_ENABLED,
-              DEFAULT_QUERY_SERVER_CUSTOM_AUTH_ENABLED)) {
+      if (getConf().getBoolean(QueryServerProperties.QUERY_SERVER_CUSTOM_AUTH_ENABLED,
+          QueryServerOptions.DEFAULT_QUERY_SERVER_CUSTOM_AUTH_ENABLED)) {
         avaticaServerConfiguration = enableCustomAuth(builder, getConf(), ugi);
       } else {
         if (isKerberos) {
@@ -287,17 +285,17 @@ public final class QueryServer extends Configured implements Tool, Runnable {
 
   @VisibleForTesting
   void configureSpnegoAuthentication(HttpServer.Builder builder, UserGroupInformation ugi) throws IOException {
-    String keytabPath = getConf().get(QueryServices.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB);
+    String keytabPath = getConf().get(QueryServerProperties.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB);
     File keytab = new File(keytabPath);
     String httpKeytabPath =
-            getConf().get(QueryServices.QUERY_SERVER_HTTP_KEYTAB_FILENAME_ATTRIB, null);
+            getConf().get(QueryServerProperties.QUERY_SERVER_HTTP_KEYTAB_FILENAME_ATTRIB, null);
     String httpPrincipal = getSpnegoPrincipal(getConf());
     File httpKeytab = null;
     if (null != httpKeytabPath) {
         httpKeytab = new File(httpKeytabPath);
     }
 
-    String realmsString = getConf().get(QueryServices.QUERY_SERVER_KERBEROS_ALLOWED_REALMS, null);
+    String realmsString = getConf().get(QueryServerProperties.QUERY_SERVER_KERBEROS_ALLOWED_REALMS, null);
     String[] additionalAllowedRealms = null;
     if (null != realmsString) {
       additionalAllowedRealms = StringUtils.split(realmsString, ',');
@@ -317,16 +315,16 @@ public final class QueryServer extends Configured implements Tool, Runnable {
    */
   String getSpnegoPrincipal(Configuration conf) throws IOException {
     String httpPrincipal = conf.get(
-        QueryServices.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB, null);
+        QueryServerProperties.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB, null);
     // Backwards compat for a configuration key change
     if (httpPrincipal == null) {
       httpPrincipal = conf.get(
-          QueryServices.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB_LEGACY, null);
+          QueryServerProperties.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB_LEGACY, null);
     }
 
     String hostname = Strings.domainNamePointerToHostName(DNS.getDefaultHost(
-        conf.get(QueryServices.QUERY_SERVER_DNS_INTERFACE_ATTRIB, "default"),
-        conf.get(QueryServices.QUERY_SERVER_DNS_NAMESERVER_ATTRIB, "default")));
+        conf.get(QueryServerProperties.QUERY_SERVER_DNS_INTERFACE_ATTRIB, "default"),
+        conf.get(QueryServerProperties.QUERY_SERVER_DNS_NAMESERVER_ATTRIB, "default")));
     return SecurityUtil.getServerPrincipal(httpPrincipal, hostname);
   }
 
@@ -348,7 +346,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
 
   private void setHandler(String[] args, HttpServer.Builder<Server> builder) throws Exception {
     Class<? extends PhoenixMetaFactory> factoryClass = getConf().getClass(
-            QueryServices.QUERY_SERVER_META_FACTORY_ATTRIB, PhoenixMetaFactoryImpl.class,
+            QueryServerProperties.QUERY_SERVER_META_FACTORY_ATTRIB, PhoenixMetaFactoryImpl.class,
             PhoenixMetaFactory.class);
     PhoenixMetaFactory factory =
             factoryClass.getDeclaredConstructor(Configuration.class).newInstance(getConf());
@@ -424,8 +422,8 @@ public final class QueryServer extends Configured implements Tool, Runnable {
    * @return The Serialization method
    */
   Driver.Serialization getSerialization(Configuration conf) {
-    String serializationName = conf.get(QueryServices.QUERY_SERVER_SERIALIZATION_ATTRIB,
-        QueryServicesOptions.DEFAULT_QUERY_SERVER_SERIALIZATION);
+    String serializationName = conf.get(QueryServerProperties.QUERY_SERVER_SERIALIZATION_ATTRIB,
+        QueryServerOptions.DEFAULT_QUERY_SERVER_SERIALIZATION);
 
     Driver.Serialization serialization;
     // Otherwise, use what was provided in the configuration
@@ -450,8 +448,8 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   // add remoteUserExtractor to builder if enabled
   @VisibleForTesting
   public void setRemoteUserExtractorIfNecessary(HttpServer.Builder builder, Configuration conf) {
-    if (conf.getBoolean(QueryServices.QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB,
-            QueryServicesOptions.DEFAULT_QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR)) {
+    if (conf.getBoolean(QueryServerProperties.QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB,
+            QueryServerOptions.DEFAULT_QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR)) {
       builder.withRemoteUserExtractor(createRemoteUserExtractor(conf));
     }
   }
@@ -459,8 +457,8 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   @VisibleForTesting
   public void enableServerCustomizersIfNecessary(HttpServer.Builder<Server> builder,
                                                  Configuration conf, AvaticaServerConfiguration avaticaServerConfiguration) {
-    if (conf.getBoolean(QueryServices.QUERY_SERVER_CUSTOMIZERS_ENABLED,
-            QueryServicesOptions.DEFAULT_QUERY_SERVER_CUSTOMIZERS_ENABLED)) {
+    if (conf.getBoolean(QueryServerProperties.QUERY_SERVER_CUSTOMIZERS_ENABLED,
+            QueryServerOptions.DEFAULT_QUERY_SERVER_CUSTOMIZERS_ENABLED)) {
       builder.withServerCustomizers(createServerCustomizers(conf, avaticaServerConfiguration), Server.class);
     }
   }
@@ -513,8 +511,8 @@ public final class QueryServer extends Configured implements Tool, Runnable {
 
     public PhoenixRemoteUserExtractor(Configuration conf) {
       this.requestRemoteUserExtractor = new HttpRequestRemoteUserExtractor();
-      this.userExtractParam = conf.get(QueryServices.QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM,
-              QueryServicesOptions.DEFAULT_QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM);
+      this.userExtractParam = conf.get(QueryServerProperties.QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM,
+              QueryServerOptions.DEFAULT_QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM);
       this.paramRemoteUserExtractor = new HttpQueryStringParameterRemoteUserExtractor(userExtractParam);
     }
 
@@ -553,12 +551,12 @@ public final class QueryServer extends Configured implements Tool, Runnable {
     public PhoenixDoAsCallback(UserGroupInformation serverUgi, Configuration conf) {
       this.serverUgi = Objects.requireNonNull(serverUgi);
       this.ugiCache = CacheBuilder.newBuilder()
-          .initialCapacity(conf.getInt(QueryServices.QUERY_SERVER_UGI_CACHE_INITIAL_SIZE,
-                  QueryServicesOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_INITIAL_SIZE))
-          .concurrencyLevel(conf.getInt(QueryServices.QUERY_SERVER_UGI_CACHE_CONCURRENCY,
-                  QueryServicesOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_CONCURRENCY))
-          .maximumSize(conf.getLong(QueryServices.QUERY_SERVER_UGI_CACHE_MAX_SIZE,
-                  QueryServicesOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_MAX_SIZE))
+          .initialCapacity(conf.getInt(QueryServerProperties.QUERY_SERVER_UGI_CACHE_INITIAL_SIZE,
+                  QueryServerOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_INITIAL_SIZE))
+          .concurrencyLevel(conf.getInt(QueryServerProperties.QUERY_SERVER_UGI_CACHE_CONCURRENCY,
+                  QueryServerOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_CONCURRENCY))
+          .maximumSize(conf.getLong(QueryServerProperties.QUERY_SERVER_UGI_CACHE_MAX_SIZE,
+                  QueryServerOptions.DEFAULT_QUERY_SERVER_UGI_CACHE_MAX_SIZE))
           .build(new UgiCacheLoader(this.serverUgi));
     }
 
diff --git a/queryserver/src/main/java/org/apache/phoenix/util/InstanceResolver.java b/queryserver/src/main/java/org/apache/phoenix/util/InstanceResolver.java
new file mode 100644
index 0000000..4757e46
--- /dev/null
+++ b/queryserver/src/main/java/org/apache/phoenix/util/InstanceResolver.java
@@ -0,0 +1,95 @@
+/*
+ * 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.util;
+
+import org.apache.commons.collections.IteratorUtils;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Resolves object instances registered using the JDK 6+ {@link java.util.ServiceLoader}.
+ *
+ * 
+ * @since 2.0
+ */
+public class InstanceResolver {
+    private static final ConcurrentHashMap<Class, Object> RESOLVED_SINGLETONS = new ConcurrentHashMap<Class, Object>();
+
+    private InstanceResolver() {/* not allowed */}
+
+    /**
+     * Resolves an instance of the specified class if it has not already been resolved.
+     * @param clazz The type of instance to resolve
+     * @param defaultInstance The instance to use if a custom instance has not been registered
+     * @return The resolved instance or the default instance provided.
+     *         {@code null} if an instance is not registered and a default is not provided.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getSingleton(Class<T> clazz, T defaultInstance) {
+        Object obj = RESOLVED_SINGLETONS.get(clazz);
+        if(obj != null) {
+            return (T)obj;
+        }
+        if (defaultInstance != null && !clazz.isInstance(defaultInstance)) throw new IllegalArgumentException("defaultInstance is not of type " + clazz.getName());
+        final Object o = resolveSingleton(clazz, defaultInstance);
+        obj = RESOLVED_SINGLETONS.putIfAbsent(clazz, o);
+        if(obj == null) {
+            obj = o;
+        }
+        return (T)obj;
+    }
+
+    /**
+     * Resolves all instances of a specified class and add it to the list of default implementations
+     * @param clazz Type of the instance to resolve
+     * @param defaultInstances {@link List} of instances that match the type clazz
+     * @param <T> Type of class passed
+     * @return {@link List} of instance of the specified class. Newly found instances will be added
+     *          to the existing contents of defaultInstances
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> List get(Class<T> clazz, List<T> defaultInstances) {
+        Iterator<T> iterator = ServiceLoader.load(clazz).iterator();
+        if (defaultInstances != null) {
+            defaultInstances.addAll(IteratorUtils.toList(iterator));
+        } else {
+            defaultInstances = IteratorUtils.toList(iterator);
+        }
+
+        return defaultInstances;
+    }
+
+    private synchronized static <T> T resolveSingleton(Class<T> clazz, T defaultInstance) {
+        ServiceLoader<T> loader = ServiceLoader.load(clazz);
+        // returns the first registered instance found
+        for (T singleton : loader) {
+            return singleton;
+        }
+        return defaultInstance;
+    }
+
+    @VisibleForTesting
+    public static void clearSingletons() {
+        RESOLVED_SINGLETONS.clear();
+    }
+}