AMBARI-9406. Service configurations are not updated as customized in the 
descriptor (rlevas)


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

Branch: refs/heads/trunk
Commit: d6c389c115194e6055f5e21fefdf389a4b5c586f
Parents: 5ff857c
Author: Robert Levas <rle...@hortonworks.com>
Authored: Tue Feb 3 20:39:06 2015 -0500
Committer: Robert Levas <rle...@hortonworks.com>
Committed: Tue Feb 3 20:39:13 2015 -0500

----------------------------------------------------------------------
 .../server/api/services/AmbariMetaInfo.java     |  18 +-
 .../AmbariManagementControllerImpl.java         |   7 +-
 .../server/controller/ClusterRequest.java       |  30 +--
 .../server/controller/ControllerModule.java     |   4 +
 .../server/controller/KerberosHelper.java       | 170 +++++++-------
 .../internal/ClusterResourceProvider.java       | 113 ---------
 .../internal/HostComponentResourceProvider.java |   2 +-
 .../internal/StackArtifactResourceProvider.java |  51 ++--
 .../internal/StackServiceResourceProvider.java  |  35 ++-
 .../internal/StackVersionResourceProvider.java  |  21 +-
 .../kerberos/AbstractKerberosDescriptor.java    |  46 ----
 .../AbstractKerberosDescriptorFactory.java      |  83 +++++++
 .../state/kerberos/KerberosDescriptor.java      |  34 +--
 .../kerberos/KerberosDescriptorFactory.java     |  80 +++++++
 .../kerberos/KerberosServiceDescriptor.java     | 106 +--------
 .../KerberosServiceDescriptorFactory.java       | 232 +++++++++++++++++++
 .../server/api/services/AmbariMetaInfoTest.java |  14 ++
 .../AmbariManagementControllerImplTest.java     |  56 +----
 .../server/controller/KerberosHelperTest.java   | 100 ++++----
 .../HostComponentResourceProviderTest.java      |   3 +-
 .../server/stack/KerberosDescriptorTest.java    |  10 +-
 .../ambari/server/state/ConfigHelperTest.java   |   7 +-
 .../state/kerberos/KerberosDescriptorTest.java  |   9 +-
 .../kerberos/KerberosServiceDescriptorTest.java |  14 +-
 24 files changed, 643 insertions(+), 602 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index 897cf52..aa239ec 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -67,7 +67,9 @@ import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptorFactory;
 import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.ambari.server.state.stack.UpgradePack;
