ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From srima...@apache.org
Subject git commit: AMBARI-6566. Provide properties_attributes to blueprints endpoint
Date Thu, 24 Jul 2014 16:37:58 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk f5c3c22bd -> 2313d2006


AMBARI-6566. Provide properties_attributes to blueprints endpoint


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

Branch: refs/heads/trunk
Commit: 2313d20063829cc452b8df589737290fda7b48ce
Parents: f5c3c22
Author: Srimanth Gunturi <sgunturi@hortonworks.com>
Authored: Tue Jul 22 11:04:18 2014 -0700
Committer: Srimanth Gunturi <sgunturi@hortonworks.com>
Committed: Thu Jul 24 09:37:44 2014 -0700

----------------------------------------------------------------------
 .../internal/BlueprintResourceProvider.java     | 142 +++++++--
 .../orm/entities/BlueprintConfigEntity.java     |  22 ++
 .../orm/entities/BlueprintConfiguration.java    |  16 +
 .../orm/entities/HostGroupConfigEntity.java     |  23 ++
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   4 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   4 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   4 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |   4 +-
 .../internal/BlueprintResourceProviderTest.java | 292 ++++++++++++++++---
 9 files changed, 448 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2313d200/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java
index 747c7a4..1fa71ce 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintResourceProvider.java
@@ -82,6 +82,8 @@ public class BlueprintResourceProvider extends BaseBlueprintProcessor {
 
   // Configurations
   protected static final String CONFIGURATION_PROPERTY_ID = "configurations";
+  protected static final String PROPERTIES_PROPERTY_ID = "properties";
+  protected static final String PROPERTIES_ATTRIBUTES_PROPERTY_ID = "properties_attributes";
 
   // Primary Key Fields
   private static Set<String> pkPropertyIds =
@@ -435,16 +437,23 @@ public class BlueprintResourceProvider extends BaseBlueprintProcessor
{
    *
    * @return list of configuration property maps
    */
-  private List<Map<String, Object>> populateConfigurationList(
+  List<Map<String, Map<String, Object>>> populateConfigurationList(
       Collection<? extends BlueprintConfiguration> configurations) {
 
-    List<Map<String, Object>> listConfigurations = new ArrayList<Map<String,
Object>>();
+    List<Map<String, Map<String, Object>>> listConfigurations = new ArrayList<Map<String,
Map<String, Object>>>();
     for (BlueprintConfiguration config : configurations) {
-      Map<String, Object> mapConfigurations = new HashMap<String, Object>();
+      Map<String, Map<String, Object>> mapConfigurations = new HashMap<String,
Map<String, Object>>();
+      Map<String, Object> configTypeDefinition = new HashMap<String, Object>();
       String type = config.getType();
-      Map<String, String> properties = jsonSerializer.<Map<String, String>>fromJson(
+      Map<String, Object> properties = jsonSerializer.<Map<String, Object>>fromJson(
           config.getConfigData(), Map.class);
-      mapConfigurations.put(type, properties);
+      configTypeDefinition.put(PROPERTIES_PROPERTY_ID, properties);
+      Map<String, Map<String, String>> attributes = jsonSerializer.<Map<String,
Map<String, String>>>fromJson(
+          config.getConfigAttributes(), Map.class);
+      if (attributes != null && !attributes.isEmpty()) {
+        configTypeDefinition.put(PROPERTIES_ATTRIBUTES_PROPERTY_ID, attributes);
+      }
+      mapConfigurations.put(type, configTypeDefinition);
       listConfigurations.add(mapConfigurations);
     }
 
@@ -457,7 +466,7 @@ public class BlueprintResourceProvider extends BaseBlueprintProcessor
{
    * @param propertyMaps  collection of configuration property maps
    * @param blueprint     blueprint entity to set configurations on
    */
-  private void createBlueprintConfigEntities(Collection<Map<String, String>>
propertyMaps,
+  void createBlueprintConfigEntities(Collection<Map<String, String>> propertyMaps,
                                              BlueprintEntity blueprint) {
 
     Collection<BlueprintConfigEntity> configurations = new ArrayList<BlueprintConfigEntity>();
@@ -465,7 +474,8 @@ public class BlueprintResourceProvider extends BaseBlueprintProcessor
{
       for (Map<String, String> configuration : propertyMaps) {
         BlueprintConfigEntity configEntity = new BlueprintConfigEntity();
         configEntity.setBlueprintEntity(blueprint);
-        populateConfigurationEntity(blueprint.getBlueprintName(), configuration, configEntity);
+        configEntity.setBlueprintName(blueprint.getBlueprintName());
+        populateConfigurationEntity(configuration, configEntity);
         configurations.add(configEntity);
       }
     }
@@ -487,7 +497,8 @@ public class BlueprintResourceProvider extends BaseBlueprintProcessor
{
         HostGroupConfigEntity configEntity = new HostGroupConfigEntity();
         configEntity.setHostGroupEntity(hostGroup);
         configEntity.setHostGroupName(hostGroup.getName());
-        populateConfigurationEntity(hostGroup.getBlueprintName(), configuration, configEntity);
+        configEntity.setBlueprintName(hostGroup.getBlueprintName());
+        populateConfigurationEntity(configuration, configEntity);
         configurations.add(configEntity);
       }
     }
@@ -497,26 +508,31 @@ public class BlueprintResourceProvider extends BaseBlueprintProcessor
{
   /**
    * Populate a configuration entity from properties.
    *
-   * @param blueprintName  name of blueprint
    * @param configuration  property map
    * @param configEntity   config entity to populate
    */
-  private void populateConfigurationEntity(String blueprintName, Map<String, String>
configuration,
-                                           BlueprintConfiguration configEntity) {
-
-    configEntity.setBlueprintName(blueprintName);
-    Map<String, String> configData = new HashMap<String, String>();
-
-    for (Map.Entry<String, String> entry : configuration.entrySet()) {
-      String absolutePropName = entry.getKey();
+  void populateConfigurationEntity(Map<String, String> configuration, BlueprintConfiguration
configEntity) {
+    BlueprintConfigPopulationStrategy p = decidePopulationStrategy(configuration);
+    p.applyConfiguration(configuration, configEntity);
+  }
 
-      int idx = absolutePropName.indexOf('/');
-      if (configEntity.getType() == null) {
-        configEntity.setType(absolutePropName.substring(0, idx));
+  BlueprintConfigPopulationStrategy decidePopulationStrategy(Map<String, String> configuration)
{
+    if (configuration != null && !configuration.isEmpty()) {
+      String keyEntry = configuration.keySet().iterator().next();
+      String[] keyNameTokens = keyEntry.split("/");
+      int levels = keyNameTokens.length;
+      String propertiesType = keyNameTokens[1];
+      if (levels == 2) {
+        return new BlueprintConfigPopulationStrategyV1();
+      } else if ((levels == 3 && PROPERTIES_PROPERTY_ID.equals(propertiesType))
+          || (levels == 4 && PROPERTIES_ATTRIBUTES_PROPERTY_ID.equals(propertiesType)))
{
+        return new BlueprintConfigPopulationStrategyV2();
+      } else {
+        throw new IllegalArgumentException("Configuration format provided in Blueprint is
not supported");
       }
-      configData.put(absolutePropName.substring(idx + 1), entry.getValue());
+    } else {
+      return new BlueprintConfigPopulationStrategyV2();
     }
-    configEntity.setConfigData(jsonSerializer.toJson(configData));
   }
 
   /**
@@ -563,4 +579,86 @@ public class BlueprintResourceProvider extends BaseBlueprintProcessor
{
       }
     };
   }
+
+  /**
+   * The structure of blueprints is evolving where multiple resource
+   * structures are to be supported. This class abstracts the population
+   * of configurations which have changed from a map of key-value strings,
+   * to an map containing 'properties' and 'properties_attributes' maps.
+   *
+   * Extending classes can determine how they want to populate the
+   * configuration maps depending on input.
+   */
+  protected static abstract class BlueprintConfigPopulationStrategy {
+
+    public void applyConfiguration(Map<String, String> configuration, BlueprintConfiguration
blueprintConfiguration) {
+      Map<String, String> configData = new HashMap<String, String>();
+      Map<String, Map<String, String>> configAttributes = new HashMap<String,
Map<String, String>>();
+
+      if (configuration != null) {
+        for (Map.Entry<String, String> entry : configuration.entrySet()) {
+          String absolutePropName = entry.getKey();
+          String propertyValue = entry.getValue();
+          String[] propertyNameTokens = absolutePropName.split("/");
+
+          if (blueprintConfiguration.getType() == null) {
+            blueprintConfiguration.setType(propertyNameTokens[0]);
+          }
+
+          addProperty(configData, configAttributes, propertyNameTokens, propertyValue);
+        }
+      }
+
+      blueprintConfiguration.setConfigData(jsonSerializer.toJson(configData));
+      blueprintConfiguration.setConfigAttributes(jsonSerializer.toJson(configAttributes));
+    }
+
+    protected abstract void addProperty(Map<String, String> configData,
+                                        Map<String, Map<String, String>> configAttributes,
+                                        String[] propertyNameTokens, String propertyValue);
+  }
+
+  /**
+   * Original blueprint configuration format where configs were a map
+   * of strings.
+   */
+  protected static class BlueprintConfigPopulationStrategyV1 extends BlueprintConfigPopulationStrategy
{
+
+    @Override
+    protected void addProperty(Map<String, String> configData,
+                               Map<String, Map<String, String>> configAttributes,
+                               String[] propertyNameTokens, String propertyValue) {
+      configData.put(propertyNameTokens[1], propertyValue);
+    }
+
+  }
+
+  /**
+   * New blueprint configuration format where configs are a map from 'properties' and
+   * 'properties_attributes' to a map of strings.
+   * 
+   * @since 1.7.0
+   */
+  protected static class BlueprintConfigPopulationStrategyV2 extends BlueprintConfigPopulationStrategy
{
+
+    @Override
+    protected void addProperty(Map<String, String> configData,
+                               Map<String, Map<String, String>> configAttributes,
+                               String[] propertyNameTokens, String propertyValue) {
+      if (PROPERTIES_PROPERTY_ID.equals(propertyNameTokens[1])) {
+        configData.put(propertyNameTokens[2], propertyValue);
+      } else if (PROPERTIES_ATTRIBUTES_PROPERTY_ID.equals(propertyNameTokens[1])) {
+        addConfigAttribute(configAttributes, propertyNameTokens, propertyValue);
+      }
+    }
+
+    private void addConfigAttribute(Map<String, Map<String, String>> configDependencyProperties,
+                                    String[] propertyNameTokens, String value) {
+      if (!configDependencyProperties.containsKey(propertyNameTokens[2])) {
+        configDependencyProperties.put(propertyNameTokens[2], new HashMap<String, String>());
+      }
+      Map<String, String> propertiesGroup = configDependencyProperties.get(propertyNameTokens[2]);
+      propertiesGroup.put(propertyNameTokens[3], value);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2313d200/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfigEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfigEntity.java
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfigEntity.java
index bc2e039..1495704 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfigEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfigEntity.java
@@ -46,6 +46,10 @@ public class BlueprintConfigEntity implements BlueprintConfiguration {
   @Basic
   private String configData;
 
+  @Column(name = "config_attributes", nullable = true, insertable = true, updatable = false)
+  @Basic
+  private String configAttributes;
+
   @ManyToOne
   @JoinColumn(name = "blueprint_name", referencedColumnName = "blueprint_name", nullable
= false)
   private BlueprintEntity blueprint;
@@ -122,4 +126,22 @@ public class BlueprintConfigEntity implements BlueprintConfiguration
{
   public void setConfigData(String configData) {
     this.configData = configData;
   }
+
+  /**
+   * Gets the attributes of configs.
+   *
+   * @return config attributes in JSON format
+   */
+  public String getConfigAttributes() {
+    return configAttributes;
+  }
+
+  /**
+   * Sets attributes of configs.
+   *
+   * @param configAttributes  all attribute values of configs in JSON format
+   */
+  public void setConfigAttributes(String configAttributes) {
+    this.configAttributes = configAttributes;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2313d200/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfiguration.java
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfiguration.java
index 761c7bb..36dde73 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfiguration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/BlueprintConfiguration.java
@@ -65,4 +65,20 @@ public interface BlueprintConfiguration {
    * @return json representation of property map
    */
   public String getConfigData();
+
+  /**
+   * Get the configuration attributes.
+   *
+   * @return json representation of attributes map
+   */
+  public String getConfigAttributes();
+
+  /**
+   * Set the configuration attributes.
+   * Data must be a map of configuration attributes in
+   * json format.
+   *
+   * @param configAttributes json representation of attributes map
+   */
+  public void setConfigAttributes(String configAttributes);
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2313d200/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupConfigEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupConfigEntity.java
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupConfigEntity.java
index db44eef..cc4e0c6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupConfigEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostGroupConfigEntity.java
@@ -52,6 +52,11 @@ public class HostGroupConfigEntity implements BlueprintConfiguration {
   @Basic
   private String configData;
 
+  @Column(name = "config_attributes", nullable = true, insertable = true, updatable = false)
+  @Basic
+  private String configAttributes;
+
+
   @ManyToOne
   @JoinColumns({
       @JoinColumn(name = "hostgroup_name", referencedColumnName = "name", nullable = false),
@@ -149,4 +154,22 @@ public class HostGroupConfigEntity implements BlueprintConfiguration
{
   public void setConfigData(String configData) {
     this.configData = configData;
   }
+
+  /**
+   * Gets the attributes of configs in this host group.
+   *
+   * @return config attributes in JSON format
+   */
+  public String getConfigAttributes() {
+    return configAttributes;
+  }
+
+  /**
+   * Sets attributes of configs in this host group.
+   *
+   * @param configAttributes  all attribute values of configs in JSON format
+   */
+  public void setConfigAttributes(String configAttributes) {
+    this.configAttributes = configAttributes;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2313d200/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index 3d70b28..d55444e 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -62,8 +62,8 @@ CREATE TABLE requestschedulebatchrequest (schedule_id bigint, batch_id bigint,
r
 CREATE TABLE blueprint (blueprint_name VARCHAR(255) NOT NULL, stack_name VARCHAR(255) NOT
NULL, stack_version VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name));
 CREATE TABLE hostgroup (blueprint_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL,
cardinality VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name, name));
 CREATE TABLE hostgroup_component (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name VARCHAR(255)
NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name, hostgroup_name, name));
-CREATE TABLE blueprint_configuration (blueprint_name VARCHAR(255) NOT NULL, type_name VARCHAR(255)
NOT NULL, config_data VARCHAR(32000) NOT NULL , PRIMARY KEY(blueprint_name, type_name));
-CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name
VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data TEXT NOT NULL, PRIMARY
KEY(blueprint_name, hostgroup_name, type_name));
+CREATE TABLE blueprint_configuration (blueprint_name VARCHAR(255) NOT NULL, type_name VARCHAR(255)
NOT NULL, config_data VARCHAR(32000) NOT NULL, config_attributes VARCHAR(32000), PRIMARY KEY(blueprint_name,
type_name));
+CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name
VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data TEXT NOT NULL, config_attributes
TEXT, PRIMARY KEY(blueprint_name, hostgroup_name, type_name));
 CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255),
resource_type_id INTEGER NOT NULL, icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255),
mask VARCHAR(255), PRIMARY KEY(view_name));
 CREATE TABLE viewinstancedata (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL,
view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255)
NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(VIEW_INSTANCE_ID, NAME, USER_NAME));
 CREATE TABLE viewinstance (view_instance_id BIGINT, resource_id BIGINT NOT NULL, view_name
VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255),
visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));

http://git-wip-us.apache.org/repos/asf/ambari/blob/2313d200/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index bf490f0..30d9e0a 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -52,8 +52,8 @@ CREATE TABLE requestschedulebatchrequest (schedule_id NUMBER(19), batch_id
NUMBE
 CREATE TABLE blueprint (blueprint_name VARCHAR2(255) NOT NULL, stack_name VARCHAR2(255) NOT
NULL, stack_version VARCHAR2(255) NOT NULL, PRIMARY KEY(blueprint_name));
 CREATE TABLE hostgroup (blueprint_name VARCHAR2(255) NOT NULL, name VARCHAR2(255) NOT NULL,
cardinality VARCHAR2(255) NOT NULL, PRIMARY KEY(blueprint_name, name));
 CREATE TABLE hostgroup_component (blueprint_name VARCHAR2(255) NOT NULL, hostgroup_name VARCHAR2(255)
NOT NULL, name VARCHAR2(255) NOT NULL, PRIMARY KEY(blueprint_name, hostgroup_name, name));
-CREATE TABLE blueprint_configuration (blueprint_name VARCHAR2(255) NOT NULL, type_name VARCHAR2(255)
NOT NULL, config_data CLOB NOT NULL , PRIMARY KEY(blueprint_name, type_name));
-CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR2(255) NOT NULL, hostgroup_name
VARCHAR2(255) NOT NULL, type_name VARCHAR2(255) NOT NULL, config_data CLOB NOT NULL, PRIMARY
KEY(blueprint_name, hostgroup_name, type_name));
+CREATE TABLE blueprint_configuration (blueprint_name VARCHAR2(255) NOT NULL, type_name VARCHAR2(255)
NOT NULL, config_data CLOB NOT NULL, config_attributes CLOB, PRIMARY KEY(blueprint_name, type_name));
+CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR2(255) NOT NULL, hostgroup_name
VARCHAR2(255) NOT NULL, type_name VARCHAR2(255) NOT NULL, config_data CLOB NOT NULL, config_attributes
CLOB, PRIMARY KEY(blueprint_name, hostgroup_name, type_name));
 CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255),
resource_type_id NUMBER(10) NOT NULL, icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255),
mask VARCHAR(255), PRIMARY KEY(view_name));
 CREATE TABLE viewinstancedata (view_instance_id NUMBER(19), view_name VARCHAR(255) NOT NULL,
view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255)
NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_instance_id, name, user_name));
 CREATE TABLE viewinstance (view_instance_id NUMBER(19), resource_id NUMBER(19) NOT NULL,
view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description
VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));

http://git-wip-us.apache.org/repos/asf/ambari/blob/2313d200/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index d44c8e3..b32a6f7 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -86,8 +86,8 @@ CREATE TABLE requestschedulebatchrequest (schedule_id bigint, batch_id bigint,
r
 CREATE TABLE blueprint (blueprint_name VARCHAR(255) NOT NULL, stack_name VARCHAR(255) NOT
NULL, stack_version VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name));
 CREATE TABLE hostgroup (blueprint_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL,
cardinality VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name, name));
 CREATE TABLE hostgroup_component (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name VARCHAR(255)
NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name, hostgroup_name, name));
-CREATE TABLE blueprint_configuration (blueprint_name varchar(255) NOT NULL, type_name varchar(255)
NOT NULL, config_data varchar(32000) NOT NULL , PRIMARY KEY(blueprint_name, type_name));
-CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name
VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data TEXT NOT NULL, PRIMARY
KEY(blueprint_name, hostgroup_name, type_name));
+CREATE TABLE blueprint_configuration (blueprint_name varchar(255) NOT NULL, type_name varchar(255)
NOT NULL, config_data varchar(32000) NOT NULL , config_attributes varchar(32000), PRIMARY
KEY(blueprint_name, type_name));
+CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name
VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data TEXT NOT NULL, config_attributes
varchar(32000), PRIMARY KEY(blueprint_name, hostgroup_name, type_name));
 
 CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255),
