Bladeren bron

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

Robert Levas 10 jaren geleden
bovenliggende
commit
d6c389c115
24 gewijzigde bestanden met toevoegingen van 643 en 602 verwijderingen
  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