Преглед на файлове

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

Robert Levas преди 10 години
родител
ревизия
d6c389c115
променени са 24 файла, в които са добавени 643 реда и са изтрити 602 реда
  1. 16 2
      ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
  2. 3 4
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
  3. 2 28
      ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
  4. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
  5. 80 90
      ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
  6. 0 113
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
  7. 1 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java
  8. 22 29
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackArtifactResourceProvider.java
  9. 16 19
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceResourceProvider.java
  10. 19 2
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
  11. 0 46
      ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
  12. 83 0
      ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorFactory.java
  13. 1 33
      ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
  14. 80 0
      ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorFactory.java
  15. 2 104
      ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
  16. 232 0
      ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptorFactory.java
  17. 14 0
      ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
  18. 3 53
      ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
  19. 39 61
      ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
  20. 1 2
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostComponentResourceProviderTest.java
  21. 6 4
      ambari-server/src/test/java/org/apache/ambari/server/stack/KerberosDescriptorTest.java
  22. 6 1
      ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java
  23. 5 4
      ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
  24. 8 6
      ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptorTest.java

+ 16 - 2
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);

+ 3 - 4
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(

+ 2 - 28
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;
@@ -51,11 +50,6 @@ public class ClusterRequest {
 
   private ServiceConfigVersionRequest serviceConfigVersionRequest = null;
 
-  /**
-   * A KerberosDescriptor parsed from the request payload.
-   */
-  private KerberosDescriptor kerberosDescriptor;
-
   /**
    * The cluster session attributes.
    */
@@ -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();

+ 4 - 0
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);

+ 80 - 90
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.
@@ -156,21 +160,6 @@ public class KerberosHelper {
   private static ClusterController clusterController = null;
 
 
-  /**
-   * 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/>
@@ -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;
+    // -------------------------------
   }
 
 
@@ -855,33 +872,6 @@ public class KerberosHelper {
     return directory;
   }
 
-  /**
-   * 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.

+ 0 - 113
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);
@@ -406,107 +394,6 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
     return cr;
   }
 
-  /**
-   * 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.
    *

+ 1 - 1
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;

+ 22 - 29
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
@@ -107,6 +112,18 @@ public class StackArtifactResourceProvider extends AbstractControllerResourcePro
   public static final String KERBEROS_DESCRIPTOR_NAME = "kerberos_descriptor";
 
 
+  /**
+   * 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
    */
@@ -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;
-  }
 }

+ 16 - 19
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);
         }
       }
 

+ 19 - 2
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) {

+ 0 - 46
ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java

@@ -212,52 +212,6 @@ public abstract class AbstractKerberosDescriptor {
     return false;
   }
 
-  /**
-   * 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
    *

+ 83 - 0
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);
+      }
+    }
+  }
+}

+ 1 - 33
ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java

@@ -99,38 +99,6 @@ public class KerberosDescriptor extends AbstractKerberosDescriptorContainer {
   private Map<String, KerberosServiceDescriptor> services = null;
 
 
-  /**
-   * 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
    */
@@ -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) {

+ 80 - 0
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);
+  }
+
+}

+ 2 - 104
ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java

@@ -110,108 +110,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/>
@@ -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.

+ 232 - 0
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);
+  }
+}

+ 14 - 0
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")) {

+ 3 - 53
ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java

@@ -55,7 +55,6 @@ import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.ServiceOsSpecific;
 import org.apache.ambari.server.state.StackId;
-import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
 import org.easymock.Capture;
 import org.junit.Before;
 import org.junit.Test;
@@ -535,55 +534,6 @@ public class AmbariManagementControllerImplTest {
     verify(actionManager, cluster, clusters, injector, clusterRequest, sessionManager);
   }
 