resource_type_id INTEGER NOT NULL, icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255),
mask VARCHAR(255), PRIMARY KEY(view_name));
 CREATE TABLE viewinstancedata (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL,
view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255)
NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_instance_id, name, user_name));

http://git-wip-us.apache.org/repos/asf/ambari/blob/2313d200/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index 723058b..bcb8145 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -130,8 +130,8 @@ GRANT ALL PRIVILEGES ON TABLE ambari.requestschedulebatchrequest TO :username;
 CREATE TABLE ambari.blueprint (blueprint_name VARCHAR(255) NOT NULL, stack_name VARCHAR(255)
NOT NULL, stack_version VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name));
 CREATE TABLE ambari.hostgroup (blueprint_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT
NULL, cardinality VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name, name));
 CREATE TABLE ambari.hostgroup_component (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name
VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name, hostgroup_name,
name));
-CREATE TABLE ambari.blueprint_configuration (blueprint_name varchar(255) NOT NULL, type_name
varchar(255) NOT NULL, config_data varchar(32000) NOT NULL , PRIMARY KEY(blueprint_name, type_name));
-CREATE TABLE ambari.hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name
VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data TEXT NOT NULL, PRIMARY
KEY(blueprint_name, hostgroup_name, type_name));
+CREATE TABLE ambari.blueprint_configuration (blueprint_name varchar(255) NOT NULL, type_name
varchar(255) NOT NULL, config_data varchar(32000) NOT NULL, config_attributes varchar(32000),
PRIMARY KEY(blueprint_name, type_name));
+CREATE TABLE ambari.hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name
VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data TEXT NOT NULL, config_attributes
varchar(32000), PRIMARY KEY(blueprint_name, hostgroup_name, type_name));
 GRANT ALL PRIVILEGES ON TABLE ambari.blueprint TO :username;
 GRANT ALL PRIVILEGES ON TABLE ambari.hostgroup TO :username;
 GRANT ALL PRIVILEGES ON TABLE ambari.hostgroup_component TO :username;

