HCATALOG-531 HCatContext should be an enum

git-svn-id: https://svn.apache.org/repos/asf/incubator/hcatalog/trunk@1412314 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES.txt b/CHANGES.txt
index 446bcb1..c4f90dd 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -44,6 +44,8 @@
   HCAT-427 Document storage-based authorization (lefty via gates)
 
   IMPROVEMENTS
+  HCAT-531 HCatContext should be an enum (traviscrawford)
+
   HCAT-530 HCatBaseLoader.getSizeInBytes NPE when partition path is missing (traviscrawford)
 
   HCAT-518 Refactor hcatalog-core as subproject (traviscrawford and toffer)
diff --git a/core/src/main/java/org/apache/hcatalog/common/HCatContext.java b/core/src/main/java/org/apache/hcatalog/common/HCatContext.java
index 1c40b5e..34e1af9 100644
--- a/core/src/main/java/org/apache/hcatalog/common/HCatContext.java
+++ b/core/src/main/java/org/apache/hcatalog/common/HCatContext.java
@@ -21,50 +21,65 @@
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.common.classification.InterfaceAudience;
+import org.apache.hadoop.hive.common.classification.InterfaceStability;
 
 import java.util.Map;
 
 /**
- * HCatContext provides global access to configuration data. It uses a reference to the
- * job configuration so that settings are automatically passed to the backend by the
- * MR framework.
+ * HCatContext is a singleton that provides global access to configuration data.
+ *
+ * <p>HCatalog provides a variety of functionality that users can configure at runtime through
+ * configuration properties. Available configuration properties are defined in
+ * {@link HCatConstants}. HCatContext allows users to enable optional functionality by
+ * setting properties in a provided configuration.</p>
+ *
+ * <p>HCatalog <em>users</em> (MR apps, processing framework adapters) should set properties
+ * in a configuration that has been provided to
+ * {@link #setConf(org.apache.hadoop.conf.Configuration)} to enable optional functionality.
+ * The job configuration must be used to ensure properties are passed to the backend MR tasks.</p>
+ *
+ * <p>HCatalog <em>developers</em> should enable optional functionality by checking properties
+ * from {@link #getConf()}. Since users are not obligated to set a configuration, optional
+ * functionality must provide a sensible default.</p>
  */