@@ -168,6 +170,18 @@ public class AmbariMetaInfo {
   @Inject
   private AmbariEventPublisher eventPublisher;
 
+  /**
+   * KerberosDescriptorFactory used to create KerberosDescriptor instances
+   */
+  @Inject
+  private KerberosDescriptorFactory kerberosDescriptorFactory;
+
+  /**
+   * KerberosServiceDescriptorFactory used to create KerberosServiceDescriptor 
instances
+   */
+  @Inject
+  private KerberosServiceDescriptorFactory kerberosServiceDescriptorFactory;
+
   //todo: only used by StackManager
   @Inject
   ActionMetadata actionMetadata;
@@ -1034,7 +1048,7 @@ public class AmbariMetaInfo {
 
       if (file.canRead()) {
         try {
-          kerberosDescriptor = KerberosDescriptor.fromFile(file);
+          kerberosDescriptor = kerberosDescriptorFactory.createInstance(file);
         } catch (IOException e) {
           throw new AmbariException(String.format("Failed to parse kerberos 
descriptor file %s",
               file.getAbsolutePath()), e);
@@ -1086,7 +1100,7 @@ public class AmbariMetaInfo {
 
     if (kerberosFile != null) {
       try {
-        kerberosServiceDescriptors = 
KerberosServiceDescriptor.fromFile(kerberosFile);
+        kerberosServiceDescriptors = 
kerberosServiceDescriptorFactory.createInstances(kerberosFile);
       } catch (Exception e) {
         LOG.error("Could not read the kerberos descriptor file", e);
         throw new AmbariException("Could not read kerberos descriptor file", 
e);

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 0f5721a..7d78a4a 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -1362,7 +1362,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
       // if any custom operations are valid and requested, the process of 
executing them should be initiated,
       // most of the validation logic will be left to the KerberosHelper to 
avoid polluting the controller
       if (kerberosHelper.shouldExecuteCustomOperations(securityType, 
requestProperties)) {
-        requestStageContainer = 
kerberosHelper.executeCustomOperations(cluster, 
request.getKerberosDescriptor(), requestProperties, requestStageContainer);
+        requestStageContainer = 
kerberosHelper.executeCustomOperations(cluster, requestProperties, 
requestStageContainer);
       } else if (cluster.getSecurityType() != securityType) {
         LOG.info("Received cluster security type change request from {} to {}",
             cluster.getSecurityType().name(), securityType.name());
@@ -1371,7 +1371,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
           // Since the security state of the cluster has changed, invoke 
toggleKerberos to handle
           // adding or removing Kerberos from the cluster. This may generate 
multiple stages
           // or not depending the current state of the cluster.
-          requestStageContainer = kerberosHelper.toggleKerberos(cluster, 
securityType, request.getKerberosDescriptor(), requestStageContainer);
+          requestStageContainer = kerberosHelper.toggleKerberos(cluster, 
securityType, requestStageContainer);
         } else {
           throw new IllegalArgumentException(String.format("Unexpected 
security type encountered: %s", securityType.name()));
         }
@@ -2853,8 +2853,7 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
 
       serviceComponentFilter.put("KERBEROS", null);
 
-      requestStageContainer = kerberosHelper.ensureIdentities(cluster, null, 
serviceComponentFilter,
-          identityFilter, requestStageContainer);
+      requestStageContainer = kerberosHelper.ensureIdentities(cluster, 
serviceComponentFilter, identityFilter, requestStageContainer);
     }
 
     ExecuteCommandJson jsons = customCommandExecutionHelper.getCommandJson(

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
index 9e097c3..5c7548c 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
@@ -19,7 +19,6 @@
 package org.apache.ambari.server.controller;
 
 import org.apache.ambari.server.state.SecurityType;
-import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
 
 import java.util.List;
 import java.util.Map;
@@ -52,11 +51,6 @@ public class ClusterRequest {
   private ServiceConfigVersionRequest serviceConfigVersionRequest = null;
 
   /**
-   * A KerberosDescriptor parsed from the request payload.
-   */
-  private KerberosDescriptor kerberosDescriptor;
-
-  /**
    * The cluster session attributes.
    */
   private final Map<String, Object> sessionAttributes;
@@ -71,13 +65,12 @@ public class ClusterRequest {
 
   public ClusterRequest(Long clusterId, String clusterName,
       String provisioningState, SecurityType securityType, String 
stackVersion, Set<String> hostNames) {
-    this(clusterId, clusterName, provisioningState, securityType, 
stackVersion, hostNames, null, null);
+    this(clusterId, clusterName, provisioningState, securityType, 
stackVersion, hostNames, null);
   }
 
   public ClusterRequest(Long clusterId, String clusterName,
                         String provisioningState, SecurityType securityType, 
String stackVersion,
-                        Set<String> hostNames, KerberosDescriptor 
kerberosDescriptor,
-                        Map<String, Object> sessionAttributes) {
+                        Set<String> hostNames, Map<String, Object> 
sessionAttributes) {
     super();
     this.clusterId         = clusterId;
     this.clusterName       = clusterName;
@@ -86,7 +79,6 @@ public class ClusterRequest {
     this.stackVersion      = stackVersion;
     this.hostNames         = hostNames;
     this.sessionAttributes = sessionAttributes;
-    this.kerberosDescriptor = kerberosDescriptor;
   }
 
 
@@ -206,24 +198,6 @@ public class ClusterRequest {
     return configs;
   }
 
-  /**
-   * Returns the KerberosDescriptor for this ClusterRequest
-   *
-   * @return a KerberosDescriptor or null if one was not specified
-   */
-  public KerberosDescriptor getKerberosDescriptor() {
-    return kerberosDescriptor;
-  }
-
-  /**
-   * Sets a KerberosDescriptor for this ClusterRequest
-   *
-   * @param kerberosDescriptor a KerberosDescriptor
-   */
-  public void setKerberosDescriptor(KerberosDescriptor kerberosDescriptor) {
-    this.kerberosDescriptor = kerberosDescriptor;
-  }
-
   @Override
   public String toString() {
     StringBuilder sb = new StringBuilder();

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 8647f26..85ae85b 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -91,6 +91,8 @@ import 
org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.configgroup.ConfigGroupImpl;
 import org.apache.ambari.server.state.host.HostFactory;
 import org.apache.ambari.server.state.host.HostImpl;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
+import 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptorFactory;
 import org.apache.ambari.server.state.scheduler.RequestExecution;
 import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
 import org.apache.ambari.server.state.scheduler.RequestExecutionImpl;
@@ -203,6 +205,8 @@ public class ControllerModule extends AbstractModule {
     bind(SessionIdManager.class).toInstance(sessionIdManager);
 
     bind(KerberosOperationHandlerFactory.class);
+    bind(KerberosDescriptorFactory.class);
+    bind(KerberosServiceDescriptorFactory.class);
 
     bind(Configuration.class).toInstance(configuration);
     bind(OsFamily.class).toInstance(os_family);

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
index e8f475f..8341826 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
@@ -82,6 +82,7 @@ import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosConfigurationDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
 import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor;
 import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
@@ -149,6 +150,9 @@ public class KerberosHelper {
   @Inject
   private KerberosOperationHandlerFactory kerberosOperationHandlerFactory;
 
+  @Inject
+  private KerberosDescriptorFactory kerberosDescriptorFactory;
+
   /**
    * Used to get kerberos descriptors associated with the cluster or stack.
    * Currently not available via injection.
@@ -157,21 +161,6 @@ public class KerberosHelper {
 
 
   /**
-   * The Handler implementation that provides the logic to enable Kerberos
-   */
-  private Handler enableKerberosHandler = new EnableKerberosHandler();
-
-  /**
-   * The Handler implementation that provides the logic to disable Kerberos
-   */
-  private Handler disableKerberosHandler = new DisableKerberosHandler();
-
-  /**
-   * The Handler implementation that provides the logic to ensure the 
existence of principals and keytabs
-   */
-  private Handler createPrincipalsAndKeytabsHandler = new 
CreatePrincipalsAndKeytabsHandler();
-
-  /**
    * Toggles Kerberos security to enable it or remove it depending on the 
state of the cluster.
    * <p/>
    * The cluster "security_type" property is used to determine the security 
state of the cluster.
@@ -193,14 +182,13 @@ public class KerberosHelper {
    * @param cluster               the relevant Cluster
    * @param securityType          the SecurityType to handle; this value is 
expected to be either
    *                              SecurityType.KERBEROS or SecurityType.NONE
-   * @param kerberosDescriptor    a KerberosDescriptor containing updates to 
the descriptor already
-   *                              configured for the cluster
    * @param requestStageContainer a RequestStageContainer to place generated 
stages, if needed -
-   *                              if null a new RequestStageContainer will be 
created.   @return the updated or a new RequestStageContainer containing the 
stages that need to be
-   *                              executed to complete this task; or null if 
no stages need to be executed.
+   *                              if null a new RequestStageContainer will be 
created.
+   * @return the updated or a new RequestStageContainer containing the stages 
that need to be
+   * executed to complete this task; or null if no stages need to be executed.
    * @throws AmbariException
    */
-  public RequestStageContainer toggleKerberos(Cluster cluster, SecurityType 
securityType, KerberosDescriptor kerberosDescriptor,
+  public RequestStageContainer toggleKerberos(Cluster cluster, SecurityType 
securityType,
                                               RequestStageContainer 
requestStageContainer)
       throws AmbariException {
 
@@ -211,10 +199,10 @@ public class KerberosHelper {
 
     if (securityType == SecurityType.KERBEROS) {
       LOG.info("Configuring Kerberos for realm {} on cluster, {}", 
kerberosDetails.getDefaultRealm(), cluster.getClusterName());
-      requestStageContainer = handle(cluster, kerberosDescriptor, 
kerberosDetails, null, null, requestStageContainer, enableKerberosHandler);
+      requestStageContainer = handle(cluster, kerberosDetails, null, null, 
requestStageContainer, new EnableKerberosHandler());
     } else if (securityType == SecurityType.NONE) {
       LOG.info("Disabling Kerberos from cluster, {}", 
cluster.getClusterName());
-      requestStageContainer = handle(cluster, kerberosDescriptor, 
kerberosDetails, null, null, requestStageContainer, disableKerberosHandler);
+      requestStageContainer = handle(cluster, kerberosDetails, null, null, 
requestStageContainer, new DisableKerberosHandler());
     } else {
       throw new AmbariException(String.format("Unexpected security type value: 
%s", securityType.name()));
     }
@@ -226,8 +214,6 @@ public class KerberosHelper {
    * Used to execute custom security operations which are sent as directives 
in URI
    *
    * @param cluster               the relevant Cluster
-   * @param kerberosDescriptor    a KerberosDescriptor containing updates to 
the descriptor already
-   *                              configured for the cluster
    * @param requestProperties     this structure is expected to hold already 
supported and validated directives
    *                              for the 'Cluster' resource. See 
ClusterResourceDefinition#getUpdateDirectives
    * @param requestStageContainer a RequestStageContainer to place generated 
stages, if needed -
@@ -235,8 +221,8 @@ public class KerberosHelper {
    *                              executed to complete this task; or null if 
no stages need to be executed.
    * @throws AmbariException
    */
-  public RequestStageContainer executeCustomOperations(Cluster cluster, 
KerberosDescriptor kerberosDescriptor,
-                                                       Map<String, String> 
requestProperties, RequestStageContainer requestStageContainer)
+  public RequestStageContainer executeCustomOperations(Cluster cluster, 
Map<String, String> requestProperties,
+                                                       RequestStageContainer 
requestStageContainer)
       throws AmbariException {
 
     if (requestProperties != null) {
@@ -253,7 +239,7 @@ public class KerberosHelper {
               }
 
               if ("true".equalsIgnoreCase(value)) {
-                handle(cluster, kerberosDescriptor, 
getKerberosDetails(cluster), null, null, requestStageContainer, 
createPrincipalsAndKeytabsHandler);
+                handle(cluster, getKerberosDetails(cluster), null, null, 
requestStageContainer, new CreatePrincipalsAndKeytabsHandler());
               }
               break;
 
@@ -283,8 +269,6 @@ public class KerberosHelper {
    * information about the Kerberos configuration, generally specific to the 
KDC being used.
    *
    * @param cluster                the relevant Cluster
-   * @param kerberosDescriptor     a KerberosDescriptor containing updates to 
the descriptor already
-   *                               configured for the cluster
    * @param serviceComponentFilter a Map of service names to component names 
indicating the relevant
    *                               set of services and components - if null, 
no filter is relevant;
    *                               if empty, the filter indicates no relevant 
services or components
@@ -297,25 +281,21 @@ public class KerberosHelper {
    * executed to complete this task; or null if no stages need to be executed.
    * @throws AmbariException
    */
-  public RequestStageContainer ensureIdentities(Cluster cluster, 
KerberosDescriptor kerberosDescriptor,
-                                                Map<String, 
Collection<String>> serviceComponentFilter,
-                                                Collection<String> 
identityFilter,
-                                                RequestStageContainer 
requestStageContainer) throws AmbariException {
-    return handle(cluster, kerberosDescriptor, getKerberosDetails(cluster), 
serviceComponentFilter, identityFilter,
-        requestStageContainer, createPrincipalsAndKeytabsHandler);
+  public RequestStageContainer ensureIdentities(Cluster cluster, Map<String, 
Collection<String>> serviceComponentFilter,
+                                                Collection<String> 
identityFilter, RequestStageContainer requestStageContainer)
+      throws AmbariException {
+    return handle(cluster, getKerberosDetails(cluster), 
serviceComponentFilter, identityFilter,
+        requestStageContainer, new CreatePrincipalsAndKeytabsHandler());
   }
 
   /**
-   * Performs operations needed to enable to disable Kerberos on the relevant 
cluster.
+   * Performs operations needed to process Kerberos related tasks on the 
relevant cluster.
    * <p/>
-   * Iterates through the components installed on the relevant cluster and 
attempts to enable or
-   * disable Kerberos as needed.
-   * <p/>
-   * The supplied Handler instance handles the logic on whether this process 
enables or disables
-   * Kerberos.
+   * Iterates through the components installed on the relevant cluster to 
determine if work
+   * need to be done.  Calls into the Handler implementation to provide 
guidance and set up stages
+   * to perform the work needed to complete the relative action.
    *
    * @param cluster                the relevant Cluster
-   * @param kerberosDescriptor     the (derived) KerberosDescriptor
    * @param kerberosDetails        a KerberosDetails containing information 
about relevant Kerberos configuration
    * @param serviceComponentFilter a Map of service names to component names 
indicating the relevant
    *                               set of services and components - if null, 
no filter is relevant;
@@ -325,13 +305,14 @@ public class KerberosHelper {
    *                               relevant identities
    * @param requestStageContainer  a RequestStageContainer to place generated 
stages, if needed -
    *                               if null a new RequestStageContainer will be 
created.
+   * @param handler                a Handler to use to provide guidance and 
set up stages
+   *                               to perform the work needed to complete the 
relative action
    * @return the updated or a new RequestStageContainer containing the stages 
that need to be
    * executed to complete this task; or null if no stages need to be executed.
    * @throws AmbariException
    */
   @Transactional
   private RequestStageContainer handle(Cluster cluster,
-                                       KerberosDescriptor kerberosDescriptor,
                                        KerberosDetails kerberosDetails,
                                        Map<String, Collection<String>> 
serviceComponentFilter,
                                        Collection<String> identityFilter,
@@ -340,11 +321,6 @@ public class KerberosHelper {
 
     Map<String, Service> services = cluster.getServices();
 
-    //todo: modify call from cluster state transition to not include descriptor
-    if (kerberosDescriptor == null) {
-      kerberosDescriptor = getClusterDescriptor(cluster);
-    }
-
     if ((services != null) && !services.isEmpty()) {
       SecurityState desiredSecurityState = 
handler.getNewServiceSecurityState();
       String clusterName = cluster.getClusterName();
@@ -353,7 +329,7 @@ public class KerberosHelper {
       if ((hosts != null) && !hosts.isEmpty()) {
         List<ServiceComponentHost> serviceComponentHostsToProcess = new 
ArrayList<ServiceComponentHost>();
         File indexFile;
-        kerberosDescriptor = 
buildKerberosDescriptor(cluster.getCurrentStackVersion(), kerberosDescriptor);
+        KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
         KerberosActionDataFileBuilder kerberosActionDataFileBuilder = null;
         Map<String, String> kerberosDescriptorProperties = 
kerberosDescriptor.getProperties();
         Map<String, Map<String, String>> kerberosConfigurations = new 
HashMap<String, Map<String, String>>();
@@ -758,18 +734,36 @@ public class KerberosHelper {
   }
 
   /**
-   * Get the cluster kerberos descriptor that was registered to the
-   * cluster/:clusterName/artifacts/kerberos_descriptor endpoint if
-   * it exists.  If not, obtain the default cluster descriptor which
-   * is available from the endpoint
-   * stacks/:stackName/versions/:version/artifacts/kerberos_descriptor.
+   * Builds a composite Kerberos descriptor using the default Kerberos 
descriptor and a user-specified
+   * Kerberos descriptor, if it exists.
+   * <p/>
+   * The default Kerberos descriptor is built from the kerberos.json files in 
the stack. It can be
+   * retrieved via the 
<code>stacks/:stackName/versions/:version/artifacts/kerberos_descriptor</code>
+   * endpoint
+   * <p/>
+   * The user-specified Kerberos descriptor was registered to the
+   * <code>cluster/:clusterName/artifacts/kerberos_descriptor</code> endpoint.
+   * <p/>
+   * If the user-specified Kerberos descriptor exists, it is used to update 
the default Kerberos
+   * descriptor and the composite is returned.  If not, the default cluster 
descriptor is returned
+   * as-is.
    *
    * @param cluster cluster instance
    * @return the kerberos descriptor associated with the specified cluster
    * @throws AmbariException if unable to obtain the descriptor
    */
-  private KerberosDescriptor getClusterDescriptor(Cluster cluster) throws 
AmbariException {
-    KerberosDescriptor descriptor;
+  private KerberosDescriptor getKerberosDescriptor(Cluster cluster) throws 
AmbariException {
+    StackId stackId = cluster.getCurrentStackVersion();
+
+    // -------------------------------
+    // Get the default Kerberos descriptor from the stack, which is the same 
as the value from
+    // stacks/:stackName/versions/:version/artifacts/kerberos_descriptor
+    KerberosDescriptor defaultDescriptor = 
ambariMetaInfo.getKerberosDescriptor(stackId.getStackName(), 
stackId.getStackVersion());
+    // -------------------------------
+
+    // Get the user-supplied Kerberos descriptor from 
cluster/:clusterName/artifacts/kerberos_descriptor
+    KerberosDescriptor descriptor = null;
+
     PredicateBuilder pb = new PredicateBuilder();
     Predicate predicate = 
pb.begin().property("Artifacts/cluster_name").equals(cluster.getClusterName()).and().
         
property(ArtifactResourceProvider.ARTIFACT_NAME_PROPERTY).equals("kerberos_descriptor").
@@ -806,16 +800,39 @@ public class KerberosHelper {
 
     if (response != null && !response.isEmpty()) {
       Resource descriptorResource = response.iterator().next();
-      String descriptor_data = (String) descriptorResource.getPropertyValue(
-          ArtifactResourceProvider.ARTIFACT_DATA_PROPERTY);
+      Map<String, Map<String, Object>> propertyMap = 
descriptorResource.getPropertiesMap();
+      if (propertyMap != null) {
+        Map<String, Object> artifactData = 
propertyMap.get(ArtifactResourceProvider.ARTIFACT_DATA_PROPERTY);
+        Map<String, Object> artifactDataProperties = 
propertyMap.get(ArtifactResourceProvider.ARTIFACT_DATA_PROPERTY + 
"/properties");
+        HashMap<String, Object> data = new HashMap<String, Object>();
+
+        if (artifactData != null) {
+          data.putAll(artifactData);
+        }
 
-      descriptor = KerberosDescriptor.fromJSON(descriptor_data);
+        if (artifactDataProperties != null) {
+          data.put("properties", artifactDataProperties);
+        }
+
+        descriptor = kerberosDescriptorFactory.createInstance(data);
+      }
+    }
+    // -------------------------------
+
+    // -------------------------------
+    // Attempt to build and return a composite of the default Kerberos 
descriptor and the user-supplied
+    // Kerberos descriptor. If the default descriptor exists, overlay the 
user-supplied Kerberos
+    // descriptor on top of it (if it exists) and return the composite; else 
return the user-supplied
+    // Kerberos descriptor. If both values are null, null may be returned.
+    if (defaultDescriptor == null) {
+      return descriptor;
     } else {
-      // get default descriptor from stack
-      StackId stackId = cluster.getCurrentStackVersion();
-      descriptor = 
ambariMetaInfo.getKerberosDescriptor(stackId.getStackName(), 
stackId.getStackVersion());
+      if (descriptor != null) {
+        defaultDescriptor.update(descriptor);
+      }
+      return defaultDescriptor;
     }
-    return descriptor;
+    // -------------------------------
   }
 
 
@@ -856,33 +873,6 @@ public class KerberosHelper {
   }
 
   /**
-   * Build a composite Kerberos descriptor using the default descriptor data, 
existing cluster
-   * descriptor data (future), and the supplied descriptor updates from the 
request
-   *
-   * @param currentStackVersion the current cluster's StackId
-   * @param kerberosDescriptor  a KerberosDescriptor containing updates from 
the request payload
-   * @return a KerberosDescriptor containing existing data with requested 
changes
-   * @throws AmbariException
-   */
-  private KerberosDescriptor buildKerberosDescriptor(StackId 
currentStackVersion,
-                                                     KerberosDescriptor 
kerberosDescriptor)
-      throws AmbariException {
-    KerberosDescriptor defaultKerberosDescriptor = 
ambariMetaInfo.getKerberosDescriptor(
-        currentStackVersion.getStackName(),
-        currentStackVersion.getStackVersion()
-    );
-
-    if (defaultKerberosDescriptor == null) {
-      return kerberosDescriptor;
-    } else {
-      if (kerberosDescriptor != null) {
-        defaultKerberosDescriptor.update(kerberosDescriptor);
-      }
-      return defaultKerberosDescriptor;
-    }
-  }
-
-  /**
    * Merges configuration from a Map of configuration updates into a main 
configurations Map.  Each
    * property in the updates Map is processed to replace variables using the 
replacement Map.
    * <p/>

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
index 49b8d5d..c226823 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
@@ -52,7 +52,6 @@ import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.ConfigImpl;
 import org.apache.ambari.server.state.SecurityType;
 import org.apache.ambari.server.state.StackId;
-import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
 
 /**
  * Resource provider for cluster resources.
@@ -323,14 +322,6 @@ public class ClusterResourceProvider extends 
BaseBlueprintProcessor {
     baseUnsupported.remove("default_password");
     baseUnsupported.remove("configurations");
 
-    // Allow property Ids that start with "kerberos_descriptor/"
-    Iterator<String> iterator = baseUnsupported.iterator();
-    while (iterator.hasNext()) {
-      if (iterator.next().startsWith("kerberos_descriptor/")) {
-        iterator.remove();
-      }
-    }
-
     return checkConfigPropertyIds(baseUnsupported, "Clusters");
   }
 
@@ -368,8 +359,6 @@ public class ClusterResourceProvider extends 
BaseBlueprintProcessor {
    * @return the cluster request object
    */
   private ClusterRequest getRequest(Map<String, Object> properties) {
-    KerberosDescriptor kerberosDescriptor = new 
KerberosDescriptor(createKerberosPropertyMap(properties));
-
     SecurityType securityType;
     String requestedSecurityType = (String) 
properties.get(CLUSTER_SECURITY_TYPE_PROPERTY_ID);
     if(requestedSecurityType == null)
@@ -389,7 +378,6 @@ public class ClusterResourceProvider extends 
BaseBlueprintProcessor {
         securityType,
         (String) properties.get(CLUSTER_VERSION_PROPERTY_ID),
         null,
-        kerberosDescriptor,
         getSessionAttributes(properties));
 
     List<ConfigurationRequest> configRequests = 
getConfigurationRequests("Clusters", properties);
@@ -407,107 +395,6 @@ public class ClusterResourceProvider extends 
BaseBlueprintProcessor {
   }
 
   /**
-   * Recursively attempts to "normalize" a property value into either a single 
Object, a Map or a
-   * Collection of items depending on the type of Object that is supplied.
-   * <p/>
-   * If the supplied value is a Map, attempts to render a Map of keys to 
"normalized" values. This
-   * may yield a Map of Maps or a Map of Collections, or a Map of values.
-   * <p/>
-   * If the supplied value is a Collection, attempts to render a Collection of 
Maps, Collections, or values
-   * <p/>
-   * Else, assumes the value is a simple value
-   *
-   * @param property an Object to "normalize"
-   * @return the normalized object or the input value if it is not a Map or 
Collection.
-   */
-  private Object normalizeKerberosProperty(Object property) {
-    if (property instanceof Map) {
-      Map<?, ?> properties = (Map) property;
-      Map<String, Object> map = new HashMap<String, Object>(properties.size());
-
-      for (Map.Entry<?, ?> entry : properties.entrySet()) {
-        normalizeKerberosProperty(entry.getKey().toString(), entry.getValue(), 
map);
-      }
-
-      return map;
-    } else if (property instanceof Collection) {
-      Collection properties = (Collection) property;
-      Collection<Object> collection = new ArrayList<Object>(properties.size());
-
-      for (Object item : properties) {
-        collection.add(normalizeKerberosProperty(item));
-      }
-
-      return collection;
-    } else {
-      return property;
-    }
-  }
-
-  /**
-   * Recursively attempts to "normalize" a property value into either a single 
Object, a Map or a
-   * Collection of items; and places the result into the supplied Map under a 
specified key.
-   * <p/>
-   * See {@link #normalizeKerberosProperty(Object)} for more information 
"normalizing" a property value
-   *
-   * If the key (propertyName) indicates a hierarchy by separating names with 
a '/', the supplied map
-   * will be updated to handle the hierarchy. For example, if the propertyName 
value is "parent/child"
-   * then the map will be updated to contain an entry where the key is named 
"parent" and the value
-   * is a Map containing an entry with a name of "child" and value that is the 
normalized version of
-   * the specified value (propertyValue).
-   *
-   * @param propertyName a String declaring the name of the supplied property 
value
-   * @param propertyValue an Object containing the property value
-   * @param map a Map to store the results within
-   * @see #normalizeKerberosProperty(Object)
-   */
-  private void normalizeKerberosProperty(String propertyName, Object 
propertyValue, Map<String, Object> map) {
-    String[] keys = propertyName.split("/");
-    Map<String, Object> currentMap = map;
-
-    if (keys.length > 0) {
-      for (int i = 0; i < keys.length - 1; i++) {
-        String key = keys[i];
-
-        Object value = currentMap.get(key);
-
-        if (value instanceof Map) {
-          currentMap = (Map<String, Object>) value;
-        } else {
-          Map<String, Object> temp = new HashMap<String, Object>();
-          currentMap.put(key, temp);
-          currentMap = temp;
-        }
-      }
-
-      currentMap.put(keys[keys.length - 1], 
normalizeKerberosProperty(propertyValue));
-    }
-  }
-
-  /**
-   * Given a Map of Strings to Objects, attempts to expand all properties into 
a tree of Maps to
-   * effectively represent a Kerberos descriptor.
-   *
-   * @param properties a Map of properties to process
-   * @return a Map containing the expanded hierarchy of data
-   * @see #normalizeKerberosProperty(String, Object, java.util.Map)
-   */
-  private Map<String, Object> createKerberosPropertyMap(Map<String, Object> 
properties) {
-    Map<String, Object> kerberosPropertyMap = new HashMap<String, Object>();
-
-    if (properties != null) {
-      for (Map.Entry<String, Object> entry : properties.entrySet()) {
-        String key = entry.getKey();
-        if (key.startsWith("kerberos_descriptor/")) {
-          normalizeKerberosProperty(key.replace("kerberos_descriptor/", ""), 
entry.getValue(), kerberosPropertyMap);
-        }
-      }
-    }
-
-    return kerberosPropertyMap;
-  }
-
-  /**
    * Get the map of session attributes from the given property map.
    *
    * @param properties  the property map from the request

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
index b513de7..196ae21 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
@@ -569,7 +569,7 @@ public class HostComponentResourceProvider extends 
AbstractControllerResourcePro
 
     if (addKerberosStages) {
       // adds the necessary kerberos related stages to the request
-      kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, null, 
requestStages);
+      kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, 
requestStages);
     }
 
     return requestStages;

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
index bdf79b9..5b5b46f 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
@@ -18,8 +18,10 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.StackAccessException;
+import org.apache.ambari.server.StaticallyInject;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
@@ -34,7 +36,9 @@ import 
org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptorFactory;
 
 import java.io.File;
 import java.io.IOException;
@@ -55,6 +59,7 @@ import java.util.Set;
  * Stack artifacts are part of the stack definition and therefore can't
  * be created, updated or deleted.
  */
+@StaticallyInject
 public class StackArtifactResourceProvider extends 
AbstractControllerResourceProvider {
   /**
    * stack name
@@ -108,6 +113,18 @@ public class StackArtifactResourceProvider extends 
AbstractControllerResourcePro
 
 
   /**
+   * KerberosDescriptorFactory used to create KerberosDescriptor instances
+   */
+  @Inject
+  private static KerberosDescriptorFactory kerberosDescriptorFactory;
+
+  /**
+   * KerberosServiceDescriptorFactory used to create KerberosServiceDescriptor 
instances
+   */
+  @Inject
+  private static KerberosServiceDescriptorFactory 
kerberosServiceDescriptorFactory;
+
+  /**
    * set resource properties, pk and fk's
    */
   static {
@@ -294,7 +311,7 @@ public class StackArtifactResourceProvider extends 
AbstractControllerResourcePro
 
     String kerberosFileLocation = 
stackInfo.getKerberosDescriptorFileLocation();
     if (kerberosFileLocation != null) {
-      kerberosDescriptor = KerberosDescriptor.fromFile(new 
File(kerberosFileLocation));
+      kerberosDescriptor = kerberosDescriptorFactory.createInstance(new 
File(kerberosFileLocation));
     } else if (! serviceDescriptors.isEmpty()) {
       // service descriptors present with no stack descriptor,
       // create an empty stack descriptor to hold services
@@ -339,8 +356,8 @@ public class StackArtifactResourceProvider extends 
AbstractControllerResourcePro
     File kerberosFile = serviceInfo.getKerberosDescriptorFile();
 
     if (kerberosFile != null) {
-      KerberosServiceDescriptor serviceDescriptor = 
getMatchingServiceDescriptor(
-          KerberosServiceDescriptor.fromFile(kerberosFile), serviceName);
+      KerberosServiceDescriptor serviceDescriptor =
+          kerberosServiceDescriptorFactory.createInstance(kerberosFile, 
serviceName);
 
       if (serviceDescriptor != null) {
         return serviceDescriptor.toMap();
@@ -363,8 +380,8 @@ public class StackArtifactResourceProvider extends 
AbstractControllerResourcePro
     for (ServiceInfo service : stack.getServices()) {
       File descriptorFile = service.getKerberosDescriptorFile();
       if (descriptorFile != null) {
-        KerberosServiceDescriptor descriptor = getMatchingServiceDescriptor(
-            KerberosServiceDescriptor.fromFile(descriptorFile), 
service.getName());
+        KerberosServiceDescriptor descriptor =
+            kerberosServiceDescriptorFactory.createInstance(descriptorFile, 
service.getName());
 
         if (descriptor != null) {
           serviceDescriptors.add(descriptor);
@@ -374,28 +391,4 @@ public class StackArtifactResourceProvider extends 
AbstractControllerResourcePro
     return serviceDescriptors;
   }
 
-  /**
-   * Get the correct service descriptor from an array of service descriptors.
-   * This is necessary because in some cases, multiple stack services are 
contained in the same
-   * stack metainfo file and all point to the same kerberos descriptor.
-   * This should be fixed in the stack to only return the matching descriptor, 
not all descriptors.
-   * When/If these changes are made in the stack, this method will go away as 
only the correct descriptor
-   * will be returned for a given service.
-   *
-   * @param descriptors  array of service descriptors
-   * @param serviceName  service name
-   *
-   * @return the service descriptor which correlates to the specified service 
or null if no match is made
-   */
-  private KerberosServiceDescriptor 
getMatchingServiceDescriptor(KerberosServiceDescriptor[] descriptors,
-                                                                 String 
serviceName) {
-    KerberosServiceDescriptor match = null;
-    for (KerberosServiceDescriptor descriptor : descriptors) {
-      if (descriptor.getName().equals(serviceName)) {
-        match = descriptor;
-        break;
-      }
-    }
-    return match;
-  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java
index 89ac9d7..c80913e 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java
@@ -19,8 +19,9 @@
 
 package org.apache.ambari.server.controller.internal;
 
-import com.google.gson.Gson;
+import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.StaticallyInject;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.StackServiceRequest;
 import org.apache.ambari.server.controller.StackServiceResponse;
@@ -28,13 +29,13 @@ import org.apache.ambari.server.controller.spi.*;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptorFactory;
 
 import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
 import java.io.IOException;
 import java.util.*;
 
+@StaticallyInject
 public class StackServiceResourceProvider extends ReadOnlyResourceProvider {
 
   protected static final String SERVICE_NAME_PROPERTY_ID = 
PropertyHelper.getPropertyId(
@@ -77,6 +78,12 @@ public class StackServiceResourceProvider extends 
ReadOnlyResourceProvider {
       Arrays.asList(new String[] { STACK_NAME_PROPERTY_ID,
           STACK_VERSION_PROPERTY_ID, SERVICE_NAME_PROPERTY_ID }));
 
+  /**
+   * KerberosServiceDescriptorFactory used to create KerberosServiceDescriptor 
instances
+   */
+  @Inject
+  private static KerberosServiceDescriptorFactory 
kerberosServiceDescriptorFactory;
+
   protected StackServiceResourceProvider(Set<String> propertyIds,
       Map<Type, String> keyPropertyIds,
       AmbariManagementController managementController) {
@@ -122,7 +129,7 @@ public class StackServiceResourceProvider extends 
ReadOnlyResourceProvider {
           response.getServiceName(), requestedIds);
 
       setResourceProperty(resource, SERVICE_DISPLAY_NAME_PROPERTY_ID,
-              response.getServiceDisplayName(), requestedIds);
+          response.getServiceDisplayName(), requestedIds);
 
       setResourceProperty(resource, USER_NAME_PROPERTY_ID,
           response.getUserName(), requestedIds);
@@ -135,7 +142,7 @@ public class StackServiceResourceProvider extends 
ReadOnlyResourceProvider {
 
       setResourceProperty(resource, CONFIG_TYPES,
           response.getConfigTypes(), requestedIds);
-      
+
       setResourceProperty(resource, REQUIRED_SERVICES_ID,
           response.getRequiredServices(), requestedIds);
 
@@ -148,25 +155,15 @@ public class StackServiceResourceProvider extends 
ReadOnlyResourceProvider {
       // TODO (rlevas): Convert this to an official resource
       File kerberosDescriptorFile = response.getKerberosDescriptorFile();
       if (kerberosDescriptorFile != null) {
-        KerberosServiceDescriptor[] descriptors;
+        KerberosServiceDescriptor descriptor;
         try {
-          descriptors = 
KerberosServiceDescriptor.fromFile(kerberosDescriptorFile);
+          descriptor = 
kerberosServiceDescriptorFactory.createInstance(kerberosDescriptorFile, 
response.getServiceName());
         } catch (IOException e) {
           throw new SystemException("Failed to parse the service's Kerberos 
descriptor", e);
         }
 
-        if (descriptors != null) {
-          String serviceName = response.getServiceName();
-
-          // Iterate over the KerberosServiceDescriptors to find the one for 
this service since
-          // Kerberos descriptor files can contain details about more than one 
service
-          for(KerberosServiceDescriptor descriptor:descriptors) {
-            if(serviceName.equals(descriptor.getName())) {
-              setResourceProperty(resource, KERBEROS_DESCRIPTOR_PROPERTY_ID,
-                  descriptor.toMap(), requestedIds);
-              break; // Stop looping, this was the service we are looking for.
-            }
-          }
+        if (descriptor != null) {
+          setResourceProperty(resource, KERBEROS_DESCRIPTOR_PROPERTY_ID, 
descriptor.toMap(), requestedIds);
         }
       }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
index 717be2f..ddb9301 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
@@ -28,7 +28,9 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.StaticallyInject;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.StackVersionRequest;
 import org.apache.ambari.server.controller.StackVersionResponse;
@@ -42,8 +44,11 @@ import 
org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptorFactory;
 
+@StaticallyInject
 public class StackVersionResourceProvider extends ReadOnlyResourceProvider {
 
   public static final String STACK_VERSION_PROPERTY_ID     = 
PropertyHelper.getPropertyId("Versions", "stack_version");
@@ -58,6 +63,18 @@ public class StackVersionResourceProvider extends 
ReadOnlyResourceProvider {
   private static Set<String> pkPropertyIds = new HashSet<String>(
       Arrays.asList(new String[] { STACK_NAME_PROPERTY_ID, 
STACK_VERSION_PROPERTY_ID }));
 
+  /**
+   * KerberosDescriptorFactory used to create KerberosDescriptor instances
+   */
+  @Inject
+  private static KerberosDescriptorFactory kerberosDescriptorFactory;
+
+  /**
+   * KerberosServiceDescriptorFactory used to create KerberosServiceDescriptor 
instances
+   */
+  @Inject
+  private static KerberosServiceDescriptorFactory 
kerberosServiceDescriptorFactory;
+
   protected StackVersionResourceProvider(Set<String> propertyIds,
       Map<Type, String> keyPropertyIds,
       AmbariManagementController managementController) {
@@ -149,7 +166,7 @@ public class StackVersionResourceProvider extends 
ReadOnlyResourceProvider {
     // Process the stack-level Kerberos descriptor file
     File stackKerberosDescriptorFile = 
stackVersionResponse.getStackKerberosDescriptorFile();
     if (stackKerberosDescriptorFile != null) {
-      kerberosDescriptor = 
KerberosDescriptor.fromFile(stackKerberosDescriptorFile);
+      kerberosDescriptor = 
kerberosDescriptorFactory.createInstance(stackKerberosDescriptorFile);
     }
 
     // Process the service-level Kerberos descriptor files
@@ -164,7 +181,7 @@ public class StackVersionResourceProvider extends 
ReadOnlyResourceProvider {
       // For each service-level Kerberos descriptor file, parse into an array 
of KerberosServiceDescriptors
       // and then append each to the KerberosDescriptor hierarchy.
       for (File file : serviceDescriptorFiles) {
-        KerberosServiceDescriptor[] serviceDescriptors = 
KerberosServiceDescriptor.fromFile(file);
+        KerberosServiceDescriptor[] serviceDescriptors = 
kerberosServiceDescriptorFactory.createInstances(file);
 
         if (serviceDescriptors != null) {
           for (KerberosServiceDescriptor serviceDescriptor : 
serviceDescriptors) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
index 41d100b..b49fec1 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
@@ -213,52 +213,6 @@ public abstract class AbstractKerberosDescriptor {
   }
 
   /**
-   * Parses a file containing JSON-formatted text into a (generic) Map.
-   *
-   * @param file a File containing the JSON-formatted text to parse
-   * @return a Map of the data
-   * @throws FileNotFoundException if the specified File does not point to a 
valid file
-   * @throws IOException           if the specified File is not a readable file
-   * @throws AmbariException       if the specified File does not contain 
valid JSON data
-   */
-  protected static Map<String, Object> parseFile(File file) throws IOException 
{
-    if (file == null) {
-      return Collections.emptyMap();
-    } else if (!file.isFile() || !file.canRead()) {
-      throw new IOException(String.format("%s is not a readable file", 
file.getAbsolutePath()));
-    } else {
-      try {
-        return new Gson().fromJson(new FileReader(file),
-            new TypeToken<Map<String, Object>>() {
-            }.getType());
-      } catch (JsonSyntaxException e) {
-        throw new AmbariException(String.format("Failed to parse 
JSON-formatted file: %s", file.getAbsolutePath()), e);
-      }
-    }
-  }
-
-  /**
-   * Parses a JSON-formatted String into a (generic) Map.
-   *
-   * @param json a String containing the JSON-formatted text to parse
-   * @return a Map of the data
-   * @throws AmbariException if an error occurs while parsing the 
JSON-formatted String
-   */
-  protected static Map<String, Object> parseJSON(String json) throws 
AmbariException {
-    if ((json == null) || json.isEmpty()) {
-      return Collections.emptyMap();
-    } else {
-      try {
-        return new Gson().fromJson(json,
-            new TypeToken<Map<String, Object>>() {
-            }.getType());
-      } catch (JsonSyntaxException e) {
-        throw new AmbariException("Failed to parse JSON-formatted string", e);
-      }
-    }
-  }
-
-  /**
    * Safely retrieves the requested value from the supplied Map
    *
    * @param map a Map containing the relevant data

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorFactory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorFactory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorFactory.java
new file mode 100644
index 0000000..9b438ed
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorFactory.java
@@ -0,0 +1,83 @@
+/*
+ * 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.ambari.server.state.kerberos;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
+import org.apache.ambari.server.AmbariException;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * AbstractKerberosDescriptorFactory is an abstract class containing common 
functionality for
+ * Kerberos descriptor factory classes.
+ */
+abstract class AbstractKerberosDescriptorFactory {
+
+  /**
+   * Parses a file containing JSON-formatted text into a (generic) Map.
+   *
+   * @param file a File containing the JSON-formatted text to parse
+   * @return a Map of the data
+   * @throws java.io.FileNotFoundException            if the specified File 
does not point to a valid file
+   * @throws java.io.IOException                      if the specified File is 
not a readable file
+   * @throws org.apache.ambari.server.AmbariException if the specified File 
does not contain valid JSON data
+   */
+  protected Map<String, Object> parseFile(File file) throws IOException {
+    if (file == null) {
+      return Collections.emptyMap();
+    } else if (!file.isFile() || !file.canRead()) {
+      throw new IOException(String.format("%s is not a readable file", 
file.getAbsolutePath()));
+    } else {
+      try {
+        return new Gson().fromJson(new FileReader(file),
+            new TypeToken<Map<String, Object>>() {
+            }.getType());
+      } catch (JsonSyntaxException e) {
+        throw new AmbariException(String.format("Failed to parse 
JSON-formatted file: %s", file.getAbsolutePath()), e);
+      }
+    }
+  }
+
+  /**
+   * Parses a JSON-formatted String into a (generic) Map.
+   *
+   * @param json a String containing the JSON-formatted text to parse
+   * @return a Map of the data
+   * @throws AmbariException if an error occurs while parsing the 
JSON-formatted String
+   */
+  protected Map<String, Object> parseJSON(String json) throws AmbariException {
+    if ((json == null) || json.isEmpty()) {
+      return Collections.emptyMap();
+    } else {
+      try {
+        return new Gson().fromJson(json,
+            new TypeToken<Map<String, Object>>() {
+            }.getType());
+      } catch (JsonSyntaxException e) {
+        throw new AmbariException("Failed to parse JSON-formatted string", e);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
index 0c05859..791b0e6 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
@@ -100,38 +100,6 @@ public class KerberosDescriptor extends 
AbstractKerberosDescriptorContainer {
 
 
   /**
-   * Given a file containing JSON-formatted text, attempts to create a 
KerberosDescriptor
-   *
-   * @param file a File pointing to the file containing JSON-formatted text
-   * @return a newly created KerberosDescriptor
-   * @throws FileNotFoundException if the specified File does not point to a 
valid file
-   * @throws IOException           if the specified File is not a readable file
-   * @throws AmbariException       if the specified File does not contain 
valid JSON data
-   */
-  public static KerberosDescriptor fromFile(File file) throws IOException {
-    try {
-      return new KerberosDescriptor(parseFile(file));
-    } catch (AmbariException e) {
-      throw new AmbariException(String.format("An error occurred processing 
the JSON-formatted file: %s", file.getAbsolutePath()), e);
-    }
-  }
-
-  /**
-   * Given a String containing JSON-formatted text, attempts to create a 
KerberosDescriptor
-   *
-   * @param json a File pointing to the file containing JSON-formatted text
-   * @return a newly created KerberosDescriptor
-   * @throws AmbariException if an error occurs while processing the 
JSON-formatted String
-   */
-  public static KerberosDescriptor fromJSON(String json) throws 
AmbariException {
-    try {
-      return new KerberosDescriptor(parseJSON(json));
-    } catch (AmbariException e) {
-      throw new AmbariException("An error occurred processing the 
JSON-formatted string", e);
-    }
-  }
-
-  /**
    * Creates an empty KerberosDescriptor
    */
   public KerberosDescriptor() {
@@ -147,7 +115,7 @@ public class KerberosDescriptor extends 
AbstractKerberosDescriptorContainer {
    * @param data a Map of values use to populate the data for the new instance
    * @see org.apache.ambari.server.state.kerberos.KerberosDescriptor
    */
-  public KerberosDescriptor(Map<?, ?> data) {
+  KerberosDescriptor(Map<?, ?> data) {
     super(data);
 
     if (data != null) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorFactory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorFactory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorFactory.java
new file mode 100644
index 0000000..6c021f3
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorFactory.java
@@ -0,0 +1,80 @@
+/*
+ * 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.ambari.server.state.kerberos;
+
+import com.google.inject.Singleton;
+import org.apache.ambari.server.AmbariException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * KerberosDescriptorFactory is a factory class used to create 
KerberosDescriptor instances using
+ * various sources of data.
+ */
+@Singleton
+public class KerberosDescriptorFactory extends 
AbstractKerberosDescriptorFactory {
+
+  /**
+   * Given a file containing JSON-formatted text, attempts to create a 
KerberosDescriptor
+   *
+   * @param file a File pointing to the file containing JSON-formatted text
+   * @return a newly created KerberosDescriptor
+   * @throws java.io.FileNotFoundException            if the specified File 
does not point to a valid file
+   * @throws java.io.IOException                      if the specified File is 
not a readable file
+   * @throws org.apache.ambari.server.AmbariException if the specified File 
does not contain valid JSON data
+   */
+  public KerberosDescriptor createInstance(File file) throws IOException {
+    try {
+      return new KerberosDescriptor(parseFile(file));
+    } catch (AmbariException e) {
+      throw new AmbariException(String.format("An error occurred processing 
the JSON-formatted file: %s", file.getAbsolutePath()), e);
+    }
+  }
+
+  /**
+   * Given a String containing JSON-formatted text, attempts to create a 
KerberosDescriptor
+   *
+   * @param json a File pointing to the file containing JSON-formatted text
+   * @return a newly created KerberosDescriptor
+   * @throws AmbariException if an error occurs while processing the 
JSON-formatted String
+   */
+  public KerberosDescriptor createInstance(String json) throws AmbariException 
{
+    try {
+      return new KerberosDescriptor(parseJSON(json));
+    } catch (AmbariException e) {
+      throw new AmbariException("An error occurred processing the 
JSON-formatted string", e);
+    }
+  }
+
+  /**
+   * Creates a new KerberosDescriptor
+   * <p/>
+   * See {@link org.apache.ambari.server.state.kerberos.KerberosDescriptor} 
for the JSON
+   * Schema that may be used to generate this map.
+   *
+   * @param map a Map of values use to populate the data for the new instance
+   * @see org.apache.ambari.server.state.kerberos.KerberosDescriptor
+   */
+  public KerberosDescriptor createInstance(Map<?, ?> map) {
+    return new KerberosDescriptor(map);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
index 1f5e94f..9eeb802 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
@@ -111,108 +111,6 @@ public class KerberosServiceDescriptor extends 
AbstractKerberosDescriptorContain
   private Map<String, KerberosComponentDescriptor> components;
 
   /**
-   * Creates a Collection of KerberosServiceDescriptors parsed from a 
JSON-formatted file.
-   * <p/>
-   * The file is expected to be formatted as follows:
-   * <pre>
-   * {
-   *    "services" : [
-   *      ... (zero or more service descriptor blocks) ...
-   *    ]
-   * }
-   * </pre>
-   *
-   * @param file a JSON-formatted file containing this service-level 
descriptor data
-   * @return an array of KerberosServiceDescriptor objects
-   * @throws FileNotFoundException if the specified File does not point to a 
valid file
-   * @throws IOException           if the specified File is not a readable file
-   * @throws AmbariException       if the specified File does not contain 
valid JSON data
-   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
-   */
-  public static KerberosServiceDescriptor[] fromFile(File file) throws 
IOException {
-    try {
-      return fromMap(parseFile(file));
-    } catch (AmbariException e) {
-      throw new AmbariException(String.format("An error occurred processing 
the JSON-formatted file: %s", file.getAbsolutePath()), e);
-    }
-  }
-
-  /**
-   * Creates a Collection of KerberosServiceDescriptors parsed from a 
JSON-formatted String.
-   * <p/>
-   * The String is expected to be formatted as follows:
-   * <pre>
-   * {
-   *    "services" : [
-   *      ... (zero or more service descriptor blocks) ...
-   *    ]
-   * }
-   * </pre>
-   *
-   * @param json a JSON-formatted String containing this service-level 
descriptor data
-   * @return an array of KerberosServiceDescriptor objects
-   * @throws AmbariException if an error occurs while processing the 
JSON-formatted String
-   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
-   */
-  public static KerberosServiceDescriptor[] fromJSON(String json) throws 
AmbariException {
-    try {
-      return fromMap(parseJSON(json));
-    } catch (AmbariException e) {
-      throw new AmbariException("An error occurred processing the 
JSON-formatted string", e);
-    }
-  }
-
-  /**
-   * Creates a Collection of KerberosServiceDescriptors parsed from a Map of 
data.
-   * <p/>
-   * The Map is expected to be formatted as follows:
-   * <pre>
-   * "services" => [
-   *   ... (zero or more Maps containing service descriptor data) ...
-   * ]
-   * </pre>
-   *
-   * @param map a Map containing this service-level descriptor data
-   * @return an array of KerberosServiceDescriptor objects
-   * @throws org.apache.ambari.server.AmbariException if an error occurs while 
processing the Map
-   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
-   */
-  public static KerberosServiceDescriptor[] fromMap(Map<String, Object> map) 
throws AmbariException {
-    ArrayList<KerberosServiceDescriptor> descriptors = new 
ArrayList<KerberosServiceDescriptor>();
-
-    if (map != null) {
-      Object servicesData = map.get("services");
-
-      if (servicesData == null) {
-        throw new AmbariException("Missing top-level \"services\" property in 
service-level Kerberos descriptor data");
-      } else if (servicesData instanceof Collection) {
-        for (Object serviceData : (Collection) servicesData) {
-          if (serviceData instanceof Map) {
-            descriptors.add(new KerberosServiceDescriptor((Map) serviceData));
-          }
-        }
-      } else {
-        throw new AmbariException(String.format("Unexpected top-level 
\"services\" type in service-level Kerberos descriptor data: %s",
-            servicesData.getClass().getName()));
-      }
-    }
-
-    return descriptors.toArray(new 
KerberosServiceDescriptor[descriptors.size()]);
-  }
-
-  /**
-   * Creates a new KerberosServiceDescriptor
-   *
-   * @param name a String declaring this service's name
-   * @param json a JSON-formatted String containing this service's descriptor 
data
-   * @throws AmbariException if an error occurs while parsing the 
JSON-formatted String
-   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
-   */
-  public static KerberosServiceDescriptor fromJSON(String name, String json) 
throws AmbariException {
-    return new KerberosServiceDescriptor(name, parseJSON(json));
-  }
-
-  /**
    * Creates a new KerberosServiceDescriptor
    * <p/>
    * See {@link 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor} for the JSON
@@ -221,7 +119,7 @@ public class KerberosServiceDescriptor extends 
AbstractKerberosDescriptorContain
    * @param data a Map of values use to populate the data for the new instance
    * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
    */
-  public KerberosServiceDescriptor(Map<?, ?> data) {
+  KerberosServiceDescriptor(Map<?, ?> data) {
     // The name for this KerberosServiceDescriptor is stored in the "name" 
entry in the map
     // This is not automatically set by the super classes.
     this(getStringValue(data, "name"), data);
@@ -237,7 +135,7 @@ public class KerberosServiceDescriptor extends 
AbstractKerberosDescriptorContain
    * @param data a Map of values use to populate the data for the new instance
    * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
    */
-  public KerberosServiceDescriptor(String name, Map<?, ?> data) {
+  KerberosServiceDescriptor(String name, Map<?, ?> data) {
     super(data);
 
     // This is not automatically set by the super classes.

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptorFactory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptorFactory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptorFactory.java
new file mode 100644
index 0000000..a5e199a
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptorFactory.java
@@ -0,0 +1,232 @@
+/*
+ * 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.ambari.server.state.kerberos;
+
+import com.google.inject.Singleton;
+import org.apache.ambari.server.AmbariException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * KerberosServiceDescriptorFactory is a factory class used to create 
KerberosServiceDescriptor
+ * instances using various sources of data.
+ */
+@Singleton
+public class KerberosServiceDescriptorFactory extends 
AbstractKerberosDescriptorFactory {
+
+
+  /**
+   * Creates a Collection of KerberosServiceDescriptors parsed from a 
JSON-formatted file.
+   * <p/>
+   * The file is expected to be formatted as follows:
+   * <pre>
+   * {
+   *    "services" : [
+   *      ... (zero or more service descriptor blocks) ...
+   *    ]
+   * }
+   * </pre>
+   *
+   * @param file a JSON-formatted file containing this service-level 
descriptor data
+   * @return an array of KerberosServiceDescriptor objects
+   * @throws java.io.FileNotFoundException if the specified File does not 
point to a valid file
+   * @throws IOException                   if the specified File is not a 
readable file
+   * @throws AmbariException               if the specified File does not 
contain valid JSON data
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public KerberosServiceDescriptor[] createInstances(File file) throws 
IOException {
+    try {
+      return createInstances(parseFile(file));
+    } catch (AmbariException e) {
+      throw new AmbariException(String.format("An error occurred processing 
the JSON-formatted file: %s", file.getAbsolutePath()), e);
+    }
+  }
+
+  /**
+   * Creates a Collection of KerberosServiceDescriptors parsed from a 
JSON-formatted String.
+   * <p/>
+   * The String is expected to be formatted as follows:
+   * <pre>
+   * {
+   *    "services" : [
+   *      ... (zero or more service descriptor blocks) ...
+   *    ]
+   * }
+   * </pre>
+   *
+   * @param json a JSON-formatted String containing this service-level 
descriptor data
+   * @return an array of KerberosServiceDescriptor objects
+   * @throws AmbariException if an error occurs while processing the 
JSON-formatted String
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public KerberosServiceDescriptor[] createInstances(String json) throws 
AmbariException {
+    try {
+      return createInstances(parseJSON(json));
+    } catch (AmbariException e) {
+      throw new AmbariException("An error occurred processing the 
JSON-formatted string", e);
+    }
+  }
+
+  /**
+   * Creates a Collection of KerberosServiceDescriptors parsed from a Map of 
data.
+   * <p/>
+   * The Map is expected to be formatted as follows:
+   * <pre>
+   * "services" => [
+   *   ... (zero or more Maps containing service descriptor data) ...
+   * ]
+   * </pre>
+   *
+   * @param map a Map containing this service-level descriptor data
+   * @return an array of KerberosServiceDescriptor objects
+   * @throws org.apache.ambari.server.AmbariException if an error occurs while 
processing the Map
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public KerberosServiceDescriptor[] createInstances(Map<String, Object> map) 
throws AmbariException {
+    ArrayList<KerberosServiceDescriptor> descriptors = new 
ArrayList<KerberosServiceDescriptor>();
+
+    if (map != null) {
+      Object servicesData = map.get("services");
+
+      if (servicesData == null) {
+        throw new AmbariException("Missing top-level \"services\" property in 
service-level Kerberos descriptor data");
+      } else if (servicesData instanceof Collection) {
+        for (Object serviceData : (Collection) servicesData) {
+          if (serviceData instanceof Map) {
+            descriptors.add(new KerberosServiceDescriptor((Map) serviceData));
+          }
+        }
+      } else {
+        throw new AmbariException(String.format("Unexpected top-level 
\"services\" type in service-level Kerberos descriptor data: %s",
+            servicesData.getClass().getName()));
+      }
+    }
+
+    return descriptors.toArray(new 
KerberosServiceDescriptor[descriptors.size()]);
+  }
+
+  /**
+   * Creates the requested KerberosServiceDescriptor parsed from a 
JSON-formatted file.
+   * <p/>
+   * The file is expected to be formatted as follows:
+   * <pre>
+   * {
+   *    "services" : [
+   *      ... (zero or more service descriptor blocks) ...
+   *    ]
+   * }
+   * </pre>
+   * <p/>
+   * Because of this one or more services may exist.  This method parses 
through the definitions to
+   * return the a KerberosServiceDescriptor for the requested service
+   *
+   * @param file a JSON-formatted file containing this service-level 
descriptor data
+   * @param name a String containing the nae of the desired service
+   * @return a KerberosServiceDescriptor object or null if a descriptor for 
the named service is not
+   * available
+   * @throws java.io.FileNotFoundException if the specified File does not 
point to a valid file
+   * @throws IOException                   if the specified File is not a 
readable file
+   * @throws AmbariException               if the specified File does not 
contain valid JSON data
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public KerberosServiceDescriptor createInstance(File file, String name) 
throws IOException {
+    try {
+      return createInstance(parseFile(file), name);
+    } catch (AmbariException e) {
+      throw new AmbariException(String.format("An error occurred processing 
the JSON-formatted file: %s", file.getAbsolutePath()), e);
+    }
+  }
+
+  /**
+   * Creates the requested KerberosServiceDescriptor parsed from a Map of data.
+   * <p/>
+   * The Map is expected to be formatted as follows:
+   * <pre>
+   * "services" => [
+   *   ... (zero or more Maps containing service descriptor data) ...
+   * ]
+   * </pre>
+   * <p/>
+   * Because of this one or more services may exist.  This method parses 
through the definitions to
+   * return the a KerberosServiceDescriptor for the requested service
+   *
+   * @param map  a Map containing this service-level descriptor data
+   * @param name a String containing the nae of the desired service
+   * @return a KerberosServiceDescriptor object or null if a descriptor for 
the named service is not
+   * available
+   * @throws org.apache.ambari.server.AmbariException if an error occurs while 
processing the Map
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public KerberosServiceDescriptor createInstance(Map<String, Object> map, 
String name) throws AmbariException {
+    KerberosServiceDescriptor descriptor = null;
+
+    if ((map != null) && (name != null)) {
+      Object servicesData = map.get("services");
+
+      if (servicesData == null) {
+        throw new AmbariException("Missing top-level \"services\" property in 
service-level Kerberos descriptor data");
+      } else if (servicesData instanceof Collection) {
+        for (Object serviceData : (Collection) servicesData) {
+          if (serviceData instanceof Map) {
+            Map<?, ?> serviceDataMap = (Map<?, ?>) serviceData;
+
+            if (name.equalsIgnoreCase((String) serviceDataMap.get("name"))) {
+              descriptor = new KerberosServiceDescriptor(serviceDataMap);
+              break;
+            }
+          }
+        }
+      } else {
+        throw new AmbariException(String.format("Unexpected top-level 
\"services\" type in service-level Kerberos descriptor data: %s",
+            servicesData.getClass().getName()));
+      }
+    }
+
+    return descriptor;
+  }
+
+
+  /**
+   * Creates a new KerberosServiceDescriptor
+   *
+   * @param name a String declaring this service's name
+   * @param json a JSON-formatted String containing this service's descriptor 
data
+   * @throws AmbariException if an error occurs while parsing the 
JSON-formatted String
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public KerberosServiceDescriptor createInstance(String name, String json) 
throws AmbariException {
+    return new KerberosServiceDescriptor(name, parseJSON(json));
+  }
+
+  /**
+   * Creates a new KerberosServiceDescriptor
+   *
+   * @param name a String declaring this service's name
+   * @param map  a Map of values use to populate the data for the new instance
+   * @throws AmbariException if an error occurs while parsing the 
JSON-formatted String
+   * @see org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor
+   */
+  public KerberosServiceDescriptor createInstance(String name, Map<?, ?> map) 
throws AmbariException {
+    return new KerberosServiceDescriptor(name, map);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d6c389c1/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
index c0ff4a6..7b0d80c 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
@@ -77,6 +77,8 @@ import org.apache.ambari.server.state.alert.PortSource;
 import org.apache.ambari.server.state.alert.Reporting;
 import org.apache.ambari.server.state.alert.Source;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
+import 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptorFactory;
 import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.commons.io.FileUtils;
@@ -1862,6 +1864,18 @@ public class AmbariMetaInfoTest {
       f.setAccessible(true);
       f.set(this, ambariEventPublisher);
 
+      //KerberosDescriptorFactory
+      KerberosDescriptorFactory kerberosDescriptorFactory = new 
KerberosDescriptorFactory();
+      f = c.getDeclaredField("kerberosDescriptorFactory");
+      f.setAccessible(true);
+      f.set(this, kerberosDescriptorFactory);
+
+      //KerberosServiceDescriptorFactory
+      KerberosServiceDescriptorFactory kerberosServiceDescriptorFactory = new 
KerberosServiceDescriptorFactory();
+      f = c.getDeclaredField("kerberosServiceDescriptorFactory");
+      f.setAccessible(true);
+      f.set(this, kerberosServiceDescriptorFactory);
+
       //OSFamily
       Configuration config = createNiceMock(Configuration.class);
       if (System.getProperty("os.name").contains("Windows")) {

Reply via email to