http://git-wip-us.apache.org/repos/asf/ambari/blob/2313d200/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
index 2da3fe5..3f732f8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/BlueprintResourceProviderTest.java
@@ -41,6 +41,7 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.dao.BlueprintDAO;
 import org.apache.ambari.server.orm.entities.BlueprintConfigEntity;
+import org.apache.ambari.server.orm.entities.BlueprintConfiguration;
 import org.apache.ambari.server.orm.entities.BlueprintEntity;
 import org.apache.ambari.server.orm.entities.HostGroupComponentEntity;
 import org.apache.ambari.server.orm.entities.HostGroupConfigEntity;
@@ -49,6 +50,7 @@ import org.apache.ambari.server.state.AutoDeployInfo;
 import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.DependencyInfo;
 import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.utils.StageUtils;
 import org.easymock.Capture;
 
 import static org.easymock.EasyMock.expectLastCall;
@@ -60,9 +62,12 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertNotNull;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -72,6 +77,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import static org.apache.ambari.server.controller.internal.BlueprintResourceProvider.*;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.createNiceMock;
@@ -90,6 +96,10 @@ public class BlueprintResourceProviderTest {
 
   private static String BLUEPRINT_NAME = "test-blueprint";
 
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private final static BlueprintResourceProvider provider = createProvider();
   private final static BlueprintDAO dao = createStrictMock(BlueprintDAO.class);
   private final static Gson gson = new Gson();
   private final static AmbariMetaInfo metaInfo = createMock(AmbariMetaInfo.class);
@@ -312,7 +322,6 @@ public class BlueprintResourceProviderTest {
                                                    NoSuchParentResourceException, NoSuchResourceException
{
     Request request = createNiceMock(Request.class);
 
-    ResourceProvider provider = createProvider();
     BlueprintEntity entity = createEntity(getTestProperties().iterator().next());
 
     List<BlueprintEntity> results = new ArrayList<BlueprintEntity>();
@@ -334,7 +343,6 @@ public class BlueprintResourceProviderTest {
       NoSuchParentResourceException, NoSuchResourceException {
     Request request = createNiceMock(Request.class);
 
-    ResourceProvider provider = createProvider();
     Set<Map<String, Object>> testProperties = getTestProperties();
     setConfigurationProperties(testProperties);
     BlueprintEntity entity = createEntity(testProperties.iterator().next());
@@ -358,7 +366,6 @@ public class BlueprintResourceProviderTest {
   public void testDeleteResources() throws SystemException, UnsupportedPropertyException,
                                            NoSuchParentResourceException, NoSuchResourceException
{
 
-    ResourceProvider provider = createProvider();
     BlueprintEntity blueprintEntity = createEntity(getTestProperties().iterator().next());
 
     // set expectations
@@ -400,7 +407,6 @@ public class BlueprintResourceProviderTest {
     replay(dao, metaInfo, request);
     // end expectations
 
-    ResourceProvider provider = createProvider();
     try {
       provider.createResources(request);
       fail("Exception expected");
@@ -444,7 +450,6 @@ public class BlueprintResourceProviderTest {
     replay(dao, metaInfo, request);
     // end expectations
 
-    ResourceProvider provider = createProvider();
     try {
       provider.createResources(request);
       fail("Exception expected");
@@ -488,7 +493,6 @@ public class BlueprintResourceProviderTest {
     replay(dao, metaInfo, request);
     // end expectations
 
-    ResourceProvider provider = createProvider();
     try {
       provider.createResources(request);
       fail("Exception expected");
@@ -532,7 +536,6 @@ public class BlueprintResourceProviderTest {
     replay(dao, metaInfo, request);
     // end expectations
 
-    ResourceProvider provider = createProvider();
     try {
       provider.createResources(request);
       fail("Exception expected");
@@ -575,7 +578,6 @@ public class BlueprintResourceProviderTest {
     replay(dao, metaInfo, request);
     // end expectations
 
-    ResourceProvider provider = createProvider();
     try {
       provider.createResources(request);
       fail("Exception expected");
@@ -1127,8 +1129,9 @@ public class BlueprintResourceProviderTest {
 
   private void setConfigurationProperties(Set<Map<String, Object>> properties
) {
     Map<String, String> clusterProperties = new HashMap<String, String>();
-    clusterProperties.put("core-site/fs.trash.interval", "480");
-    clusterProperties.put("core-site/ipc.client.idlethreshold", "8500");
+    clusterProperties.put("core-site/properties/fs.trash.interval", "480");
+    clusterProperties.put("core-site/properties/ipc.client.idlethreshold", "8500");
+    clusterProperties.put("core-site/properties_attributes/final/ipc.client.idlethreshold",
"true");
 
     // single entry in set which was created in getTestProperties
     Map<String, Object> mapProperties = properties.iterator().next();
@@ -1252,14 +1255,26 @@ public class BlueprintResourceProviderTest {
 
       Map<String, Object> typeConfigs = blueprintConfigurations.iterator().next();
       assertEquals(1, typeConfigs.size());
-      Map<String, String> properties = (Map<String, String>) typeConfigs.get("core-site");
-      assertEquals(2, properties.size());
+      Map<String, Map<String, Object>> coreSiteConfig = (Map<String, Map<String,
Object>>) typeConfigs.get("core-site");
+      assertEquals(2, coreSiteConfig.size());
+      assertTrue(coreSiteConfig.containsKey(BlueprintResourceProvider.PROPERTIES_PROPERTY_ID));
+      Map<String, Object> properties = coreSiteConfig.get(BlueprintResourceProvider.PROPERTIES_PROPERTY_ID);
+      assertNotNull(properties);
       assertEquals("480", properties.get("fs.trash.interval"));
       assertEquals("8500", properties.get("ipc.client.idlethreshold"));
+
+      assertTrue(coreSiteConfig.containsKey(BlueprintResourceProvider.PROPERTIES_ATTRIBUTES_PROPERTY_ID));
+      Map<String, Object> attributes = coreSiteConfig.get(BlueprintResourceProvider.PROPERTIES_ATTRIBUTES_PROPERTY_ID);
+      assertNotNull(attributes);
+      assertEquals(1, attributes.size());
+      assertTrue(attributes.containsKey("final"));
+      Map<String, String> finalAttrs = (Map<String, String>) attributes.get("final");
+      assertEquals(1, finalAttrs.size());
+      assertEquals("true", finalAttrs.get("ipc.client.idlethreshold"));
     }
   }
 
-  private BlueprintResourceProvider createProvider() {
+  private static BlueprintResourceProvider createProvider() {
     return new BlueprintResourceProvider(
         PropertyHelper.getPropertyIds(Resource.Type.Blueprint),
         PropertyHelper.getKeyPropertyIds(Resource.Type.Blueprint),
@@ -1300,27 +1315,238 @@ public class BlueprintResourceProviderTest {
 
     Collection<Map<String, String>> configProperties = (Collection<Map<String,
String>>) properties.get(
         BlueprintResourceProvider.CONFIGURATION_PROPERTY_ID);
-    Map<String, String> configData = new HashMap<String, String>();
-    Collection<BlueprintConfigEntity> configs = new ArrayList<BlueprintConfigEntity>();
-    if (configProperties != null) {
-      for (Map<String, String> config : configProperties) {
-        BlueprintConfigEntity configEntity = new BlueprintConfigEntity();
-        for (Map.Entry<String, String> entry : config.entrySet()) {
-          String absolutePropName = entry.getKey();
-
-          int idx = absolutePropName.indexOf('/');
-          if (configEntity.getType() == null) {
-            configEntity.setType(absolutePropName.substring(0, idx));
-          }
-          configData.put(absolutePropName.substring(idx + 1), entry.getValue());
-        }
-        configEntity.setConfigData(gson.toJson(configData));
-        configs.add(configEntity);
-      }
-    }
-    entity.setConfigurations(configs);
-
+    createProvider().createBlueprintConfigEntities(configProperties, entity);
     return entity;
   }
+
+  @Test
+  public void testPopulateConfigurationEntity_oldSchema() throws Exception {
+    Map<String, String> configuration = new HashMap<String, String>();
+    configuration.put("global/property1", "val1");
+    configuration.put("global/property2", "val2");
+    BlueprintConfiguration config = new BlueprintConfigEntity();
+
+    provider.populateConfigurationEntity(configuration, config);
+
+    assertNotNull(config.getConfigData());
+    assertNotNull(config.getConfigAttributes());
+    Map<?, ?> configData = StageUtils.getGson().fromJson(config.getConfigData(), Map.class);
+    Map<?, Map<?, ?>> configAttrs = StageUtils.getGson().fromJson(config.getConfigAttributes(),
Map.class);
+    assertNotNull(configData);
+    assertNotNull(configAttrs);
+    assertEquals(2, configData.size());
+    assertTrue(configData.containsKey("property1"));
+    assertTrue(configData.containsKey("property2"));
+    assertEquals("val1", configData.get("property1"));
+    assertEquals("val2", configData.get("property2"));
+    assertEquals(0, configAttrs.size());
+  }
+
+  @Test
+  public void testPopulateConfigurationEntity_newSchema() throws Exception {
+    Map<String, String> configuration = new HashMap<String, String>();
+    configuration.put("global/properties/property1", "val1");
+    configuration.put("global/properties/property2", "val2");
+    configuration.put("global/properties_attributes/final/property1", "true");
+    configuration.put("global/properties_attributes/final/property2", "false");
+    configuration.put("global/properties_attributes/deletable/property1", "true");
+    BlueprintConfiguration config = new BlueprintConfigEntity();
+
+    provider.populateConfigurationEntity(configuration, config);
+
+    assertNotNull(config.getConfigData());
+    assertNotNull(config.getConfigAttributes());
+    Map<?, ?> configData = StageUtils.getGson().fromJson(config.getConfigData(), Map.class);
+    Map<?, Map<?, ?>> configAttrs = StageUtils.getGson().fromJson(config.getConfigAttributes(),
Map.class);
+    assertNotNull(configData);
+    assertNotNull(configAttrs);
+    assertEquals(2, configData.size());
+    assertTrue(configData.containsKey("property1"));
+    assertTrue(configData.containsKey("property2"));
+    assertEquals("val1", configData.get("property1"));
+    assertEquals("val2", configData.get("property2"));
+    assertEquals(2, configAttrs.size());
+    assertTrue(configAttrs.containsKey("final"));
+    assertTrue(configAttrs.containsKey("deletable"));
+    Map<?, ?> finalAttrs = configAttrs.get("final");
+    assertNotNull(finalAttrs);
+    assertEquals(2, finalAttrs.size());
+    assertTrue(finalAttrs.containsKey("property1"));
+    assertTrue(finalAttrs.containsKey("property2"));
+    assertEquals("true", finalAttrs.get("property1"));
+    assertEquals("false", finalAttrs.get("property2"));
+
+    Map<?, ?> deletableAttrs = configAttrs.get("deletable");
+    assertNotNull(deletableAttrs);
+    assertEquals(1, deletableAttrs.size());
+    assertTrue(deletableAttrs.containsKey("property1"));
+    assertEquals("true", deletableAttrs.get("property1"));
+  }
+
+  @Test
+  public void testPopulateConfigurationEntity_configIsNull() throws Exception {
+    Map<String, String> configuration = null;
+    BlueprintConfiguration config = new BlueprintConfigEntity();
+
+    provider.populateConfigurationEntity(configuration, config);
+
+    assertNotNull(config.getConfigAttributes());
+    assertNotNull(config.getConfigData());
+  }
+
+  @Test
+  public void testPopulateConfigurationEntity_configIsEmpty() throws Exception {
+    Map<String, String> configuration = new HashMap<String, String>();
+    BlueprintConfiguration config = new BlueprintConfigEntity();
+
+    provider.populateConfigurationEntity(configuration, config);
+
+    assertNotNull(config.getConfigAttributes());
+    assertNotNull(config.getConfigData());
+  }
+
+  @Test
+  public void testDecidePopulationStrategy_configIsEmpty() throws Exception {
+    Map<String, String> configMap = new HashMap<String, String>();
+
+    BlueprintConfigPopulationStrategy provisioner =
+        provider.decidePopulationStrategy(configMap);
+
+    assertNotNull(provisioner);
+    assertTrue(provisioner instanceof BlueprintConfigPopulationStrategyV2);
+  }
+
+  @Test
+  public void testDecidePopulationStrategy_configIsNull() throws Exception {
+    Map<String, String> configMap = null;
+
+    BlueprintConfigPopulationStrategy provisioner =
+        provider.decidePopulationStrategy(configMap);
+
+    assertNotNull(provisioner);
+    assertTrue(provisioner instanceof BlueprintConfigPopulationStrategyV2);
+  }
+
+  @Test
+  public void testDecidePopulationStrategy_withOldSchema() throws Exception {
+    Map<String, String> configMap = new HashMap<String, String>();
+    configMap.put("global/hive_database", "db");
+
+    BlueprintConfigPopulationStrategy provisioner =
+        provider.decidePopulationStrategy(configMap);
+
+    assertNotNull(provisioner);
+    assertTrue(provisioner instanceof BlueprintConfigPopulationStrategyV1);
+  }
+
+  @Test
+  public void testDecidePopulationStrategy_withNewSchema_attributes() throws Exception {
+    Map<String, String> configMap = new HashMap<String, String>();
+    configMap.put("global/properties_attributes/final/nagios_contact", "true");
+
+    BlueprintConfigPopulationStrategy provisioner =
+        provider.decidePopulationStrategy(configMap);
+
+    assertNotNull(provisioner);
+    assertTrue(provisioner instanceof BlueprintConfigPopulationStrategyV2);
+  }
+
+  @Test
+  public void testDecidePopulationStrategy_withNewSchema_properties() throws Exception {
+    Map<String, String> configMap = new HashMap<String, String>();
+    configMap.put("global/properties/nagios_contact", "foo@ffl.dsfds");
+
+    BlueprintConfigPopulationStrategy provisioner =
+        provider.decidePopulationStrategy(configMap);
+
+    assertNotNull(provisioner);
+    assertTrue(provisioner instanceof BlueprintConfigPopulationStrategyV2);
+  }
+
+  @Test
+  public void testDecidePopulationStrategy_unsupportedSchema() throws Exception {
+    Map<String, String> configMap = new HashMap<String, String>();
+    configMap.put("global/properties/lot/nagios_contact", "foo@ffl.dsfds");
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Configuration definition schema is not supported");
+
+    provider.decidePopulationStrategy(configMap);
+  }
+
+  @Test
+  public void testPopulateConfigurationList() throws Exception {
+    // attributes is null
+    BlueprintConfiguration config1 = new BlueprintConfigEntity();
+    config1.setType("type1");
+    config1.setConfigData("{\"key1\":\"value1\"}");
+    // attributes is empty
+    BlueprintConfiguration config2 = new BlueprintConfigEntity();
+    config2.setType("type2");
+    config2.setConfigData("{\"key2\":\"value2\"}");
+    config2.setConfigAttributes("{}");
+    // attributes is provided
+    BlueprintConfiguration config3 = new BlueprintConfigEntity();
+    config3.setType("type3");
+    config3.setConfigData("{\"key3\":\"value3\",\"key4\":\"value4\"}");
+    config3.setConfigAttributes("{\"final\":{\"key3\":\"attrValue1\",\"key4\":\"attrValue2\"}}");
+
+    List<Map<String, Map<String, Object>>> configs =
+        provider.populateConfigurationList(Arrays.asList(config1, config2, config3));
+
+    assertNotNull(configs);
+    assertEquals(3, configs.size());
+    Map<String, Map<String, Object>> configuration1 = configs.get(0);
+    assertNotNull(configuration1);
+    assertEquals(1, configuration1.size());
+    assertTrue(configuration1.containsKey("type1"));
+    Map<String, Object> typeConfig1 = configuration1.get("type1");
+    assertNotNull(typeConfig1);
+    assertEquals(1, typeConfig1.size());
+    assertTrue(typeConfig1.containsKey(BlueprintResourceProvider.PROPERTIES_PROPERTY_ID));
+    Map<String, String> confProperties1
+        = (Map<String, String>) typeConfig1.get(BlueprintResourceProvider.PROPERTIES_PROPERTY_ID);
+    assertNotNull(confProperties1);
+    assertEquals(1, confProperties1.size());
+    assertEquals("value1", confProperties1.get("key1"));
+
+    Map<String, Map<String, Object>> configuration2 = configs.get(1);
+    assertNotNull(configuration2);
+    assertEquals(1, configuration2.size());
+    assertTrue(configuration2.containsKey("type2"));
+    Map<String, Object> typeConfig2 = configuration2.get("type2");
+    assertNotNull(typeConfig2);
+    assertEquals(1, typeConfig2.size());
+    assertTrue(typeConfig2.containsKey(BlueprintResourceProvider.PROPERTIES_PROPERTY_ID));
+    Map<String, String> confProperties2
+        = (Map<String, String>) typeConfig2.get(BlueprintResourceProvider.PROPERTIES_PROPERTY_ID);
+    assertNotNull(confProperties2);
+    assertEquals(1, confProperties2.size());
+    assertEquals("value2", confProperties2.get("key2"));
+
+    Map<String, Map<String, Object>> configuration3 = configs.get(2);
+    assertNotNull(configuration3);
+    assertEquals(1, configuration3.size());
+    assertTrue(configuration3.containsKey("type3"));
+    Map<String, Object> typeConfig3 = configuration3.get("type3");
+    assertNotNull(typeConfig3);
+    assertEquals(2, typeConfig3.size());
+    assertTrue(typeConfig3.containsKey(BlueprintResourceProvider.PROPERTIES_PROPERTY_ID));
+    Map<String, String> confProperties3
+        = (Map<String, String>) typeConfig3.get(BlueprintResourceProvider.PROPERTIES_PROPERTY_ID);
+    assertNotNull(confProperties3);
+    assertEquals(2, confProperties3.size());
+    assertEquals("value3", confProperties3.get("key3"));
+    assertEquals("value4", confProperties3.get("key4"));
+    assertTrue(typeConfig3.containsKey(BlueprintResourceProvider.PROPERTIES_ATTRIBUTES_PROPERTY_ID));
+    Map<String, Map<String, String>> confAttributes3
+        = (Map<String, Map<String, String>>) typeConfig3.get(BlueprintResourceProvider.PROPERTIES_ATTRIBUTES_PROPERTY_ID);
+    assertNotNull(confAttributes3);
+    assertEquals(1, confAttributes3.size());
+    assertTrue(confAttributes3.containsKey("final"));
+    Map<String, String> finalAttrs = confAttributes3.get("final");
+    assertEquals(2, finalAttrs.size());
+    assertEquals("attrValue1", finalAttrs.get("key3"));
+    assertEquals("attrValue2", finalAttrs.get("key4"));
+  }
 }
 


Mime
View raw message