You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by js...@apache.org on 2014/11/10 22:32:07 UTC

[08/11] ambari git commit: AMBARI-7175. Add explicit stack service inheritance

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
index c9794d8..dcfd00f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
@@ -207,6 +207,10 @@ public class ComponentInfo {
     this.dependencies = dependencies;
   }
 
+  public void setAutoDeploy(AutoDeployInfo autoDeploy) {
+    this.autoDeploy = autoDeploy;
+  }
+
   public AutoDeployInfo getAutoDeploy() {
     return autoDeploy;
   }
@@ -226,4 +230,48 @@ public class ComponentInfo {
   public void setClientsToUpdateConfigs(List<String> clientsToUpdateConfigs) {
     this.clientsToUpdateConfigs = clientsToUpdateConfigs;
   }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ComponentInfo that = (ComponentInfo) o;
+
+    if (deleted != that.deleted) return false;
+    if (autoDeploy != null ? !autoDeploy.equals(that.autoDeploy) : that.autoDeploy != null) return false;
+    if (cardinality != null ? !cardinality.equals(that.cardinality) : that.cardinality != null) return false;
+    if (category != null ? !category.equals(that.category) : that.category != null) return false;
+    if (clientConfigFiles != null ? !clientConfigFiles.equals(that.clientConfigFiles) : that.clientConfigFiles != null)
+      return false;
+    if (commandScript != null ? !commandScript.equals(that.commandScript) : that.commandScript != null) return false;
+    if (configDependencies != null ? !configDependencies.equals(that.configDependencies) : that.configDependencies != null)
+      return false;
+    if (customCommands != null ? !customCommands.equals(that.customCommands) : that.customCommands != null)
+      return false;
+    if (dependencies != null ? !dependencies.equals(that.dependencies) : that.dependencies != null) return false;
+    if (displayName != null ? !displayName.equals(that.displayName) : that.displayName != null) return false;
+    if (name != null ? !name.equals(that.name) : that.name != null) return false;
+    if (clientConfigFiles != null ? !clientConfigFiles.equals(that.clientConfigFiles) :
+        that.clientConfigFiles != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = name != null ? name.hashCode() : 0;
+    result = 31 * result + (displayName != null ? displayName.hashCode() : 0);
+    result = 31 * result + (category != null ? category.hashCode() : 0);
+    result = 31 * result + (deleted ? 1 : 0);
+    result = 31 * result + (cardinality != null ? cardinality.hashCode() : 0);
+    result = 31 * result + (commandScript != null ? commandScript.hashCode() : 0);
+    result = 31 * result + (clientConfigFiles != null ? clientConfigFiles.hashCode() : 0);
+    result = 31 * result + (customCommands != null ? customCommands.hashCode() : 0);
+    result = 31 * result + (dependencies != null ? dependencies.hashCode() : 0);
+    result = 31 * result + (autoDeploy != null ? autoDeploy.hashCode() : 0);
+    result = 31 * result + (configDependencies != null ? configDependencies.hashCode() : 0);
+    result = 31 * result + (clientConfigFiles != null ? clientConfigFiles.hashCode() : 0);
+    return result;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
index e15a62a..d4cbd4e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
@@ -417,13 +417,13 @@ public class ConfigHelper {
    * @param propertyName
    */
   public Set<String> findConfigTypesByPropertyName(StackId stackId, String propertyName, String clusterName) throws AmbariException {
-    StackInfo stack = ambariMetaInfo.getStackInfo(stackId.getStackName(),
+    StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(),
         stackId.getStackVersion());
     
     Set<String> result = new HashSet<String>();
 
     for(Service service : clusters.getCluster(clusterName).getServices().values()) {
-      Set<PropertyInfo> stackProperties = ambariMetaInfo.getProperties(stack.getName(), stack.getVersion(), service.getName());
+      Set<PropertyInfo> stackProperties = ambariMetaInfo.getServiceProperties(stack.getName(), stack.getVersion(), service.getName());
       Set<PropertyInfo> stackLevelProperties = ambariMetaInfo.getStackProperties(stack.getName(), stack.getVersion());
       stackProperties.addAll(stackLevelProperties);
       
@@ -440,18 +440,17 @@ public class ConfigHelper {
   }
   
   public Set<String> getPropertyValuesWithPropertyType(StackId stackId, PropertyType propertyType, Cluster cluster) throws AmbariException {
-    StackInfo stack = ambariMetaInfo.getStackInfo(stackId.getStackName(),
+    StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(),
         stackId.getStackVersion());
     
     Set<String> result = new HashSet<String>();
 
     for(Service service : cluster.getServices().values()) {
-      Set<PropertyInfo> stackProperties = ambariMetaInfo.getProperties(stack.getName(), stack.getVersion(), service.getName());
-
-      for (PropertyInfo stackProperty : stackProperties) {
-        if(stackProperty.getPropertyTypes().contains(propertyType)) {
-          String stackPropertyConfigType = fileNameToConfigType(stackProperty.getFilename());
-          result.add(cluster.getDesiredConfigByType(stackPropertyConfigType).getProperties().get(stackProperty.getName()));
+      Set<PropertyInfo> serviceProperties = ambariMetaInfo.getServiceProperties(stack.getName(), stack.getVersion(), service.getName());
+      for (PropertyInfo serviceProperty : serviceProperties) {
+        if(serviceProperty.getPropertyTypes().contains(propertyType)) {
+          String stackPropertyConfigType = fileNameToConfigType(serviceProperty.getFilename());
+          result.add(cluster.getDesiredConfigByType(stackPropertyConfigType).getProperties().get(serviceProperty.getName()));
         }
       }
     }
@@ -470,15 +469,15 @@ public class ConfigHelper {
   
   public String getPropertyValueFromStackDefenitions(Cluster cluster, String configType, String propertyName) throws AmbariException {
     StackId stackId = cluster.getCurrentStackVersion();
-    StackInfo stack = ambariMetaInfo.getStackInfo(stackId.getStackName(),
+    StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(),
         stackId.getStackVersion());
     
-    for(ServiceInfo serviceInfo:stack.getServices()) {     
-      Set<PropertyInfo> stackProperties = ambariMetaInfo.getProperties(stack.getName(), stack.getVersion(), serviceInfo.getName());
-      Set<PropertyInfo> stackLevelProperties = ambariMetaInfo.getStackProperties(stack.getName(), stack.getVersion());
-      stackProperties.addAll(stackLevelProperties);
+    for(ServiceInfo serviceInfo:stack.getServices()) {
+      Set<PropertyInfo> serviceProperties = ambariMetaInfo.getServiceProperties(stack.getName(), stack.getVersion(), serviceInfo.getName());
+      Set<PropertyInfo> stackProperties = ambariMetaInfo.getStackProperties(stack.getName(), stack.getVersion());
+      serviceProperties.addAll(stackProperties);
       
-      for (PropertyInfo stackProperty : stackProperties) {
+      for (PropertyInfo stackProperty : serviceProperties) {
         String stackPropertyConfigType = fileNameToConfigType(stackProperty.getFilename());
         
         if(stackProperty.getName().equals(propertyName) && stackPropertyConfigType.equals(configType)) {
@@ -493,13 +492,12 @@ public class ConfigHelper {
   
   public ServiceInfo getPropertyOwnerService(Cluster cluster, String configType, String propertyName) throws AmbariException {
     StackId stackId = cluster.getCurrentStackVersion();
-    StackInfo stack = ambariMetaInfo.getStackInfo(stackId.getStackName(),
-        stackId.getStackVersion());
+    StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
     
     for(ServiceInfo serviceInfo:stack.getServices()) {     
-      Set<PropertyInfo> stackProperties = ambariMetaInfo.getProperties(stack.getName(), stack.getVersion(), serviceInfo.getName());
+      Set<PropertyInfo> serviceProperties = ambariMetaInfo.getServiceProperties(stack.getName(), stack.getVersion(), serviceInfo.getName());
       
-      for (PropertyInfo stackProperty : stackProperties) {
+      for (PropertyInfo stackProperty : serviceProperties) {
         String stackPropertyConfigType = fileNameToConfigType(stackProperty.getFilename());
         
         if(stackProperty.getName().equals(propertyName) && stackPropertyConfigType.equals(configType)) {
@@ -514,16 +512,14 @@ public class ConfigHelper {
   
   public Set<PropertyInfo> getServiceProperties(Cluster cluster, String serviceName) throws AmbariException {
     StackId stackId = cluster.getCurrentStackVersion();
-    StackInfo stack = ambariMetaInfo.getStackInfo(stackId.getStackName(),
-        stackId.getStackVersion());
+    StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
     
-    return ambariMetaInfo.getProperties(stack.getName(), stack.getVersion(), serviceName);
+    return ambariMetaInfo.getServiceProperties(stack.getName(), stack.getVersion(), serviceName);
   }
   
   public Set<PropertyInfo> getStackProperties(Cluster cluster) throws AmbariException {
     StackId stackId = cluster.getCurrentStackVersion();
-    StackInfo stack = ambariMetaInfo.getStackInfo(stackId.getStackName(),
-        stackId.getStackVersion());
+    StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
     
     return ambariMetaInfo.getStackProperties(stack.getName(), stack.getVersion());
   }
@@ -654,14 +650,14 @@ public class ConfigHelper {
       
       if (!actual.containsKey(type)) {
         // desired is set, but actual is not
-        if (!serviceInfo.hasConfigType(type)) {
+        if (!serviceInfo.hasConfigDependency(type)) {
           stale = componentInfo != null && componentInfo.hasConfigType(type);
         } else if (type.equals(Configuration.GLOBAL_CONFIG_TAG)) {
           // find out if the keys are stale by first checking the target service,
           // then all services
           Collection<String> keys = mergeKeyNames(cluster, type, tags.values());
           
-          if (serviceInfo.hasPropertyFor(type, keys) || !hasPropertyFor(stackId, type, keys)) {
+          if (serviceInfo.hasDependencyAndPropertyFor(type, keys) || !hasPropertyFor(stackId, type, keys)) {
             stale = true;
           }
         } else {
@@ -680,11 +676,11 @@ public class ConfigHelper {
           // to the service
           Collection<String> changed = findChangedKeys(cluster, type,
             tags.values(), actualTags.values());
-          if (serviceInfo.hasPropertyFor(type, changed)) {
+          if (serviceInfo.hasDependencyAndPropertyFor(type, changed)) {
             stale = true;
           }
         } else {
-          stale = serviceInfo.hasConfigType(type) || componentInfo.hasConfigType(type);
+          stale = serviceInfo.hasConfigDependency(type) || componentInfo.hasConfigType(type);
         }
       }
     }
@@ -726,7 +722,7 @@ public class ConfigHelper {
     for (ServiceInfo svc : ambariMetaInfo.getServices(stack.getStackName(),
         stack.getStackVersion()).values()) {
       
-      if (svc.hasPropertyFor(type, keys))
+      if (svc.hasDependencyAndPropertyFor(type, keys))
         return true;
       
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
index 58e6e4c..e3db662 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/DependencyInfo.java
@@ -143,4 +143,30 @@ public class DependencyInfo {
            ", auto-deploy=" + m_autoDeploy.isEnabled() +
            "]";
   }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    DependencyInfo that = (DependencyInfo) o;
+
+    if (componentName != null ? !componentName.equals(that.componentName) : that.componentName != null) return false;
+    if (m_autoDeploy != null ? !m_autoDeploy.equals(that.m_autoDeploy) : that.m_autoDeploy != null) return false;
+    if (name != null ? !name.equals(that.name) : that.name != null) return false;
+    if (scope != null ? !scope.equals(that.scope) : that.scope != null) return false;
+    if (serviceName != null ? !serviceName.equals(that.serviceName) : that.serviceName != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = name != null ? name.hashCode() : 0;
+    result = 31 * result + (scope != null ? scope.hashCode() : 0);
+    result = 31 * result + (serviceName != null ? serviceName.hashCode() : 0);
+    result = 31 * result + (componentName != null ? componentName.hashCode() : 0);
+    result = 31 * result + (m_autoDeploy != null ? m_autoDeploy.hashCode() : 0);
+    return result;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
index 45ea1f9..a31e42c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java
@@ -25,6 +25,7 @@ import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
 import com.google.inject.persist.Transactional;
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.ServiceComponentHostNotFoundException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.ServiceComponentResponse;
@@ -88,10 +89,12 @@ public class ServiceComponentImpl implements ServiceComponent {
     this.hostComponents = new HashMap<String, ServiceComponentHost>();
 
     StackId stackId = service.getDesiredStackVersion();
-    ComponentInfo compInfo = ambariMetaInfo.getComponentCategory(
-        stackId.getStackName(), stackId.getStackVersion(), service.getName(),
-        componentName);
-    if (compInfo == null) {
+    try {
+      ComponentInfo compInfo = ambariMetaInfo.getComponent(stackId.getStackName(),
+          stackId.getStackVersion(), service.getName(), componentName);
+      this.isClientComponent = compInfo.isClient();
+      this.isMasterComponent = compInfo.isMaster();
+    } catch (ObjectNotFoundException e) {
       throw new RuntimeException("Trying to create a ServiceComponent"
           + " not recognized in stack info"
           + ", clusterName=" + service.getCluster().getClusterName()
@@ -99,9 +102,6 @@ public class ServiceComponentImpl implements ServiceComponent {
           + ", componentName=" + componentName
           + ", stackInfo=" + stackId.getStackId());
     }
-    this.isClientComponent = compInfo.isClient();
-    this.isMasterComponent = compInfo.isMaster();
-
     init();
   }
 
@@ -130,10 +130,13 @@ public class ServiceComponentImpl implements ServiceComponent {
     }
 
     StackId stackId = service.getDesiredStackVersion();
-    ComponentInfo compInfo = ambariMetaInfo.getComponentCategory(
-        stackId.getStackName(), stackId.getStackVersion(), service.getName(),
-        getName());
-    if (compInfo == null) {
+    try {
+      ComponentInfo compInfo = ambariMetaInfo.getComponent(
+          stackId.getStackName(), stackId.getStackVersion(), service.getName(),
+          getName());
+      this.isClientComponent = compInfo.isClient();
+      this.isMasterComponent = compInfo.isMaster();
+    } catch (ObjectNotFoundException e) {
       throw new AmbariException("Trying to create a ServiceComponent"
           + " not recognized in stack info"
           + ", clusterName=" + service.getCluster().getClusterName()
@@ -141,8 +144,6 @@ public class ServiceComponentImpl implements ServiceComponent {
           + ", componentName=" + getName()
           + ", stackInfo=" + stackId.getStackId());
     }
-    this.isClientComponent = compInfo.isClient();
-    this.isMasterComponent = compInfo.isMaster();
 
     persisted = true;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
index bb5057f..4b4a305 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
@@ -107,7 +107,7 @@ public class ServiceImpl implements Service {
     StackId stackId = cluster.getDesiredStackVersion();
     setDesiredStackVersion(stackId);
 
-    ServiceInfo sInfo = ambariMetaInfo.getServiceInfo(stackId.getStackName(),
+    ServiceInfo sInfo = ambariMetaInfo.getService(stackId.getStackName(),
         stackId.getStackVersion(), serviceName);
     isClientOnlyService = sInfo.isClientOnlyService();
 
@@ -145,7 +145,7 @@ public class ServiceImpl implements Service {
     }
 
     StackId stackId = getDesiredStackVersion();
-    ServiceInfo sInfo = ambariMetaInfo.getServiceInfo(stackId.getStackName(),
+    ServiceInfo sInfo = ambariMetaInfo.getService(stackId.getStackName(),
         stackId.getStackVersion(), getName());
     isClientOnlyService = sInfo.isClientOnlyService();
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
index ae746d6..9277ec6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
@@ -74,7 +74,7 @@ public class ServiceInfo {
 
   @XmlElementWrapper(name="excluded-config-types")
   @XmlElement(name="config-type")
-  private Set<String> excludedConfigTypes;
+  private Set<String> excludedConfigTypes = new HashSet<String>();
 
   @XmlTransient
   private Map<String, Map<String, Map<String, String>>> configTypes;
@@ -84,7 +84,13 @@ public class ServiceInfo {
   
   @JsonIgnore
   @XmlElement(name = "restartRequiredAfterChange")
-  private Boolean restartRequiredAfterChange;  
+  private Boolean restartRequiredAfterChange;
+
+  @XmlElement(name = "extends")
+  private String parent;
+
+  @XmlTransient
+  private volatile Map<String, PropertyInfo> requiredProperties;
 
   public Boolean isRestartRequiredAfterChange() {
     return restartRequiredAfterChange;
@@ -137,7 +143,7 @@ public class ServiceInfo {
   
   @XmlElementWrapper(name="requiredServices")
   @XmlElement(name="service")
-  private List<String> requiredServices;
+  private List<String> requiredServices = new ArrayList<String>();
 
   /**
    * Meaning: stores subpath from stack root to exact directory, that contains
@@ -164,6 +170,14 @@ public class ServiceInfo {
     this.name = name;
   }
 
+  public String getParent() {
+    return parent;
+  }
+
+  public void setParent(String parent) {
+    this.parent = parent;
+  }
+
   public String getDisplayName() {
     return displayName;
   }
@@ -205,7 +219,7 @@ public class ServiceInfo {
   }
   /**
    * Finds ComponentInfo by component name
-   * @param componentName
+   * @param componentName  name of the component
    * @return ComponentInfo componentName or null
    */
   public ComponentInfo getComponentByName(String componentName){
@@ -229,65 +243,112 @@ public class ServiceInfo {
   }
 
   public ComponentInfo getClientComponent() {
-    if (components == null || components.isEmpty()) {
-      return null;
-    }
-    for (ComponentInfo compInfo : components) {
-      if (compInfo.isClient()) {
-        return compInfo;
+    ComponentInfo client = null;
+
+    if (components != null) {
+      for (ComponentInfo compInfo : components) {
+        if (compInfo.isClient()) {
+          client = compInfo;
+          break;
+        }
       }
     }
-    return components.get(0);
+    return client;
   }
 
   @Override
   public String toString() {
     StringBuilder sb = new StringBuilder();
-    sb.append("Service name:" + name + "\nversion:" + version +
-        "\ncomment:" + comment);
+    sb.append("Service name:");
+    sb.append(name);
+    sb.append("\nversion:");
+    sb.append(version);
+    sb.append("\ncomment:");
+    sb.append(comment);
     //for (PropertyInfo property : getProperties()) {
     //  sb.append("\tProperty name=" + property.getName() +
     //"\nproperty value=" + property.getValue() + "\ndescription=" + property.getDescription());
     //}
     for (ComponentInfo component : getComponents()) {
       sb.append("\n\n\nComponent:\n");
-      sb.append("name=" + component.getName());
-      sb.append("\tcategory=" + component.getCategory());
+      sb.append("name=");
+      sb.append(component.getName());
+      sb.append("\tcategory=");
+      sb.append(component.getCategory());
     }
 
     return sb.toString();
   }
-  
-  public Map<String, Map<String, Map<String, String>>> getConfigTypes() {
-    if (configTypes == null) configTypes = new HashMap<String, Map<String, Map<String, String>>>();
-    return configTypes;
+
+  /**
+   * Obtain the config types associated with this service.
+   * The returned map is an unmodifiable view.
+   * @return unmodifiable map of config types associated with this service
+   */
+  public synchronized Map<String, Map<String, Map<String, String>>> getConfigTypeAttributes() {
+    return configTypes == null ?
+        Collections.<String, Map<String, Map<String, String>>>emptyMap() :
+        Collections.unmodifiableMap(configTypes);
   }
 
-  public void setConfigTypes(Map<String, Map<String, Map<String, String>>> configTypes) {
-    this.configTypes = configTypes;
+  /**
+   * Add the given type and set it's attributes.
+   * If the type is marked for exclusion, it will not be added.
+   *
+   * @param type            configuration type
+   * @param typeAttributes  attributes associated with the type
+   */
+  public synchronized void setTypeAttributes(String type, Map<String, Map<String, String>> typeAttributes) {
+    if (this.configTypes == null) {
+      configTypes = new HashMap<String, Map<String, Map<String, String>>>();
+    }
+
+    if (! excludedConfigTypes.contains(type)) {
+      configTypes.put(type, typeAttributes);
+    }
   }
 
   /**
+   * Set all types and associated attributes.  Any previously existing types and
+   * attributes are removed prior to setting the new values.
+   *
+   * @param types map of type attributes
+   */
+  public synchronized void setAllConfigAttributes(Map<String, Map<String, Map<String, String>>> types) {
+    configTypes = new HashMap<String, Map<String, Map<String, String>>>();
+    for (Map.Entry<String, Map<String, Map<String, String>>> entry : types.entrySet()) {
+      setTypeAttributes(entry.getKey(), entry.getValue());
+    }
+  }
+
+  /**
+   * Determine of the service has a dependency on the provided configuration type.
    * @param type the config type
-   * @return <code>true</code> if the service defines the supplied type
+   * @return <code>true</code> if the service defines a dependency on the provided type
    */
-  public boolean hasConfigType(String type) {
+  public boolean hasConfigDependency(String type) {
     return configDependencies != null && configDependencies.contains(type);
   }
 
   /**
-   * The purpose of this method is to determine if a service has a property
-   * defined in a supplied set:
-   * <ul>
-   *   <li>If the type is not defined for the service, then no property can exist.</li>
-   *   <li>If the type is defined, then check each supplied property for existence.</li>
-   * </ul>
+   * Determine if the service contains the specified config type
+   * @param type  config type to check
+   * @return true if the service has the specified config type; false otherwise
+   */
+  public boolean hasConfigType(String type) {
+    return configTypes != null && configTypes.containsKey(type);
+  }
+
+  /**
+   * Determine if the service has a dependency on the provided type and contains any of the provided properties.
+   * This can be used in determining if a property is stale.
+
    * @param type the config type
    * @param keyNames the names of all the config keys for the given type 
    * @return <code>true</code> if the config is stale
    */
-  public boolean hasPropertyFor(String type, Collection<String> keyNames) {
-    if (!hasConfigType(type))
+  public boolean hasDependencyAndPropertyFor(String type, Collection<String> keyNames) {
+    if (!hasConfigDependency(type))
       return false;
 
     buildConfigLayout();
@@ -371,7 +432,7 @@ public class ServiceInfo {
 
   /**
    * Exposes (and initializes on first use) map of os-specific details.
-   * @return
+   * @return  map of OS specific details keyed by family
    */
   public Map<String, ServiceOsSpecific> getOsSpecifics() {
     if (serviceOsSpecificsMap == null) {
@@ -487,4 +548,24 @@ public class ServiceInfo {
   public void setExcludedConfigTypes(Set<String> excludedConfigTypes) {
     this.excludedConfigTypes = excludedConfigTypes;
   }
+
+  //todo: ensure that required properties are never modified...
+  public Map<String, PropertyInfo> getRequiredProperties() {
+    Map<String, PropertyInfo> result = requiredProperties;
+    if (result == null) {
+      synchronized(this) {
+        result = requiredProperties;
+        if (result == null) {
+          requiredProperties = result = new HashMap<String, PropertyInfo>();
+          List<PropertyInfo> properties = getProperties();
+          for (PropertyInfo propertyInfo : properties) {
+            if (propertyInfo.isRequireInput()) {
+              result.put(propertyInfo.getName(), propertyInfo);
+            }
+          }
+        }
+      }
+    }
+    return result;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceOsSpecific.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceOsSpecific.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceOsSpecific.java
index a143ba1..d81c182 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceOsSpecific.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceOsSpecific.java
@@ -62,6 +62,28 @@ public class ServiceOsSpecific {
     this.packages.addAll(packages);
   }
 
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ServiceOsSpecific that = (ServiceOsSpecific) o;
+
+    if (osFamily != null ? !osFamily.equals(that.osFamily) : that.osFamily != null) return false;
+    if (packages != null ? !packages.equals(that.packages) : that.packages != null) return false;
+    if (repo != null ? !repo.equals(that.repo) : that.repo != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = osFamily != null ? osFamily.hashCode() : 0;
+    result = 31 * result + (repo != null ? repo.hashCode() : 0);
+    result = 31 * result + (packages != null ? packages.hashCode() : 0);
+    return result;
+  }
+
   /**
    * The <code>repo</code> tag. It has different set of fields compared to
    * <link>org.apache.ambari.server.state.RepositoryInfo</link>,
@@ -110,6 +132,29 @@ public class ServiceOsSpecific {
       return reponame;
     }
 
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      Repo repo = (Repo) o;
+
+      if (baseurl != null ? !baseurl.equals(repo.baseurl) : repo.baseurl != null) return false;
+      if (mirrorslist != null ? !mirrorslist.equals(repo.mirrorslist) : repo.mirrorslist != null) return false;
+      if (repoid != null ? !repoid.equals(repo.repoid) : repo.repoid != null) return false;
+      if (reponame != null ? !reponame.equals(repo.reponame) : repo.reponame != null) return false;
+
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      int result = baseurl != null ? baseurl.hashCode() : 0;
+      result = 31 * result + (mirrorslist != null ? mirrorslist.hashCode() : 0);
+      result = 31 * result + (repoid != null ? repoid.hashCode() : 0);
+      result = 31 * result + (reponame != null ? reponame.hashCode() : 0);
+      return result;
+    }
   }
 
 
@@ -130,6 +175,21 @@ public class ServiceOsSpecific {
     }
 
     public Package() { }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      Package that = (Package) o;
+
+      return name.equals(that.name);
+    }
+
+    @Override
+    public int hashCode() {
+      return name.hashCode();
+    }
   }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/Stack.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Stack.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Stack.java
deleted file mode 100644
index 92b799d..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Stack.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * 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;
-
-import org.apache.ambari.server.controller.StackResponse;
-
-public class Stack {
-
-  private String stackName;
-
-  public Stack(String stackName) {
-    setStackName(stackName);
-  }
-
-  public String getStackName() {
-    return stackName;
-  }
-
-  public void setStackName(String stackName) {
-    this.stackName = stackName;
-  }
-
-  @Override
-  public int hashCode() {
-    return stackName.hashCode();
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-
-    if (obj == null)
-      return false;
-
-    if (!(obj instanceof Stack)) {
-      return false;
-    }
-    if (this == obj) {
-      return true;
-    }
-    Stack stack = (Stack) obj;
-    return getStackName().equals(stack.getStackName());
-  }
-  
-  
-  public StackResponse convertToResponse()
-  {
-    return new StackResponse(getStackName());
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
index 64782cc..f19cf81 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
@@ -19,11 +19,14 @@
 package org.apache.ambari.server.state;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.ambari.server.controller.StackVersionResponse;
+import org.apache.ambari.server.state.stack.UpgradePack;
 
 public class StackInfo implements Comparable<StackInfo>{
   private String name;
@@ -32,11 +35,12 @@ public class StackInfo implements Comparable<StackInfo>{
   private boolean active;
   private String rcoFileLocation;
   private List<RepositoryInfo> repositories;
-  private List<ServiceInfo> services;
+  private Collection<ServiceInfo> services;
   private String parentStackVersion;
   // stack-level properties
   private List<PropertyInfo> properties;
   private Map<String, Map<String, Map<String, String>>> configTypes;
+  private Map<String, UpgradePack> upgradePacks;
 
   /**
    * Meaning: stores subpath from stack root to exact hooks folder for stack. These hooks are
@@ -71,12 +75,23 @@ public class StackInfo implements Comparable<StackInfo>{
     this.repositories = repositories;
   }
 
-  public synchronized List<ServiceInfo> getServices() {
+  public synchronized Collection<ServiceInfo> getServices() {
     if (services == null) services = new ArrayList<ServiceInfo>();
     return services;
   }
 
-  public synchronized void setServices(List<ServiceInfo> services) {
+  public ServiceInfo getService(String name) {
+    Collection<ServiceInfo> services = getServices();
+    for (ServiceInfo service : services) {
+      if (service.getName().equals(name)) {
+        return service;
+      }
+    }
+    //todo: exception?
+    return null;
+  }
+
+  public synchronized void setServices(Collection<ServiceInfo> services) {
     this.services = services;
   }
 
@@ -89,14 +104,43 @@ public class StackInfo implements Comparable<StackInfo>{
     this.properties = properties;
   }
 
-  public Map<String, Map<String, Map<String, String>>> getConfigTypes() {
-    if (configTypes == null) configTypes = new HashMap<String, Map<String, Map<String, String>>>();
-    return configTypes;
+  /**
+   * Obtain the config types associated with this stack.
+   * The returned map is an unmodifiable view.
+   * @return copy of the map of config types associated with this stack
+   */
+  public synchronized Map<String, Map<String, Map<String, String>>> getConfigTypeAttributes() {
+    return configTypes == null ?
+        Collections.<String, Map<String, Map<String, String>>>emptyMap() :
+        Collections.unmodifiableMap(configTypes);
   }
 
-  public void setConfigTypes(
-      Map<String, Map<String, Map<String, String>>> configTypes) {
-    this.configTypes = configTypes;
+
+  /**
+   * Add the given type and set it's attributes.
+   *
+   * @param type            configuration type
+   * @param typeAttributes  attributes associated with the type
+   */
+  public synchronized void setConfigTypeAttributes(String type, Map<String, Map<String, String>> typeAttributes) {
+    if (this.configTypes == null) {
+      configTypes = new HashMap<String, Map<String, Map<String, String>>>();
+    }
+    // todo: no exclusion mechanism for stack config types
+    configTypes.put(type, typeAttributes);
+  }
+
+  /**
+   * Set all types and associated attributes.  Any previously existing types and
+   * attributes are removed prior to setting the new values.
+   *
+   * @param types map of type attributes
+   */
+  public synchronized void setAllConfigAttributes(Map<String, Map<String, Map<String, String>>> types) {
+    configTypes = new HashMap<String, Map<String, Map<String, String>>>();
+    for (Map.Entry<String, Map<String, Map<String, String>>> entry : types.entrySet()) {
+      setConfigTypeAttributes(entry.getKey(), entry.getValue());
+    }
   }
 
   @Override
@@ -106,14 +150,16 @@ public class StackInfo implements Comparable<StackInfo>{
     if (services != null) {
       sb.append("\n\t\tService:");
       for (ServiceInfo service : services) {
-        sb.append("\t\t" + service.toString());
+        sb.append("\t\t");
+        sb.append(service);
       }
     }
 
     if (repositories != null) {
       sb.append("\n\t\tRepositories:");
       for (RepositoryInfo repository : repositories) {
-        sb.append("\t\t" + repository.toString());
+        sb.append("\t\t");
+        sb.append(repository.toString());
       }
     }
 
@@ -123,9 +169,7 @@ public class StackInfo implements Comparable<StackInfo>{
 
   @Override
   public int hashCode() {
-    int result = 1;
-    result = 31  + name.hashCode() + version.hashCode();
-    return result;
+    return 31  + name.hashCode() + version.hashCode();
   }
 
   @Override
@@ -143,7 +187,7 @@ public class StackInfo implements Comparable<StackInfo>{
   public StackVersionResponse convertToResponse() {
 
     return new StackVersionResponse(getVersion(), getMinUpgradeVersion(),
-      isActive(), getParentStackVersion(), getConfigTypes());
+      isActive(), getParentStackVersion(), getConfigTypeAttributes());
   }
 
   public String getMinUpgradeVersion() {
@@ -186,25 +230,47 @@ public class StackInfo implements Comparable<StackInfo>{
     this.stackHooksFolder = stackHooksFolder;
   }
 
-  @Override
-  public int compareTo(StackInfo o) {
-    String myId = name + "-" + version;
-    String oId = o.name + "-" + o.version;
-    return myId.compareTo(oId);
-  }
-
   /**
-   * @param path the path to the upgrades folder
+   * Set the path of the stack upgrade directory.
+   *
+   * @param path the path to the upgrades directory
    */
   public void setUpgradesFolder(String path) {
     upgradesFolder = path;
   }
 
   /**
+   * Obtain the path of the upgrades folder or null if directory doesn't exist.
+   *
    * @return the upgrades folder, or {@code null} if not set
    */
   public String getUpgradesFolder() {
     return upgradesFolder;
   }
 
+  /**
+   * Set upgrade packs.
+   *
+   * @param upgradePacks  map of upgrade packs
+   */
+  public void setUpgradePacks(Map<String, UpgradePack> upgradePacks) {
+    this.upgradePacks = upgradePacks;
+  }
+
+  /**
+   * Obtain all stack upgrade packs.
+   *
+   * @return map of upgrade pack name to upgrade pack or {@code null} of no packs
+   */
+  public Map<String, UpgradePack> getUpgradePacks() {
+    return upgradePacks;
+  }
+
+
+  @Override
+  public int compareTo(StackInfo o) {
+    String myId = name + "-" + version;
+    String oId = o.name + "-" + o.version;
+    return myId.compareTo(oId);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index d22e250..30dceb0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -268,11 +268,11 @@ public class ClusterImpl implements Cluster {
       String serviceName = entry.getKey();
       ServiceInfo serviceInfo = entry.getValue();
       //collect config types for service
-      Set<PropertyInfo> properties = ambariMetaInfo.getProperties(desiredStackVersion.getStackName(), desiredStackVersion.getStackVersion(), serviceName);
+      Set<PropertyInfo> properties = ambariMetaInfo.getServiceProperties(desiredStackVersion.getStackName(),
+          desiredStackVersion.getStackVersion(), serviceName);
       for (PropertyInfo property : properties) {
         String configType = ConfigHelper.fileNameToConfigType(property.getFilename());
-        if (serviceInfo.getExcludedConfigTypes() == null ||
-          !serviceInfo.getExcludedConfigTypes().contains(configType)) {
+        if (serviceInfo.hasConfigType(configType)) {
           serviceConfigTypes.put(serviceName, configType);
         }
       }
@@ -359,7 +359,7 @@ public class ClusterImpl implements Cluster {
               for (ClusterServiceEntity serviceEntity : clusterEntity.getClusterServiceEntities()) {
                 StackId stackId = getCurrentStackVersion();
                 try {
-                  if (ambariMetaInfo.getServiceInfo(stackId.getStackName(), stackId.getStackVersion(),
+                  if (ambariMetaInfo.getService(stackId.getStackName(), stackId.getStackVersion(),
                           serviceEntity.getServiceName()) != null) {
                     services.put(serviceEntity.getServiceName(), serviceFactory.createExisting(this, serviceEntity));
                   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java
index 6e58267..e7db9d3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java
@@ -30,7 +30,7 @@ import org.apache.ambari.server.api.util.TreeNodeImpl;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.internal.ResourceImpl;
 import org.apache.ambari.server.controller.spi.Resource;
-import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.state.ServiceInfo;
 import org.junit.Test;
 
 import java.net.InetAddress;
@@ -103,9 +103,13 @@ public class ClusterBlueprintRendererTest {
 
     AmbariManagementController controller = createMock(AmbariManagementController.class);
     AmbariMetaInfo stackInfo = createNiceMock(AmbariMetaInfo.class);
+    ServiceInfo hdfsService = new ServiceInfo();
+    hdfsService.setName("HDFS");
+    ServiceInfo mrService = new ServiceInfo();
+    mrService.setName("MAPREDUCE");
 
-    expect(stackInfo.getRequiredProperties("HDP", "1.3.3", "HDFS")).andReturn(Collections.<String, PropertyInfo>emptyMap());
-    expect(stackInfo.getRequiredProperties("HDP", "1.3.3", "MAPREDUCE")).andReturn(Collections.<String, PropertyInfo>emptyMap());
+    expect(stackInfo.getService("HDP", "1.3.3", "HDFS")).andReturn(hdfsService);
+    expect(stackInfo.getService("HDP", "1.3.3", "MAPREDUCE")).andReturn(mrService);
 
     Result result = new ResultImpl(true);
     createClusterResultTree(result.getResultTree());

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fc7adec/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
index e7b946d..4d08d6f 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
@@ -18,6 +18,10 @@
 
 package org.apache.ambari.server.api.services;
 
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -26,30 +30,33 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.File;
-import java.lang.reflect.Method;
+import java.lang.reflect.Field;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 
-import javax.persistence.EntityManager;
-import javax.xml.bind.JAXBException;
-
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.util.Modules;
 import junit.framework.Assert;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.StackAccessException;
-import org.apache.ambari.server.api.util.StackExtensionHelper;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.metadata.AgentAlertDefinitions;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.MetainfoDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.MetainfoEntity;
+import org.apache.ambari.server.stack.StackManager;
 import org.apache.ambari.server.state.AutoDeployInfo;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
@@ -60,15 +67,16 @@ import org.apache.ambari.server.state.OperatingSystemInfo;
 import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.ServiceInfo;
-import org.apache.ambari.server.state.Stack;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.MetricSource;
+import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
 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.stack.MetricDefinition;
+import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.commons.io.FileUtils;
 import org.junit.Before;
 import org.junit.Rule;
@@ -78,9 +86,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.util.Modules;
+
+import javax.persistence.EntityManager;
+import javax.xml.bind.JAXBException;
 
 public class AmbariMetaInfoTest {
 
@@ -112,7 +120,9 @@ public class AmbariMetaInfoTest {
   private static final String HADOOP_ENV_FILE_NAME = "hadoop-env.xml";
   private static final String HDFS_LOG4J_FILE_NAME = "hdfs-log4j.xml";
 
-  private Injector injector;
+  //private Injector injector;
+
+  //todo: add fail() for cases where an exception is expected such as getService, getComponent ...
 
 
   @Rule
@@ -120,22 +130,7 @@ public class AmbariMetaInfoTest {
 
   @Before
   public void before() throws Exception {
-    injector = Guice.createInjector(Modules.override(
-        new InMemoryDefaultTestModule()).with(new MockModule()));
-
-    injector.getInstance(GuiceJpaInitializer.class);
-    injector.getInstance(EntityManager.class);
-
-    File stackRoot = new File("src/test/resources/stacks");
-    LOG.info("Stacks file " + stackRoot.getAbsolutePath());
-    metaInfo = new AmbariMetaInfo(stackRoot, new File("target/version"));
-    metaInfo.injector = injector;
-
-    try {
-      metaInfo.init();
-    } catch(Exception e) {
-      LOG.info("Error in initializing ", e);
-    }
+    metaInfo = createAmbariMetaInfo(new File("src/test/resources/stacks"), new File("target/version"), true);
   }
 
   public class MockModule extends AbstractModule {
@@ -145,16 +140,6 @@ public class AmbariMetaInfoTest {
     }
   }
 
-  @Test
-  public void getComponentCategory() throws AmbariException {
-    ComponentInfo componentInfo = metaInfo.getComponentCategory(STACK_NAME_HDP,
-        STACK_VERSION_HDP, SERVICE_NAME_HDFS, SERVICE_COMPONENT_NAME);
-    assertNotNull(componentInfo);
-    componentInfo = metaInfo.getComponentCategory(STACK_NAME_HDP,
-        STACK_VERSION_HDP, SERVICE_NAME_HDFS, "DATANODE1");
-    Assert.assertNotNull(componentInfo);
-    assertTrue(!componentInfo.isClient());
-  }
 
   @Test
   public void getRestartRequiredServicesNames() throws AmbariException {
@@ -184,11 +169,13 @@ public class AmbariMetaInfoTest {
     // Scenario: user has internet and does nothing to repos via api
     // use the latest
     String buildDir = tmpFolder.getRoot().getAbsolutePath();
-    AmbariMetaInfo ambariMetaInfo = setupTempAmbariMetaInfo(buildDir);
+    AmbariMetaInfo ambariMetaInfo = setupTempAmbariMetaInfo(buildDir, true);
     // The current stack already has (HDP, 2.1.1, redhat6) with valid latest
     // url
     ambariMetaInfo.init();
 
+    waitForAllReposToBeResolved(ambariMetaInfo);
+
     List<RepositoryInfo> redhat6Repo = ambariMetaInfo.getRepositories(
         STACK_NAME_HDP, "2.1.1", "redhat6");
     assertNotNull(redhat6Repo);
@@ -205,7 +192,7 @@ public class AmbariMetaInfoTest {
     // Scenario: user has no internet and does nothing to repos via api
     // use the default
     String buildDir = tmpFolder.getRoot().getAbsolutePath();
-    AmbariMetaInfo ambariMetaInfo = setupTempAmbariMetaInfo(buildDir);
+    AmbariMetaInfo ambariMetaInfo = setupTempAmbariMetaInfo(buildDir, true);
     // The current stack already has (HDP, 2.1.1, redhat6).
 
     // Deleting the json file referenced by the latestBaseUrl to simulate No
@@ -233,7 +220,7 @@ public class AmbariMetaInfoTest {
     // Scenario: user has internet and but calls to set repos via api
     // use whatever they set
     String buildDir = tmpFolder.getRoot().getAbsolutePath();
-    AmbariMetaInfo ambariMetaInfo = setupTempAmbariMetaInfo(buildDir);
+    TestAmbariMetaInfo ambariMetaInfo = setupTempAmbariMetaInfo(buildDir, true);
     // The current stack already has (HDP, 2.1.1, redhat6)
 
     // Updating the baseUrl
@@ -244,8 +231,19 @@ public class AmbariMetaInfoTest {
         STACK_NAME_HDP + "-2.1.1");
     assertEquals(newBaseUrl, repoInfo.getBaseUrl());
     String prevBaseUrl = repoInfo.getDefaultBaseUrl();
+
+    // mock expectations
+    MetainfoDAO metainfoDAO = ambariMetaInfo.metaInfoDAO;
+    reset(metainfoDAO);
+    MetainfoEntity entity = createNiceMock(MetainfoEntity.class);
+    expect(metainfoDAO.findByKey("repo:/HDP/2.1.1/redhat6/HDP-2.1.1:baseurl")).andReturn(entity).atLeastOnce();
+    expect(entity.getMetainfoValue()).andReturn(newBaseUrl).atLeastOnce();
+    replay(metainfoDAO, entity);
+
     ambariMetaInfo.init();
 
+    waitForAllReposToBeResolved(ambariMetaInfo);
+
     List<RepositoryInfo> redhat6Repo = ambariMetaInfo.getRepositories(
         STACK_NAME_HDP, "2.1.1", "redhat6");
     assertNotNull(redhat6Repo);
@@ -266,8 +264,9 @@ public class AmbariMetaInfoTest {
   public void testGetRepositoryNoInternetUpdatedBaseUrl() throws Exception {
     // Scenario: user has no internet and but calls to set repos via api
     // use whatever they set
+    String newBaseUrl = "http://myprivate-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.0.6.0";
     String buildDir = tmpFolder.getRoot().getAbsolutePath();
-    AmbariMetaInfo ambariMetaInfo = setupTempAmbariMetaInfo(buildDir);
+    TestAmbariMetaInfo ambariMetaInfo = setupTempAmbariMetaInfo(buildDir, true);
     // The current stack already has (HDP, 2.1.1, redhat6).
 
     // Deleting the json file referenced by the latestBaseUrl to simulate No
@@ -278,15 +277,25 @@ public class AmbariMetaInfoTest {
     assertTrue(!latestUrlFile.exists());
 
     // Update baseUrl
-    String newBaseUrl = "http://myprivate-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.0.6.0";
     ambariMetaInfo.updateRepoBaseURL("HDP", "2.1.1", "redhat6", "HDP-2.1.1",
         newBaseUrl);
     RepositoryInfo repoInfo = ambariMetaInfo.getRepository(STACK_NAME_HDP, "2.1.1", "redhat6",
         STACK_NAME_HDP + "-2.1.1");
     assertEquals(newBaseUrl, repoInfo.getBaseUrl());
     String prevBaseUrl = repoInfo.getDefaultBaseUrl();
+
+    // mock expectations
+    MetainfoDAO metainfoDAO = ambariMetaInfo.metaInfoDAO;
+    reset(metainfoDAO);
+    MetainfoEntity entity = createNiceMock(MetainfoEntity.class);
+    expect(metainfoDAO.findByKey("repo:/HDP/2.1.1/redhat6/HDP-2.1.1:baseurl")).andReturn(entity).atLeastOnce();
+    expect(entity.getMetainfoValue()).andReturn(newBaseUrl).atLeastOnce();
+    replay(metainfoDAO, entity);
+
     ambariMetaInfo.init();
 
+    waitForAllReposToBeResolved(ambariMetaInfo);
+
     List<RepositoryInfo> redhat6Repo = ambariMetaInfo.getRepositories(
         STACK_NAME_HDP, "2.1.1", "redhat6");
     assertNotNull(redhat6Repo);
@@ -324,24 +333,6 @@ public class AmbariMetaInfoTest {
     assertFalse(invalid);
   }
 
-  /**
-   * Method: getSupportedConfigs(String stackName, String version, String
-   * serviceName)
-   */
-  @Test
-  public void getSupportedConfigs() throws Exception {
-
-    Map<String, Map<String, String>> configsAll = metaInfo.getSupportedConfigs(
-        STACK_NAME_HDP, STACK_VERSION_HDP, SERVICE_NAME_HDFS);
-    Set<String> filesKeys = configsAll.keySet();
-    for (String file : filesKeys) {
-      Map<String, String> configs = configsAll.get(file);
-      Set<String> propertyKeys = configs.keySet();
-      assertNotNull(propertyKeys);
-      assertFalse(propertyKeys.size() == 0);
-    }
-  }
-
   @Test
   public void testServiceNameUsingComponentName() throws AmbariException {
     String serviceName = metaInfo.getComponentToService(STACK_NAME_HDP,
@@ -374,31 +365,19 @@ public class AmbariMetaInfoTest {
    */
   @Test
   public void getServiceInfo() throws Exception {
-    ServiceInfo si = metaInfo.getServiceInfo(STACK_NAME_HDP, STACK_VERSION_HDP,
+    ServiceInfo si = metaInfo.getService(STACK_NAME_HDP, STACK_VERSION_HDP,
         SERVICE_NAME_HDFS);
     assertNotNull(si);
   }
 
   @Test
   public void testConfigDependencies() throws Exception {
-    ServiceInfo serviceInfo = metaInfo.getServiceInfo(STACK_NAME_HDP, EXT_STACK_NAME,
-      SERVICE_NAME_MAPRED2);
+    ServiceInfo serviceInfo = metaInfo.getService(STACK_NAME_HDP, EXT_STACK_NAME,
+        SERVICE_NAME_MAPRED2);
     assertNotNull(serviceInfo);
     assertTrue(!serviceInfo.getConfigDependencies().isEmpty());
   }
 
-  /**
-   * Method: getSupportedServices(String stackName, String version)
-   */
-  @Test
-  public void getSupportedServices() throws Exception {
-    List<ServiceInfo> services = metaInfo.getSupportedServices(STACK_NAME_HDP,
-        STACK_VERSION_HDP);
-    assertNotNull(services);
-    assertFalse(services.size() == 0);
-
-  }
-
   @Test
   public void testGetRepos() throws Exception {
     Map<String, List<RepositoryInfo>> repos = metaInfo.getRepository(
@@ -447,7 +426,7 @@ public class AmbariMetaInfoTest {
    * @throws Exception
    */
   public void testGlobalMapping() throws Exception {
-    ServiceInfo sinfo = metaInfo.getServiceInfo("HDP",
+    ServiceInfo sinfo = metaInfo.getService("HDP",
         "0.2", "HDFS");
     List<PropertyInfo> pinfo = sinfo.getProperties();
     /** check all the config knobs and make sure the global one is there **/
@@ -459,7 +438,7 @@ public class AmbariMetaInfoTest {
       }
     }
     Assert.assertTrue(checkforglobal);
-    sinfo = metaInfo.getServiceInfo("HDP",
+    sinfo = metaInfo.getService("HDP",
         "0.2", "MAPREDUCE");
     boolean checkforhadoopheapsize = false;
     pinfo = sinfo.getProperties();
@@ -479,8 +458,9 @@ public class AmbariMetaInfoTest {
     File stackRoot = new File("src/test/resources/stacks");
     File stackRootTmp = new File(buildDir + "/ambari-metaInfo"); stackRootTmp.mkdir();
     FileUtils.copyDirectory(stackRoot, stackRootTmp);
-    AmbariMetaInfo ambariMetaInfo = new AmbariMetaInfo(stackRootTmp, new File("target/version"));
-    ambariMetaInfo.injector = injector;
+    AmbariMetaInfo ambariMetaInfo = createAmbariMetaInfo(stackRootTmp, new File("target/version"), true);
+    //todo
+    //ambariMetaInfo.injector = injector;
     File f1, f2, f3;
     f1 = new File(stackRootTmp.getAbsolutePath() + "/001.svn"); f1.createNewFile();
     f2 = new File(stackRootTmp.getAbsolutePath() + "/abcd.svn/001.svn"); f2.mkdirs(); f2.createNewFile();
@@ -492,10 +472,8 @@ public class AmbariMetaInfoTest {
     // Tests the stack is loaded as expected
     getServices();
     getComponentsByService();
-    getComponentCategory();
-    getSupportedConfigs();
     // Check .svn is not part of the stack but abcd.svn is
-    Assert.assertNotNull(ambariMetaInfo.getStackInfo("abcd.svn", "001.svn"));
+    Assert.assertNotNull(ambariMetaInfo.getStack("abcd.svn", "001.svn"));
 
     Assert.assertFalse(ambariMetaInfo.isSupportedStack(".svn", ""));
     Assert.assertFalse(ambariMetaInfo.isSupportedStack(".svn", ""));
@@ -511,7 +489,6 @@ public class AmbariMetaInfoTest {
       metaInfo.getComponent(STACK_NAME_HDP,
           STACK_VERSION_HDP, SERVICE_NAME_HDFS, NON_EXT_VALUE);
     } catch (StackAccessException e) {
-      Assert.assertTrue(e instanceof StackAccessException);
     }
 
   }
@@ -530,7 +507,6 @@ public class AmbariMetaInfoTest {
     try {
       metaInfo.getRepository(STACK_NAME_HDP, STACK_VERSION_HDP, OS_TYPE, NON_EXT_VALUE);
     } catch (StackAccessException e) {
-      Assert.assertTrue(e instanceof StackAccessException);
     }
   }
 
@@ -541,40 +517,25 @@ public class AmbariMetaInfoTest {
     try {
       metaInfo.getService(STACK_NAME_HDP, STACK_VERSION_HDP, NON_EXT_VALUE);
     } catch (StackAccessException e) {
-      Assert.assertTrue(e instanceof StackAccessException);
     }
 
   }
 
   @Test
-  public void testGetStacksNames() throws Exception {
-    Set<Stack> stackNames = metaInfo.getStackNames();
-    assertEquals(stackNames.size(), STACKS_NAMES_CNT);
-    assertTrue(stackNames.contains(new Stack(STACK_NAME_HDP)));
-    assertTrue(stackNames.contains(new Stack(STACK_NAME_XYZ)));
-  }
-
-  @Test
-  public void testGetStack() throws Exception {
-    Stack stack = metaInfo.getStack(STACK_NAME_HDP);
-    Assert.assertEquals(stack.getStackName(), STACK_NAME_HDP);
-    try {
-      metaInfo.getStack(NON_EXT_VALUE);
-    } catch (StackAccessException e) {
-      Assert.assertTrue(e instanceof StackAccessException);
-    }
+  public void testGetStacks() {
+    Collection<StackInfo> stacks = metaInfo.getStacks();
+    //todo: complete test
   }
 
   @Test
   public void testGetStackInfo() throws Exception {
-    StackInfo stackInfo = metaInfo.getStackInfo(STACK_NAME_HDP, STACK_VERSION_HDP);
+    StackInfo stackInfo = metaInfo.getStack(STACK_NAME_HDP, STACK_VERSION_HDP);
     Assert.assertEquals(stackInfo.getName(), STACK_NAME_HDP);
     Assert.assertEquals(stackInfo.getVersion(), STACK_VERSION_HDP);
     Assert.assertEquals(stackInfo.getMinUpgradeVersion(), STACK_MINIMAL_VERSION_HDP);
     try {
-      metaInfo.getStackInfo(STACK_NAME_HDP, NON_EXT_VALUE);
+      metaInfo.getStack(STACK_NAME_HDP, NON_EXT_VALUE);
     } catch (StackAccessException e) {
-      Assert.assertTrue(e instanceof StackAccessException);
     }
   }
 
@@ -589,7 +550,7 @@ public class AmbariMetaInfoTest {
 
   @Test
   public void testGetProperties() throws Exception {
-    Set<PropertyInfo> properties = metaInfo.getProperties(STACK_NAME_HDP, STACK_VERSION_HDP, SERVICE_NAME_HDFS);
+    Set<PropertyInfo> properties = metaInfo.getServiceProperties(STACK_NAME_HDP, STACK_VERSION_HDP, SERVICE_NAME_HDFS);
     Assert.assertEquals(properties.size(), PROPERTIES_CNT);
   }
 
@@ -605,7 +566,6 @@ public class AmbariMetaInfoTest {
     try {
       metaInfo.getPropertiesByName(STACK_NAME_HDP, STACK_VERSION_HDP, SERVICE_NAME_HDFS, NON_EXT_VALUE);
     } catch (StackAccessException e) {
-      Assert.assertTrue(e instanceof StackAccessException);
     }
 
   }
@@ -636,7 +596,6 @@ public class AmbariMetaInfoTest {
     try {
       metaInfo.getOperatingSystem(STACK_NAME_HDP, STACK_VERSION_HDP, NON_EXT_VALUE);
     } catch (StackAccessException e) {
-      Assert.assertTrue(e instanceof StackAccessException);
     }
   }
 
@@ -656,9 +615,9 @@ public class AmbariMetaInfoTest {
 
   @Test
   public void testExtendedStackDefinition() throws Exception {
-    StackInfo stackInfo = metaInfo.getStackInfo(STACK_NAME_HDP, EXT_STACK_NAME);
+    StackInfo stackInfo = metaInfo.getStack(STACK_NAME_HDP, EXT_STACK_NAME);
     Assert.assertTrue(stackInfo != null);
-    List<ServiceInfo> serviceInfos = stackInfo.getServices();
+    Collection<ServiceInfo> serviceInfos = stackInfo.getServices();
     Assert.assertFalse(serviceInfos.isEmpty());
     Assert.assertTrue(serviceInfos.size() > 1);
     ServiceInfo deletedService = null;
@@ -740,86 +699,8 @@ public class AmbariMetaInfoTest {
   }
 
   @Test
-  public void testGetParentStacksInOrder() throws Exception {
-    List<StackInfo> allStacks = metaInfo.getSupportedStacks();
-    StackInfo stackInfo = metaInfo.getStackInfo(STACK_NAME_HDP, EXT_STACK_NAME);
-    StackInfo newStack = new StackInfo();
-    newStack.setName(STACK_NAME_HDP);
-    newStack.setVersion("2.0.99");
-    newStack.setParentStackVersion(EXT_STACK_NAME);
-    newStack.setActive(true);
-    newStack.setRepositories(stackInfo.getRepositories());
-    allStacks.add(newStack);
-
-    Method method = StackExtensionHelper.class.getDeclaredMethod
-      ("getParentStacksInOrder", Collection.class);
-    method.setAccessible(true);
-    StackExtensionHelper helper = new StackExtensionHelper(injector, metaInfo.getStackRoot());
-    helper.fillInfo();
-    Map<String, List<StackInfo>> stacks =
-      (Map<String, List<StackInfo>>) method.invoke(helper, allStacks);
-
-    Assert.assertNotNull(stacks.get("2.0.99"));
-    // Verify order
-    LinkedList<String> target = new LinkedList<String>();
-    target.add("2.0.5");
-    target.add("2.0.6");
-    target.add("2.0.99");
-    LinkedList<String> actual = new LinkedList<String>();
-    LinkedList<StackInfo> parents = (LinkedList<StackInfo>) stacks.get("2.0.99");
-    parents.addFirst(newStack);
-    ListIterator lt = parents.listIterator(parents.size());
-    while (lt.hasPrevious()) {
-      StackInfo stack = (StackInfo) lt.previous();
-      actual.add(stack.getVersion());
-    }
-    org.junit.Assert.assertArrayEquals("Order of stack extension not " +
-      "preserved.", target.toArray(), actual.toArray());
-  }
-
-  @Test
-  public void testGetApplicableServices() throws Exception {
-    StackExtensionHelper helper = new StackExtensionHelper(injector,
-      metaInfo.getStackRoot());
-    helper.fillInfo();
-    List<ServiceInfo> allServices = helper.getAllApplicableServices(metaInfo
-      .getStackInfo(STACK_NAME_HDP, EXT_STACK_NAME));
-
-    ServiceInfo testService = null;
-    ServiceInfo existingService = null;
-    for (ServiceInfo serviceInfo : allServices) {
-      if (serviceInfo.getName().equals("YARN")) {
-        testService = serviceInfo;
-      } else if (serviceInfo.getName().equals("MAPREDUCE2")) {
-        existingService = serviceInfo;
-      }
-    }
-
-    Assert.assertNotNull(testService);
-    Assert.assertNotNull(existingService);
-
-    PropertyInfo testProperty = null;
-    PropertyInfo existingProperty = null;
-    for (PropertyInfo property : testService.getProperties()) {
-      if (property.getName().equals("new-yarn-property")) {
-        testProperty = property;
-      }
-    }
-    for (PropertyInfo property : existingService.getProperties()) {
-      if (property.getName().equals("mapreduce.map.log.level")) {
-        existingProperty = property;
-      }
-    }
-
-    Assert.assertNotNull(testProperty);
-    Assert.assertEquals("some-value", testProperty.getValue());
-    Assert.assertNotNull(existingProperty);
-    Assert.assertEquals("INFO", existingProperty.getValue());
-  }
-
-  @Test
   public void testPropertyCount() throws Exception {
-    Set<PropertyInfo> properties = metaInfo.getProperties(STACK_NAME_HDP, STACK_VERSION_HDP_02, SERVICE_NAME_HDFS);
+    Set<PropertyInfo> properties = metaInfo.getServiceProperties(STACK_NAME_HDP, STACK_VERSION_HDP_02, SERVICE_NAME_HDFS);
     // 3 empty properties
     Assert.assertEquals(103, properties.size());
   }
@@ -828,12 +709,13 @@ public class AmbariMetaInfoTest {
   public void testBadStack() throws Exception {
     File stackRoot = new File("src/test/resources/bad-stacks");
     LOG.info("Stacks file " + stackRoot.getAbsolutePath());
-    AmbariMetaInfo mi = new AmbariMetaInfo(stackRoot, new File("target/version"));
-    mi.injector = injector;
+
     try {
-      mi.init();
-    } catch(Exception e) {
-      assertTrue(JAXBException.class.isInstance(e));
+      createAmbariMetaInfo(stackRoot, new File("target/version"), true);
+      fail("Exception expected due to bad stack");
+    } catch(AmbariException e) {
+      e.printStackTrace();
+      assertTrue(e.getCause() instanceof JAXBException);
     }
   }
 
@@ -1262,13 +1144,13 @@ public class AmbariMetaInfoTest {
   @Test
   public void testHooksDirInheritance() throws Exception {
     // Test hook dir determination in parent
-    StackInfo stackInfo = metaInfo.getStackInfo(STACK_NAME_HDP, "2.0.6");
+    StackInfo stackInfo = metaInfo.getStack(STACK_NAME_HDP, "2.0.6");
     Assert.assertEquals("HDP/2.0.6/hooks", stackInfo.getStackHooksFolder());
     // Test hook dir inheritance
-    stackInfo = metaInfo.getStackInfo(STACK_NAME_HDP, "2.0.7");
+    stackInfo = metaInfo.getStack(STACK_NAME_HDP, "2.0.7");
     Assert.assertEquals("HDP/2.0.6/hooks", stackInfo.getStackHooksFolder());
     // Test hook dir override
-    stackInfo = metaInfo.getStackInfo(STACK_NAME_HDP, "2.0.8");
+    stackInfo = metaInfo.getStack(STACK_NAME_HDP, "2.0.8");
     Assert.assertEquals("HDP/2.0.8/hooks", stackInfo.getStackHooksFolder());
   }
 
@@ -1317,21 +1199,21 @@ public class AmbariMetaInfoTest {
   public void testComponentCommandScriptInheritance() throws Exception {
     // Test command script determination in parent
     ComponentInfo component = metaInfo.getComponent(STACK_NAME_HDP,
-            "2.0.7", "HDFS", "HDFS_CLIENT");
+        "2.0.7", "HDFS", "HDFS_CLIENT");
     Assert.assertEquals("scripts/hdfs_client.py",
             component.getCommandScript().getScript());
     component = metaInfo.getComponent(STACK_NAME_HDP,
-            "2.0.7", "HBASE", "HBASE_MASTER");
+        "2.0.7", "HBASE", "HBASE_MASTER");
     Assert.assertEquals("scripts/hbase_master.py",
             component.getCommandScript().getScript());
     // Test command script inheritance
     component = metaInfo.getComponent(STACK_NAME_HDP,
-            "2.0.8", "HBASE", "HBASE_MASTER");
+        "2.0.8", "HBASE", "HBASE_MASTER");
     Assert.assertEquals("scripts/hbase_master.py",
             component.getCommandScript().getScript());
     // Test command script override
     component = metaInfo.getComponent(STACK_NAME_HDP,
-            "2.0.8", "HDFS", "HDFS_CLIENT");
+        "2.0.8", "HDFS", "HDFS_CLIENT");
     Assert.assertEquals("scripts/hdfs_client_overridden.py",
             component.getCommandScript().getScript());
   }
@@ -1484,6 +1366,18 @@ public class AmbariMetaInfoTest {
 
   @Test
   public void testLatestRepo() throws Exception {
+    // ensure that all of the latest repo retrieval tasks have completed
+    StackManager sm = metaInfo.getStackManager();
+    int maxWait = 45000;
+    int waitTime = 0;
+    while (waitTime < maxWait && ! sm.haveAllRepoUrlsBeenResolved()) {
+      Thread.sleep(5);
+      waitTime += 5;
+    }
+
+    if (waitTime >= maxWait) {
+      fail("Latest Repo tasks did not complete");
+    }
 
     for (RepositoryInfo ri : metaInfo.getRepositories("HDP", "2.1.1", "centos6")) {
       Assert.assertEquals(
@@ -1651,6 +1545,8 @@ public class AmbariMetaInfoTest {
     assertTrue(ignoreHost.isHostIgnored());
   }
 
+
+  //todo: refactor test to use mocks instead of injector
   /**
    * Tests merging stack-based with existing definitions works
    *
@@ -1658,7 +1554,19 @@ public class AmbariMetaInfoTest {
    */
   @Test
   public void testAlertDefinitionMerging() throws Exception {
+    Injector injector = Guice.createInjector(Modules.override(
+        new InMemoryDefaultTestModule()).with(new MockModule()));
+
+    injector.getInstance(GuiceJpaInitializer.class);
+    injector.getInstance(EntityManager.class);
     injector.getInstance(OrmTestHelper.class).createCluster();
+
+    metaInfo.alertDefinitionDao = injector.getInstance(AlertDefinitionDAO.class);
+    Class<?> c = metaInfo.getClass().getSuperclass();
+    Field f = c.getDeclaredField("agentAlertDefinitions");
+    f.setAccessible(true);
+    f.set(metaInfo, injector.getInstance(AgentAlertDefinitions.class));
+
     Clusters clusters = injector.getInstance(Clusters.class);
     Cluster cluster = clusters.getClusterById(1);
     cluster.setDesiredStackVersion(
@@ -1700,15 +1608,102 @@ public class AmbariMetaInfoTest {
     }
   }
 
-  private AmbariMetaInfo setupTempAmbariMetaInfo(String buildDir)
+  private TestAmbariMetaInfo setupTempAmbariMetaInfo(String buildDir, boolean replayMocks)
       throws Exception {
     File stackRootTmp = new File(buildDir + "/ambari-metaInfo");
     File stackRoot = new File("src/test/resources/stacks");
     stackRootTmp.mkdir();
     FileUtils.copyDirectory(stackRoot, stackRootTmp);
-    AmbariMetaInfo ambariMetaInfo = new AmbariMetaInfo(stackRootTmp, new File(
-        "target/version"));
-    injector.injectMembers(ambariMetaInfo);
+    TestAmbariMetaInfo ambariMetaInfo = createAmbariMetaInfo(stackRootTmp, new File(
+        "target/version"), replayMocks);
+
     return ambariMetaInfo;
   }
+
+  private TestAmbariMetaInfo createAmbariMetaInfo(File stackRoot, File versionFile, boolean replayMocks) throws Exception {
+    TestAmbariMetaInfo metaInfo = new TestAmbariMetaInfo(stackRoot, versionFile);
+    if (replayMocks) {
+      metaInfo.replayAllMocks();
+
+      try {
+        metaInfo.init();
+      } catch(Exception e) {
+        LOG.info("Error in initializing ", e);
+        throw e;
+      }
+      waitForAllReposToBeResolved(metaInfo);
+    }
+
+    return metaInfo;
+  }
+
+  private void waitForAllReposToBeResolved(AmbariMetaInfo metaInfo) throws Exception {
+    int maxWait = 45000;
+    int waitTime = 0;
+    StackManager sm = metaInfo.getStackManager();
+    while (waitTime < maxWait && ! sm.haveAllRepoUrlsBeenResolved()) {
+      Thread.sleep(5);
+      waitTime += 5;
+    }
+
+    if (waitTime >= maxWait) {
+      fail("Latest Repo tasks did not complete");
+    }
+  }
+
+  private static class TestAmbariMetaInfo extends AmbariMetaInfo {
+
+    MetainfoDAO metaInfoDAO;
+    AlertDefinitionDAO alertDefinitionDAO;
+    AlertDefinitionFactory alertDefinitionFactory;
+    OsFamily osFamily;
+
+    public TestAmbariMetaInfo(File stackRoot, File serverVersionFile) throws Exception {
+      super(stackRoot, serverVersionFile);
+      // MetainfoDAO
+      metaInfoDAO = createNiceMock(MetainfoDAO.class);
+      Class<?> c = getClass().getSuperclass();
+      Field f = c.getDeclaredField("metaInfoDAO");
+      f.setAccessible(true);
+      f.set(this, metaInfoDAO);
+
+      // ActionMetadata
+      ActionMetadata actionMetadata = new ActionMetadata();
+      f = c.getDeclaredField("actionMetadata");
+      f.setAccessible(true);
+      f.set(this, actionMetadata);
+
+      //AlertDefinitionDAO
+      alertDefinitionDAO = createNiceMock(AlertDefinitionDAO.class);
+      f = c.getDeclaredField("alertDefinitionDao");
+      f.setAccessible(true);
+      f.set(this, alertDefinitionDAO);
+
+      //AlertDefinitionFactory
+      //alertDefinitionFactory = createNiceMock(AlertDefinitionFactory.class);
+      alertDefinitionFactory = new AlertDefinitionFactory();
+      f = c.getDeclaredField("alertDefinitionFactory");
+      f.setAccessible(true);
+      f.set(this, alertDefinitionFactory);
+
+      //AmbariEventPublisher
+      AmbariEventPublisher ambariEventPublisher = new AmbariEventPublisher();
+      f = c.getDeclaredField("eventPublisher");
+      f.setAccessible(true);
+      f.set(this, ambariEventPublisher);
+
+      //OSFamily
+      Configuration config = createNiceMock(Configuration.class);
+      expect(config.getSharedResourcesDirPath()).andReturn("./src/test/resources").anyTimes();
+      replay(config);
+      osFamily = new OsFamily(config);
+      f = c.getDeclaredField("os_family");
+      f.setAccessible(true);
+      f.set(this, osFamily);
+    }
+
+    public void replayAllMocks() {
+      replay(metaInfoDAO, alertDefinitionDAO);
+    }
+  }
 }