-public class HCatContext {
-
-    private static final HCatContext hCatContext = new HCatContext();
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public enum HCatContext {
+    INSTANCE;
 
     private Configuration conf = null;
 
-    private HCatContext() {
-    }
-
     /**
-     * Setup the HCatContext as a reference to the given configuration. Keys
-     * exclusive to an existing config are set in the new conf.
+     * Use the given configuration for optional behavior. Keys exclusive to an existing config
+     * are set in the new conf. The job conf must be used to ensure properties are passed to
+     * backend MR tasks.
      */
-    public static synchronized HCatContext setupHCatContext(Configuration newConf) {
-        Preconditions.checkNotNull(newConf, "HCatContext must not have a null conf.");
+    public synchronized HCatContext setConf(Configuration newConf) {
+        Preconditions.checkNotNull(newConf, "Required parameter 'newConf' must not be null.");
 
-        if (hCatContext.conf == null) {
-            hCatContext.conf = newConf;
-            return hCatContext;
+        if (conf == null) {
+            conf = newConf;
+            return this;
         }
 
-        if (hCatContext.conf != newConf) {
-            for (Map.Entry<String, String> entry : hCatContext.conf) {
+        if (conf != newConf) {
+            for (Map.Entry<String, String> entry : conf) {
                 if (newConf.get(entry.getKey()) == null) {
                     newConf.set(entry.getKey(), entry.getValue());
                 }
             }
-            hCatContext.conf = newConf;
+            conf = newConf;
         }
-        return hCatContext;
+        return this;
     }
 
-    public static HCatContext getInstance() {
-        return hCatContext;
-    }
-
+    /**
+     * Get the configuration, if there is one. Users are not required to setup HCatContext
+     * unless they wish to override default behavior, so the configuration may not be present.
+     *
+     * @return an Optional that might contain a Configuration
+     */
     public Optional<Configuration> getConf() {
         return Optional.fromNullable(conf);
     }
diff --git a/core/src/main/java/org/apache/hcatalog/data/HCatRecordSerDe.java b/core/src/main/java/org/apache/hcatalog/data/HCatRecordSerDe.java
index 468a1f5..b59febe 100644
--- a/core/src/main/java/org/apache/hcatalog/data/HCatRecordSerDe.java
+++ b/core/src/main/java/org/apache/hcatalog/data/HCatRecordSerDe.java
@@ -265,8 +265,8 @@
     private static Object serializePrimitiveField(Object field,
             ObjectInspector fieldObjectInspector) {
 
-        if (field != null && HCatContext.getInstance().getConf().isPresent()) {
-            Configuration conf = HCatContext.getInstance().getConf().get();
+        if (field != null && HCatContext.INSTANCE.getConf().isPresent()) {
+            Configuration conf = HCatContext.INSTANCE.getConf().get();
 
             if (field instanceof Boolean &&
                 conf.getBoolean(
diff --git a/core/src/main/java/org/apache/hcatalog/data/schema/HCatSchemaUtils.java b/core/src/main/java/org/apache/hcatalog/data/schema/HCatSchemaUtils.java
index b4060e9..5e95439 100644
--- a/core/src/main/java/org/apache/hcatalog/data/schema/HCatSchemaUtils.java
+++ b/core/src/main/java/org/apache/hcatalog/data/schema/HCatSchemaUtils.java
@@ -139,14 +139,14 @@
     private static Type getPrimitiveHType(TypeInfo basePrimitiveTypeInfo) {
         switch (((PrimitiveTypeInfo) basePrimitiveTypeInfo).getPrimitiveCategory()) {
         case BOOLEAN:
-            return (HCatContext.getInstance().getConf().isPresent() &&
-                HCatContext.getInstance().getConf().get().getBoolean(
+            return (HCatContext.INSTANCE.getConf().isPresent() &&
+                HCatContext.INSTANCE.getConf().get().getBoolean(
                     HCatConstants.HCAT_DATA_CONVERT_BOOLEAN_TO_INTEGER,
                     HCatConstants.HCAT_DATA_CONVERT_BOOLEAN_TO_INTEGER_DEFAULT)) ?
                 Type.INT : Type.BOOLEAN;
         case BYTE:
-            return (HCatContext.getInstance().getConf().isPresent() &&
-                HCatContext.getInstance().getConf().get().getBoolean(
+            return (HCatContext.INSTANCE.getConf().isPresent() &&
+                HCatContext.INSTANCE.getConf().get().getBoolean(
                     HCatConstants.HCAT_DATA_TINY_SMALL_INT_PROMOTION,
                     HCatConstants.HCAT_DATA_TINY_SMALL_INT_PROMOTION_DEFAULT)) ?
                 Type.INT : Type.TINYINT;
@@ -159,8 +159,8 @@
         case LONG:
             return Type.BIGINT;
         case SHORT:
-            return (HCatContext.getInstance().getConf().isPresent() &&
-                HCatContext.getInstance().getConf().get().getBoolean(
+            return (HCatContext.INSTANCE.getConf().isPresent() &&
+                HCatContext.INSTANCE.getConf().get().getBoolean(
                     HCatConstants.HCAT_DATA_TINY_SMALL_INT_PROMOTION,
                     HCatConstants.HCAT_DATA_TINY_SMALL_INT_PROMOTION_DEFAULT)) ?
                 Type.INT : Type.SMALLINT;
diff --git a/hcatalog-pig-adapter/src/main/java/org/apache/hcatalog/pig/HCatLoader.java b/hcatalog-pig-adapter/src/main/java/org/apache/hcatalog/pig/HCatLoader.java
index 4bdb7c3..5a4d400 100644
--- a/hcatalog-pig-adapter/src/main/java/org/apache/hcatalog/pig/HCatLoader.java
+++ b/hcatalog-pig-adapter/src/main/java/org/apache/hcatalog/pig/HCatLoader.java
@@ -82,7 +82,7 @@
 
     @Override
     public void setLocation(String location, Job job) throws IOException {
-        HCatContext.setupHCatContext(job.getConfiguration()).getConf().get()
+        HCatContext.INSTANCE.setConf(job.getConfiguration()).getConf().get()
             .setBoolean(HCatConstants.HCAT_DATA_TINY_SMALL_INT_PROMOTION, true);
 
         UDFContext udfContext = UDFContext.getUDFContext();
@@ -187,7 +187,7 @@
 
     @Override
     public ResourceSchema getSchema(String location, Job job) throws IOException {
-        HCatContext.setupHCatContext(job.getConfiguration()).getConf().get()
+        HCatContext.INSTANCE.setConf(job.getConfiguration()).getConf().get()
             .setBoolean(HCatConstants.HCAT_DATA_TINY_SMALL_INT_PROMOTION, true);
 
         Table table = phutil.getTable(location,
diff --git a/hcatalog-pig-adapter/src/main/java/org/apache/hcatalog/pig/HCatStorer.java b/hcatalog-pig-adapter/src/main/java/org/apache/hcatalog/pig/HCatStorer.java
index 54c174b..a457a07 100644
--- a/hcatalog-pig-adapter/src/main/java/org/apache/hcatalog/pig/HCatStorer.java
+++ b/hcatalog-pig-adapter/src/main/java/org/apache/hcatalog/pig/HCatStorer.java
@@ -77,7 +77,7 @@
 
     @Override
     public void setStoreLocation(String location, Job job) throws IOException {
-        HCatContext.setupHCatContext(job.getConfiguration()).getConf().get()
+        HCatContext.INSTANCE.setConf(job.getConfiguration()).getConf().get()
             .setBoolean(HCatConstants.HCAT_DATA_TINY_SMALL_INT_PROMOTION, false);
 
         Configuration config = job.getConfiguration();