-  /**
-   * Ensure that when the appropriate request directives are set, KerberosHelper#executeCustomOperations
-   * is invoked
-   */
-  @Test
-  public void testUpdateClustersKerberosCustomOperationsInvoked() throws Exception {
-    // member state mocks
-    Capture<AmbariManagementController> controllerCapture = new Capture<AmbariManagementController>();
-    Injector injector = createStrictMock(Injector.class);
-    Cluster cluster = createNiceMock(Cluster.class);
-    ActionManager actionManager = createNiceMock(ActionManager.class);
-    ClusterRequest clusterRequest = createNiceMock(ClusterRequest.class);
-
-    // requests
-    Set<ClusterRequest> requests = Collections.singleton(clusterRequest);
-
-    // request properties (aka directives)
-    Map<String, String> requestProperties = Collections.singletonMap("regenerate_keytabs", "true");
-
-    KerberosHelper kerberosHelper = createMockBuilder(KerberosHelper.class)
-    .addMockedMethod("executeCustomOperations", Cluster.class, KerberosDescriptor.class, Map.class, RequestStageContainer.class)
-    .createStrictMock();
-
-    // expectations
-    injector.injectMembers(capture(controllerCapture));
-    expect(injector.getInstance(Gson.class)).andReturn(null);
-    expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null);
-    expect(injector.getInstance(KerberosHelper.class)).andReturn(kerberosHelper);
-    expect(clusterRequest.getClusterId()).andReturn(1L).times(6);
-    expect(clusterRequest.getSecurityType()).andReturn(SecurityType.KERBEROS).anyTimes();
-    expect(clusters.getClusterById(1L)).andReturn(cluster).times(2);
-    expect(cluster.getClusterName()).andReturn("cluster").times(2);
-
-    expect(kerberosHelper.executeCustomOperations(cluster, null, requestProperties, null))
-        .andReturn(null)
-        .once();
-
-    // replay mocks
-    replay(actionManager, cluster, clusters, injector, clusterRequest, sessionManager, kerberosHelper);
-
-    // test
-    AmbariManagementController controller = new AmbariManagementControllerImpl(actionManager, clusters, injector);
-    controller.updateClusters(requests, requestProperties);
-
-    // assert and verify
-    assertSame(controller, controllerCapture.getValue());
-    verify(actionManager, cluster, clusters, injector, clusterRequest, sessionManager, kerberosHelper);
-  }
-
   /**
    * Ensure that when the cluster is updated KerberosHandler.toggleKerberos is not invoked unless
    * the security type is altered
@@ -659,7 +609,7 @@ public class AmbariManagementControllerImplTest {
     expect(kerberosHelper.shouldExecuteCustomOperations(SecurityType.KERBEROS, null))
         .andReturn(false)
         .once();
-    expect(kerberosHelper.toggleKerberos(anyObject(Cluster.class), anyObject(SecurityType.class), anyObject(KerberosDescriptor.class), anyObject(RequestStageContainer.class)))
+    expect(kerberosHelper.toggleKerberos(anyObject(Cluster.class), anyObject(SecurityType.class), anyObject(RequestStageContainer.class)))
         .andReturn(null)
         .once();
 
@@ -709,7 +659,7 @@ public class AmbariManagementControllerImplTest {
     expect(kerberosHelper.shouldExecuteCustomOperations(SecurityType.NONE, null))
         .andReturn(false)
         .once();
-    expect(kerberosHelper.toggleKerberos(anyObject(Cluster.class), anyObject(SecurityType.class), anyObject(KerberosDescriptor.class), anyObject(RequestStageContainer.class)))
+    expect(kerberosHelper.toggleKerberos(anyObject(Cluster.class), anyObject(SecurityType.class), anyObject(RequestStageContainer.class)))
         .andReturn(null)
         .once();
 
@@ -768,7 +718,7 @@ public class AmbariManagementControllerImplTest {
     expect(kerberosHelper.shouldExecuteCustomOperations(SecurityType.NONE, null))
         .andReturn(false)
         .once();
-    expect(kerberosHelper.toggleKerberos(anyObject(Cluster.class), anyObject(SecurityType.class), anyObject(KerberosDescriptor.class), anyObject(RequestStageContainer.class)))
+    expect(kerberosHelper.toggleKerberos(anyObject(Cluster.class), anyObject(SecurityType.class), anyObject(RequestStageContainer.class)))
         .andThrow(new IllegalArgumentException("bad args!"))
         .once();
 

+ 39 - 61
ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java

@@ -62,6 +62,7 @@ import org.apache.ambari.server.state.cluster.ClustersImpl;
 import org.apache.ambari.server.state.host.HostFactory;
 import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
 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;
@@ -69,14 +70,11 @@ import org.apache.ambari.server.state.kerberos.KerberosPrincipalType;
 import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
 import org.apache.ambari.server.state.stack.OsFamily;
 import org.easymock.Capture;
+import org.easymock.EasyMockSupport;
 import org.easymock.IAnswer;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
 import javax.persistence.EntityManager;
 
@@ -94,27 +92,18 @@ import static org.easymock.EasyMock.anyLong;
 import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.powermock.api.easymock.PowerMock.createMock;
-import static org.powermock.api.easymock.PowerMock.createNiceMock;
-import static org.powermock.api.easymock.PowerMock.createStrictMock;
-import static org.powermock.api.easymock.PowerMock.expectLastCall;
-import static org.powermock.api.easymock.PowerMock.mockStatic;
-import static org.powermock.api.easymock.PowerMock.replay;
-import static org.powermock.api.easymock.PowerMock.replayAll;
-import static org.powermock.api.easymock.PowerMock.reset;
-import static org.powermock.api.easymock.PowerMock.verify;
-import static org.powermock.api.easymock.PowerMock.verifyAll;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(KerberosDescriptor.class)
-@PowerMockIgnore({"javax.crypto.*", "org.apache.log4j.*"})
-@SuppressWarnings("unchecked")
-public class KerberosHelperTest {
+
+public class KerberosHelperTest extends EasyMockSupport {
 
   private static Injector injector;
   private final ClusterController clusterController = createStrictMock(ClusterController.class);
+  private final KerberosDescriptorFactory kerberosDescriptorFactory = createStrictMock(KerberosDescriptorFactory.class);
   private final AmbariMetaInfo metaInfo = createNiceMock(AmbariMetaInfo.class);
 
   @Before
@@ -181,6 +170,7 @@ public class KerberosHelperTest {
         bind(ConfigHelper.class).toInstance(createNiceMock(ConfigHelper.class));
         bind(KerberosOperationHandlerFactory.class).toInstance(kerberosOperationHandlerFactory);
         bind(ClusterController.class).toInstance(clusterController);
+        bind(KerberosDescriptorFactory.class).toInstance(kerberosDescriptorFactory);
       }
     });
 
@@ -198,11 +188,10 @@ public class KerberosHelperTest {
     KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);
 
     Cluster cluster = createNiceMock(Cluster.class);
-    KerberosDescriptor kerberosDescriptor = createNiceMock(KerberosDescriptor.class);
     RequestStageContainer requestStageContainer = createNiceMock(RequestStageContainer.class);
 
     replayAll();
-    kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, kerberosDescriptor, requestStageContainer);
+    kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, requestStageContainer);
     verifyAll();
   }
 
@@ -220,10 +209,8 @@ public class KerberosHelperTest {
     final Cluster cluster = createNiceMock(Cluster.class);
     expect(cluster.getDesiredConfigByType("kerberos-env")).andReturn(kerberosEnvConfig).once();
 
-    final KerberosDescriptor kerberosDescriptor = createNiceMock(KerberosDescriptor.class);
-
     replayAll();
-    kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, kerberosDescriptor, null);
+    kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, null);
     verifyAll();
   }
 
@@ -242,22 +229,20 @@ public class KerberosHelperTest {
     final Cluster cluster = createNiceMock(Cluster.class);
     expect(cluster.getDesiredConfigByType("krb5-conf")).andReturn(krb5ConfConfig).once();
 
-    final KerberosDescriptor kerberosDescriptor = createNiceMock(KerberosDescriptor.class);
-
     replayAll();
-    kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, kerberosDescriptor, null);
+    kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, null);
     verifyAll();
   }
 
   @Test
   public void testEnableKerberos() throws Exception {
-    testEnableKerberos(new KerberosCredential("principal", "password", "keytab"), false, false);
+    testEnableKerberos(new KerberosCredential("principal", "password", "keytab"), true, false);
   }
 
   @Test(expected = IllegalArgumentException.class)
   public void testEnableKerberosMissingCredentials() throws Exception {
     try {
-      testEnableKerberos(null, false, false);
+      testEnableKerberos(null, true, false);
     } catch (IllegalArgumentException e) {
       Assert.assertTrue(e.getMessage().startsWith("Missing KDC administrator credentials"));
       throw e;
@@ -267,7 +252,7 @@ public class KerberosHelperTest {
   @Test(expected = IllegalArgumentException.class)
   public void testEnableKerberosInvalidCredentials() throws Exception {
     try {
-      testEnableKerberos(new KerberosCredential("invalid_principal", "password", "keytab"), false, false);
+      testEnableKerberos(new KerberosCredential("invalid_principal", "password", "keytab"), true, false);
     } catch (IllegalArgumentException e) {
       Assert.assertTrue(e.getMessage().startsWith("Invalid KDC administrator credentials"));
       throw e;
@@ -315,10 +300,9 @@ public class KerberosHelperTest {
     final Cluster cluster = createNiceMock(Cluster.class);
 
     try {
-      kerberosHelper.executeCustomOperations(cluster, createNiceMock(KerberosDescriptor.class),
+      kerberosHelper.executeCustomOperations(cluster,
           Collections.singletonMap("invalid_operation", "false"), null);
-    }
-    catch(Throwable t) {
+    } catch (Throwable t) {
       Assert.fail("Exception should not have been thrown");
     }
   }
@@ -328,14 +312,14 @@ public class KerberosHelperTest {
     KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);
     final Cluster cluster = createNiceMock(Cluster.class);
 
-    kerberosHelper.executeCustomOperations(cluster, createNiceMock(KerberosDescriptor.class),
+    kerberosHelper.executeCustomOperations(cluster,
         Collections.singletonMap("regenerate_keytabs", "false"), null);
     Assert.fail("AmbariException should have failed");
   }
 
   @Test
   public void testRegenerateKeytabs() throws Exception {
-    testRegenerateKeytabs(new KerberosCredential("principal", "password", "keytab"), false, false);
+    testRegenerateKeytabs(new KerberosCredential("principal", "password", "keytab"));
   }
 
   @Test
@@ -535,13 +519,12 @@ public class KerberosHelperTest {
     expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).once();
     expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).once();
 
-    //todo: extract method?
     if (getClusterDescriptor) {
-      // needed to mock the static method fromJson()
       setupGetDescriptorFromCluster(kerberosDescriptor);
     } else if (getStackDescriptor) {
       setupGetDescriptorFromStack(kerberosDescriptor);
     }
+
     final StageFactory stageFactory = injector.getInstance(StageFactory.class);
     expect(stageFactory.createNew(anyLong(), anyObject(String.class), anyObject(String.class),
         anyLong(), anyObject(String.class), anyObject(String.class), anyObject(String.class),
@@ -594,8 +577,7 @@ public class KerberosHelperTest {
     // Needed by infrastructure
     metaInfo.init();
 
-    kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, !(getClusterDescriptor || getStackDescriptor) ?
-        kerberosDescriptor : null, requestStageContainer);
+    kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, requestStageContainer);
 
     verifyAll();
   }
@@ -834,15 +816,12 @@ public class KerberosHelperTest {
     // Needed by infrastructure
     metaInfo.init();
 
-    kerberosHelper.toggleKerberos(cluster, SecurityType.NONE, !(getClusterDescriptor || getStackDescriptor) ?
-        kerberosDescriptor : null, requestStageContainer);
+    kerberosHelper.toggleKerberos(cluster, SecurityType.NONE, requestStageContainer);
 
     verifyAll();
   }
 
-  private void testRegenerateKeytabs(final KerberosCredential kerberosCredential,
-                                     boolean getClusterDescriptor,
-                                     boolean getStackDescriptor) throws Exception {
+  private void testRegenerateKeytabs(final KerberosCredential kerberosCredential) throws Exception {
 
     KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);
 
@@ -1018,13 +997,8 @@ public class KerberosHelperTest {
     expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).once();
     expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).once();
 
-    //todo: extract method?
-    if (getClusterDescriptor) {
-      // needed to mock the static method fromJson()
-      setupGetDescriptorFromCluster(kerberosDescriptor);
-    } else if (getStackDescriptor) {
-      setupGetDescriptorFromStack(kerberosDescriptor);
-    }
+    setupGetDescriptorFromCluster(kerberosDescriptor);
+
     final StageFactory stageFactory = injector.getInstance(StageFactory.class);
     expect(stageFactory.createNew(anyLong(), anyObject(String.class), anyObject(String.class),
         anyLong(), anyObject(String.class), anyObject(String.class), anyObject(String.class),
@@ -1071,14 +1045,12 @@ public class KerberosHelperTest {
     // Needed by infrastructure
     metaInfo.init();
 
-    kerberosHelper.executeCustomOperations(cluster, !(getClusterDescriptor || getStackDescriptor) ?
-        kerberosDescriptor : null, Collections.singletonMap("regenerate_keytabs", "true"), requestStageContainer);
+    kerberosHelper.executeCustomOperations(cluster, Collections.singletonMap("regenerate_keytabs", "true"), requestStageContainer);
 
     verifyAll();
   }
 
   private void setupGetDescriptorFromCluster(KerberosDescriptor kerberosDescriptor) throws Exception {
-    mockStatic(KerberosDescriptor.class);
     ResourceProvider resourceProvider = createStrictMock(ResourceProvider.class);
     expect(clusterController.ensureResourceProvider(Resource.Type.Artifact)).andReturn(resourceProvider).once();
 
@@ -1098,15 +1070,19 @@ public class KerberosHelperTest {
     expect(resourceProvider.getResources(capture(requestCapture),
         capture(predicateCapture))).andReturn(result).once();
 
-    String artifactData = "kerberos descriptor json";
-    expect(resource.getPropertyValue(ArtifactResourceProvider.ARTIFACT_DATA_PROPERTY)).
-        andReturn(artifactData).once();
+    Map<String, Map<String, Object>> resourcePropertiesMap = createStrictMock(Map.class);
+    expect(resourcePropertiesMap.get(ArtifactResourceProvider.ARTIFACT_DATA_PROPERTY))
+        .andReturn(Collections.<String, Object>emptyMap()).once();
+    expect(resourcePropertiesMap.get(ArtifactResourceProvider.ARTIFACT_DATA_PROPERTY + "/properties"))
+        .andReturn(Collections.<String, Object>emptyMap()).once();
 
-    expect(KerberosDescriptor.fromJSON(artifactData)).andReturn(kerberosDescriptor).once();
+    expect(resource.getPropertiesMap()).andReturn(resourcePropertiesMap).once();
+
+    expect(kerberosDescriptorFactory.createInstance(anyObject(Map.class)))
+        .andReturn(kerberosDescriptor).once();
   }
 
   private void setupGetDescriptorFromStack(KerberosDescriptor kerberosDescriptor) throws Exception {
-    mockStatic(KerberosDescriptor.class);
     ResourceProvider resourceProvider = createStrictMock(ResourceProvider.class);
     expect(clusterController.ensureResourceProvider(Resource.Type.Artifact)).andReturn(resourceProvider).once();
 
@@ -1310,6 +1286,8 @@ public class KerberosHelperTest {
     expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).once();
     expect(kerberosDescriptor.getService("SERVICE3")).andReturn(serviceDescriptor3).once();
 
+    setupGetDescriptorFromCluster(kerberosDescriptor);
+
     final StageFactory stageFactory = injector.getInstance(StageFactory.class);
     expect(stageFactory.createNew(anyLong(), anyObject(String.class), anyObject(String.class),
         anyLong(), anyObject(String.class), anyObject(String.class), anyObject(String.class),
@@ -1362,7 +1340,7 @@ public class KerberosHelperTest {
     serviceComponentFilter.put("SERVICE3", Collections.singleton("COMPONENT3"));
     serviceComponentFilter.put("SERVICE1", null);
 
-    kerberosHelper.ensureIdentities(cluster, kerberosDescriptor, serviceComponentFilter, identityFilter, requestStageContainer);
+    kerberosHelper.ensureIdentities(cluster, serviceComponentFilter, identityFilter, requestStageContainer);
 
     verifyAll();
   }

+ 1 - 2
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostComponentResourceProviderTest.java

@@ -19,7 +19,6 @@
 package org.apache.ambari.server.controller.internal;
 
 import com.google.inject.Injector;
-import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.KerberosHelper;
 import org.apache.ambari.server.controller.MaintenanceStateHelper;
@@ -542,7 +541,7 @@ public class HostComponentResourceProviderTest {
         andReturn(provider).anyTimes();
 
     expect(kerberosHelper.isClusterKerberosEnabled(cluster)).andReturn(true).once();
-    expect(kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, null, stageContainer)).
+    expect(kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, stageContainer)).
         andReturn(stageContainer).once();
 
     // replay

+ 6 - 4
ambari-server/src/test/java/org/apache/ambari/server/stack/KerberosDescriptorTest.java

@@ -19,6 +19,7 @@
 package org.apache.ambari.server.stack;
 
 import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.springframework.util.Assert;
@@ -32,13 +33,14 @@ import java.net.URL;
  * and services
  */
 public class KerberosDescriptorTest {
+  private static final KerberosDescriptorFactory KERBEROS_DESCRIPTOR_FACTORY = new KerberosDescriptorFactory();
+
   private static File stacksDirectory;
   private static File hdpStackDirectory;
   private static File hdp22StackDirectory;
   private static File hdp22ServicesDirectory;
   private static File commonServicesDirectory;
 
-
   @BeforeClass
   public static void beforeClass() {
     URL rootDirectoryURL = KerberosDescriptorTest.class.getResource("/");
@@ -69,7 +71,7 @@ public class KerberosDescriptorTest {
   @Test
   public void testHDP22HBASEServiceDescriptor() throws IOException {
     File hbaseDirectory = new File(hdp22ServicesDirectory, "HBASE");
-    KerberosDescriptor descriptor = KerberosDescriptor.fromFile(new File(hbaseDirectory, "kerberos.json"));
+    KerberosDescriptor descriptor = KERBEROS_DESCRIPTOR_FACTORY.createInstance(new File(hbaseDirectory, "kerberos.json"));
     Assert.notNull(descriptor);
     Assert.notNull(descriptor.getServices());
     Assert.notNull(descriptor.getService("HBASE"));
@@ -78,7 +80,7 @@ public class KerberosDescriptorTest {
   @Test
   public void testHDP22HDFSServiceDescriptor() throws IOException {
     File hdfsDirectory = new File(hdp22ServicesDirectory, "HDFS");
-    KerberosDescriptor descriptor = KerberosDescriptor.fromFile(new File(hdfsDirectory, "kerberos.json"));
+    KerberosDescriptor descriptor = KERBEROS_DESCRIPTOR_FACTORY.createInstance(new File(hdfsDirectory, "kerberos.json"));
     Assert.notNull(descriptor);
     Assert.notNull(descriptor.getServices());
     Assert.notNull(descriptor.getService("HDFS"));
@@ -87,7 +89,7 @@ public class KerberosDescriptorTest {
   @Test
   public void testHDP22YarnServiceDescriptor() throws IOException {
     File yarnDirectory = new File(hdp22ServicesDirectory, "YARN");
-    KerberosDescriptor descriptor = KerberosDescriptor.fromFile(new File(yarnDirectory, "kerberos.json"));
+    KerberosDescriptor descriptor = KERBEROS_DESCRIPTOR_FACTORY.createInstance(new File(yarnDirectory, "kerberos.json"));
     Assert.notNull(descriptor);
     Assert.notNull(descriptor.getServices());
     Assert.notNull(descriptor.getService("YARN"));

+ 6 - 1
ambari-server/src/test/java/org/apache/ambari/server/state/ConfigHelperTest.java

@@ -17,6 +17,12 @@
  */
 package org.apache.ambari.server.state;
 
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
@@ -57,7 +63,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
-import static org.easymock.EasyMock.*;
 
 
 @RunWith(Enclosed.class)

+ 5 - 4
ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java

@@ -22,14 +22,15 @@ import junit.framework.Assert;
 import org.apache.ambari.server.AmbariException;
 import org.junit.Test;
 
-import java.io.File;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 public class KerberosDescriptorTest {
+  private static final KerberosDescriptorFactory KERBEROS_DESCRIPTOR_FACTORY = new KerberosDescriptorFactory();
+  private static final KerberosServiceDescriptorFactory KERBEROS_SERVICE_DESCRIPTOR_FACTORY = new KerberosServiceDescriptorFactory();
+
   public static final String JSON_VALUE =
       "{" +
           "  \"properties\": {" +
@@ -219,7 +220,7 @@ public class KerberosDescriptorTest {
   }
 
   private KerberosDescriptor createFromJSON() throws AmbariException {
-    return KerberosDescriptor.fromJSON(JSON_VALUE);
+    return KERBEROS_DESCRIPTOR_FACTORY.createInstance(JSON_VALUE);
   }
 
   private KerberosDescriptor createFromMap() throws AmbariException {
@@ -251,7 +252,7 @@ public class KerberosDescriptorTest {
   public void testInvalid() {
     // Invalid JSON syntax
     try {
-      KerberosServiceDescriptor.fromJSON(JSON_VALUE + "erroneous text");
+      KERBEROS_SERVICE_DESCRIPTOR_FACTORY.createInstances(JSON_VALUE + "erroneous text");
       Assert.fail("Should have thrown AmbariException.");
     } catch (AmbariException e) {
       // This is expected

+ 8 - 6
ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptorTest.java

@@ -114,6 +114,8 @@ public class KerberosServiceDescriptorTest {
         }
       };
 
+  private static final KerberosServiceDescriptorFactory KERBEROS_SERVICE_DESCRIPTOR_FACTORY = new KerberosServiceDescriptorFactory();
+
   public static void validateFromJSON(KerberosServiceDescriptor[] serviceDescriptors) {
     Assert.assertNotNull(serviceDescriptors);
     Assert.assertEquals(2, serviceDescriptors.length);
@@ -241,11 +243,11 @@ public class KerberosServiceDescriptorTest {
   }
 
   private KerberosServiceDescriptor createFromJSON() throws AmbariException {
-    return KerberosServiceDescriptor.fromJSON("SERVICE_NAME", JSON_VALUE);
+    return KERBEROS_SERVICE_DESCRIPTOR_FACTORY.createInstance("SERVICE_NAME", JSON_VALUE);
   }
 
   private KerberosServiceDescriptor[] createMultipleFromJSON() throws AmbariException {
-    return KerberosServiceDescriptor.fromJSON(JSON_VALUE_SERVICES);
+    return KERBEROS_SERVICE_DESCRIPTOR_FACTORY.createInstances(JSON_VALUE_SERVICES);
   }
 
   private KerberosServiceDescriptor createFromMap() throws AmbariException {
@@ -255,7 +257,7 @@ public class KerberosServiceDescriptorTest {
   private KerberosServiceDescriptor[] createFromFile() throws IOException {
     URL url = getClass().getClassLoader().getResource("service_level_kerberos.json");
     File file = (url == null) ? null : new File(url.getFile());
-    return KerberosServiceDescriptor.fromFile(file);
+    return KERBEROS_SERVICE_DESCRIPTOR_FACTORY.createInstances(file);
   }
 
   @Test
@@ -272,7 +274,7 @@ public class KerberosServiceDescriptorTest {
   public void testInvalid() {
     // Invalid JSON syntax
     try {
-      KerberosServiceDescriptor.fromJSON(JSON_VALUE_SERVICES + "erroneous text");
+      KERBEROS_SERVICE_DESCRIPTOR_FACTORY.createInstances(JSON_VALUE_SERVICES + "erroneous text");
       Assert.fail("Should have thrown AmbariException.");
     } catch (AmbariException e) {
       // This is expected
@@ -282,7 +284,7 @@ public class KerberosServiceDescriptorTest {
 
     // Test missing top-level "services"
     try {
-      KerberosServiceDescriptor.fromJSON(JSON_VALUE);
+      KERBEROS_SERVICE_DESCRIPTOR_FACTORY.createInstances(JSON_VALUE);
       Assert.fail("Should have thrown AmbariException.");
     } catch (AmbariException e) {
       // This is expected
@@ -294,7 +296,7 @@ public class KerberosServiceDescriptorTest {
     URL url = getClass().getClassLoader().getResource("service_level_kerberos_invalid.json");
     File file = (url == null) ? null : new File(url.getFile());
     try {
-      KerberosServiceDescriptor.fromFile(file);
+      KERBEROS_SERVICE_DESCRIPTOR_FACTORY.createInstances(file);
       Assert.fail("Should have thrown AmbariException.");
     } catch (AmbariException e) {
       // This is expected