AMBARI-14650.  Add persistence for Repo Version file (ncole)

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

Branch: refs/heads/branch-dev-patch-upgrade
Commit: ee623b7ff2b58c3a957a745a9351c3899e650f9b
Parents: 5da392b
Author: Nate Cole <[email protected]>
Authored: Wed Jan 13 12:51:37 2016 -0500
Committer: Nate Cole <[email protected]>
Committed: Fri Jan 15 12:30:36 2016 -0500

----------------------------------------------------------------------
 .../ClusterStackVersionResourceProvider.java    |   6 +-
 .../RepositoryVersionResourceProvider.java      | 121 +++++++++++++------
 .../orm/entities/RepositoryVersionEntity.java   | 112 +++++++++--------
 .../apache/ambari/server/stack/StackModule.java |  45 +++----
 .../state/repository/AvailableService.java      |  54 +++++++++
 .../state/repository/AvailableVersion.java      |  62 ++++++++++
 .../state/repository/ManifestService.java       |   2 +-
 .../state/repository/VersionDefinitionXml.java  |  95 ++++++++++++++-
 .../server/state/stack/RepositoryXml.java       |  75 ++++++++----
 .../main/resources/Ambari-DDL-Derby-CREATE.sql  |   3 +
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |  14 +--
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |  12 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |  12 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |  13 +-
 .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql |  12 +-
 .../resources/Ambari-DDL-SQLServer-CREATE.sql   |  12 +-
 .../RepositoryVersionResourceProviderTest.java  |  67 +++++++++-
 .../state/repository/VersionDefinitionTest.java |   8 +-
 .../version_definition_resource_provider.xml    |  77 ++++++++++++
 .../test/resources/version_definition_test.xml  |   2 +
 20 files changed, 597 insertions(+), 207 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
index 061a373..b114ea5 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java
@@ -415,9 +415,9 @@ public class ClusterStackVersionResourceProvider extends 
AbstractControllerResou
 
       // determine services for the repo
       Set<String> serviceNames = new HashSet<>();
-      for (RepositoryVersionEntity.Component component : 
repoVersionEnt.getComponents()) {
-        serviceNames.add(component.getService());
-      }
+//      for (RepositoryVersionEntity.Component component : 
repoVersionEnt.getComponents()) {
+//        serviceNames.add(component.getService());
+//      }
 
       // Populate with commands for host
       for (int i = 0; i < maxTasks && hostIterator.hasNext(); i++) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java
index 5f14793..8b34cc8 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.controller.internal;
 
+import java.net.URL;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -25,7 +26,6 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
@@ -59,12 +59,13 @@ import 
org.apache.ambari.server.security.authorization.RoleAuthorization;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.OperatingSystemInfo;
-import org.apache.ambari.server.state.RepositoryType;
 import org.apache.ambari.server.state.RepositoryVersionState;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
+import org.apache.ambari.server.state.repository.VersionDefinitionXml;
 import org.apache.ambari.server.state.stack.UpgradePack;
 import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.ObjectUtils;
 import org.apache.commons.lang.StringUtils;
 
@@ -87,11 +88,17 @@ public class RepositoryVersionResourceProvider extends 
AbstractAuthorizedResourc
   public static final String REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID      
= PropertyHelper.getPropertyId("RepositoryVersions", "stack_version");
   public static final String REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID 
= PropertyHelper.getPropertyId("RepositoryVersions", "repository_version");
   public static final String REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID       
= PropertyHelper.getPropertyId("RepositoryVersions", "display_name");
-  public static final String REPOSITORY_VERSION_TYPE_PROPERTY_ID               
= "RepositoryVersions/type";
-  public static final String REPOSITORY_VERSION_COMPONENTS                     
= "RepositoryVersions/components";
   public static final String SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID         
= new OperatingSystemResourceDefinition().getPluralName();
   public static final String SUBRESOURCE_REPOSITORIES_PROPERTY_ID              
= new RepositoryResourceDefinition().getPluralName();
 
+  public static final String REPOSITORY_VERSION_TYPE_PROPERTY_ID               
= "RepositoryVersions/type";
+  public static final String REPOSITORY_VERSION_DEFINITION_URL                 
= "RepositoryVersions/version_url";
+  public static final String REPOSITORY_VERSION_RELEASE_VERSION                
= "RepositoryVersions/release/version";
+  public static final String REPOSITORY_VERSION_RELEASE_BUILD                  
= "RepositoryVersions/release/build";
+  public static final String REPOSITORY_VERSION_RELEASE_NOTES                  
= "RepositoryVersions/release/notes";
+  public static final String REPOSITORY_VERSION_RELEASE_COMPATIBLE_WITH        
= "RepositoryVersions/release/compatible_with";
+  public static final String REPOSITORY_VERSION_AVAILABLE_SERVICES             
= "RepositoryVersions/services";
+
   @SuppressWarnings("serial")
   private static Set<String> pkPropertyIds = new HashSet<String>() {
     {
@@ -106,9 +113,14 @@ public class RepositoryVersionResourceProvider extends 
AbstractAuthorizedResourc
       REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID,
       REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID,
       REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID,
+      REPOSITORY_VERSION_DEFINITION_URL,
       SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID,
       REPOSITORY_VERSION_TYPE_PROPERTY_ID,
-      REPOSITORY_VERSION_COMPONENTS);
+      REPOSITORY_VERSION_RELEASE_BUILD,
+      REPOSITORY_VERSION_RELEASE_COMPATIBLE_WITH,
+      REPOSITORY_VERSION_RELEASE_NOTES,
+      REPOSITORY_VERSION_RELEASE_VERSION,
+      REPOSITORY_VERSION_AVAILABLE_SERVICES);
 
   @SuppressWarnings("serial")
   public static Map<Type, String> keyPropertyIds = new HashMap<Type, String>() 
{
@@ -179,12 +191,20 @@ public class RepositoryVersionResourceProvider extends 
AbstractAuthorizedResourc
             REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID,
             REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID
           };
-          for (String propertyName : requiredProperties) {
-            if (properties.get(propertyName) == null) {
-              throw new AmbariException("Property " + propertyName + " should 
be provided");
+
+          final RepositoryVersionEntity entity;
+          if (properties.containsKey(REPOSITORY_VERSION_DEFINITION_URL)) {
+            String definitionUrl = (String) 
properties.get(REPOSITORY_VERSION_DEFINITION_URL);
+
+            entity = toRepositoryVersionEntity(definitionUrl);
+          } else {
+            for (String propertyName : requiredProperties) {
+              if (properties.get(propertyName) == null) {
+                throw new AmbariException("Property " + propertyName + " 
should be provided");
+              }
             }
+            entity = toRepositoryVersionEntity(properties);
           }
-          final RepositoryVersionEntity entity = 
toRepositoryVersionEntity(properties);
 
           if (repositoryVersionDAO.findByDisplayName(entity.getDisplayName()) 
!= null) {
             throw new AmbariException("Repository version with name " + 
entity.getDisplayName() + " already exists");
@@ -192,6 +212,7 @@ public class RepositoryVersionResourceProvider extends 
AbstractAuthorizedResourc
           if (repositoryVersionDAO.findByStackAndVersion(entity.getStack(), 
entity.getVersion()) != null) {
             throw new AmbariException("Repository version for stack " + 
entity.getStack() + " and version " + entity.getVersion() + " already exists");
           }
+
           validateRepositoryVersion(entity);
           repositoryVersionDAO.create(entity);
           notifyCreate(Resource.Type.RepositoryVersion, request);
@@ -242,19 +263,28 @@ public class RepositoryVersionResourceProvider extends 
AbstractAuthorizedResourc
       setResourceProperty(resource, 
REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID, entity.getVersion(), 
requestedIds);
       setResourceProperty(resource, REPOSITORY_VERSION_TYPE_PROPERTY_ID, 
entity.getType(), requestedIds);
 
-      if (isPropertyRequested(REPOSITORY_VERSION_COMPONENTS, requestedIds)) {
-        Map<String, List<String>> map = new HashMap<>();
+      if (null != entity.getVersionXsd()) {
+        final VersionDefinitionXml xml;
+        final StackInfo stack;
 
-        // !!! sort via ordering first?
+        try {
+          xml = VersionDefinitionXml.load(entity.getVersionXml());
+        } catch (Exception e) {
+          throw new SystemException(String.format("Could not load xml for 
Repository %s", entity.getId()), e);
+        }
 
-        for (RepositoryVersionEntity.Component comp : entity.getComponents()) {
-          if (!map.containsKey(comp.getService())) {
-            map.put(comp.getService(), new ArrayList<String>());
-          }
-          map.get(comp.getService()).add(comp.getComponent());
+        try {
+          stack = ambariMetaInfo.getStack(entity.getStackName(), 
entity.getStackVersion());
+        } catch (AmbariException e) {
+          throw new SystemException(String.format("Could not load stack %s for 
Repository %s",
+              entity.getStackId().toString(), entity.getId()));
         }
 
-        setResourceProperty(resource, REPOSITORY_VERSION_COMPONENTS, map, 
requestedIds);
+        setResourceProperty(resource, REPOSITORY_VERSION_RELEASE_VERSION, 
xml.release.version, requestedIds);
+        setResourceProperty(resource, REPOSITORY_VERSION_RELEASE_BUILD, 
xml.release.build, requestedIds);
+        setResourceProperty(resource, 
REPOSITORY_VERSION_RELEASE_COMPATIBLE_WITH, xml.release.compatibleWith, 
requestedIds);
+        setResourceProperty(resource, REPOSITORY_VERSION_RELEASE_NOTES, 
xml.release.releaseNotes, requestedIds);
+        setResourceProperty(resource, REPOSITORY_VERSION_AVAILABLE_SERVICES, 
xml.getAvailableServices(stack), requestedIds);
       }
 
       resources.add(resource);
@@ -484,6 +514,7 @@ public class RepositoryVersionResourceProvider extends 
AbstractAuthorizedResourc
    */
   protected RepositoryVersionEntity toRepositoryVersionEntity(Map<String, 
Object> properties) throws AmbariException {
     final RepositoryVersionEntity entity = new RepositoryVersionEntity();
+
     final String stackName = 
properties.get(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).toString();
     final String stackVersion = 
properties.get(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).toString();
 
@@ -502,28 +533,48 @@ public class RepositoryVersionResourceProvider extends 
AbstractAuthorizedResourc
     }
     entity.setOperatingSystems(operatingSystemsJson);
 
-    List<RepositoryVersionEntity.Component> components = null;
-    int i = 1;
+    return entity;
+  }
 
-    for (Entry<String, Object> entry : properties.entrySet()) {
-      if (entry.getKey().startsWith(REPOSITORY_VERSION_COMPONENTS)) {
-        if (null == components) {
-          components = new ArrayList<>();
-        }
+  /**
+   * Transforms a XML version defintion to an entity
+   *
+   * @param definitionUrl the String URL for loading
+   * @return constructed entity
+   * @throws AmbariException if some properties are missing or json has 
incorrect structure
+   */
+  protected RepositoryVersionEntity toRepositoryVersionEntity(String 
definitionUrl) throws AmbariException {
+    final VersionDefinitionXml xml;
+    final String xmlString;
+    try {
+      URL url = new URL(definitionUrl);
 
-        String serviceName = PropertyHelper.getPropertyName(entry.getKey());
-        Collection<String> componentNames = (Collection<String>) 
entry.getValue();
+      xmlString = IOUtils.toString(url.openStream(), "UTF-8");
 
-        for (String componentName : componentNames) {
-          components.add(new RepositoryVersionEntity.Component(serviceName, 
componentName, i++));
-        }
-      }
+      xml = VersionDefinitionXml.load(xmlString);
+    } catch (Exception e) {
+      String err = String.format("Could not load url from %s.  %s",
+          definitionUrl, e.getMessage());
+      throw new AmbariException(err, e);
     }
 
-    if (null != components) {
-      entity.setType(RepositoryType.PATCH);
-      entity.setComponents(components);
-    }
+    // !!! TODO validate parsed object graph
+
+    RepositoryVersionEntity entity = new RepositoryVersionEntity();
+
+    StackId stackId = new StackId(xml.release.stackId);
+
+    StackEntity stackEntity = stackDAO.find(stackId.getStackName(), 
stackId.getStackVersion());
+
+    entity.setStack(stackEntity);
+    
entity.setOperatingSystems(repositoryVersionHelper.serializeOperatingSystems(
+        xml.repositoryInfo.getRepositories()));
+    entity.setVersion(xml.release.version + "-" + 
StringUtils.stripToEmpty(xml.release.build));
+    entity.setDisplayName(stackId.getStackName() + "-" + entity.getVersion());
+    entity.setType(xml.release.repositoryType);
+    entity.setVersionUrl(definitionUrl);
+    entity.setVersionXml(xmlString);
+    entity.setVersionXsd(xml.xsdLocation);
 
     return entity;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
index e12e118..a31b135 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java
@@ -17,20 +17,17 @@
  */
 package org.apache.ambari.server.orm.entities;
 
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
+import javax.persistence.Basic;
 import javax.persistence.CascadeType;
-import javax.persistence.CollectionTable;
 import javax.persistence.Column;
-import javax.persistence.ElementCollection;
-import javax.persistence.Embeddable;
 import javax.persistence.Entity;
 import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
@@ -102,9 +99,6 @@ public class RepositoryVersionEntity {
   @Column(name = "repositories")
   private String operatingSystems;
 
-  @Column(name = "repo_type", nullable = false, insertable = true, updatable = 
true)
-  @Enumerated(value = EnumType.STRING)
-  private RepositoryType type = RepositoryType.STANDARD;
 
   @OneToMany(cascade = CascadeType.REMOVE, mappedBy = "repositoryVersion")
   private Set<ClusterVersionEntity> clusterVersionEntities;
@@ -112,9 +106,20 @@ public class RepositoryVersionEntity {
   @OneToMany(cascade = CascadeType.REMOVE, mappedBy = "repositoryVersion")
   private Set<HostVersionEntity> hostVersionEntities;
 
-  @ElementCollection(targetClass = Component.class)
-  @CollectionTable(name = "repo_version_component", joinColumns = 
@JoinColumn(name = "repo_version_id"))
-  private List<Component> components = new ArrayList<>();
+  @Column(name = "repo_type", nullable = false, insertable = true, updatable = 
true)
+  @Enumerated(value = EnumType.STRING)
+  private RepositoryType type = RepositoryType.STANDARD;
+
+  @Basic(fetch=FetchType.LAZY)
+  @Lob
+  @Column(name="version_xml", insertable = true, updatable = true)
+  private String versionXml;
+
+  @Column(name="version_url", nullable=true, insertable=true, updatable=true)
+  private String versionUrl;
+
+  @Column(name="version_xsd", insertable = true, updatable = true)
+  private String versionXsd;
 
   // ----- RepositoryVersionEntity 
-------------------------------------------------------
 
@@ -267,6 +272,7 @@ public class RepositoryVersionEntity {
     if (displayName != null ? !displayName.equals(that.displayName) : 
that.displayName != null) {
       return false;
     }
+
     if (operatingSystems != null ? 
!operatingSystems.equals(that.operatingSystems) : that.operatingSystems != 
null) {
       return false;
     }
@@ -274,6 +280,48 @@ public class RepositoryVersionEntity {
     return true;
   }
 
+  /**
+   * @return the XML that is the basis for the version
+   */
+  public String getVersionXml() {
+    return versionXml;
+  }
+
+  /**
+   * @param xml the XML that is the basis for the version
+   */
+  public void setVersionXml(String xml) {
+    versionXml = xml;
+  }
+
+  /**
+   * @return The url used for the version.  Optional in case the XML was 
loaded via blob.
+   */
+  public String getVersionUrl() {
+    return versionUrl;
+  }
+
+  /**
+   * @param url the url used to load the XML.
+   */
+  public void setVersionUrl(String url) {
+    versionUrl = url;
+  }
+
+  /**
+   * @return the XSD name extracted from the XML.
+   */
+  public String getVersionXsd() {
+    return versionXml;
+  }
+
+  /**
+   * @param xsdLocation the XSD name extracted from XML.
+   */
+  public void setVersionXsd(String xsdLocation) {
+    versionXsd = xsdLocation;
+  }
+
   @Override
   public int hashCode() {
     int result = id != null ? id.hashCode() : 0;
@@ -311,46 +359,4 @@ public class RepositoryVersionEntity {
     return false;
   }
 
-
-  /**
-   * Used to identify the components associated with a repository.
-   */
-  @Embeddable
-  public static class Component {
-    private String service;
-    private String component;
-    private int component_order;
-
-    public Component() {
-    }
-
-    public Component(String serviceName, String componentName, int order) {
-      service = serviceName;
-      component = componentName;
-      component_order = order;
-    }
-
-    public String getService() {
-      return service;
-    }
-
-    public String getComponent() {
-      return component;
-    }
-
-  }
-
-
-  /**
-   * @param components
-   */
-  public void setComponents(List<Component> components) {
-    // TODO Auto-generated method stub
-    this.components = components;
-  }
-
-  public List<Component> getComponents() {
-    return components;
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
index def33f0..7d934bb 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
@@ -110,8 +110,8 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
   /**
    * validity flag
    */
-  protected boolean valid = true;  
-  
+  protected boolean valid = true;
+
   /**
    * Logger
    */
@@ -342,7 +342,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
         setValid(false);
         stackInfo.setValid(false);
         setErrors(baseService.getErrors());
-        stackInfo.setErrors(baseService.getErrors());        
+        stackInfo.setErrors(baseService.getErrors());
       }
     }
   }
@@ -439,7 +439,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
         setValid(false);
         setErrors(stackInfo.getErrors());
       }
-      
+
       //todo: shouldn't blindly catch Exception, re-evaluate this.
     } catch (Exception e) {
       String error = "Exception caught while populating services for stack: " +
@@ -475,7 +475,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
       stackInfo.setValid(metaInfoXml.isValid());
       setValid(metaInfoXml.isValid());
       stackInfo.setErrors(metaInfoXml.getErrors());
-      setErrors(metaInfoXml.getErrors());      
+      setErrors(metaInfoXml.getErrors());
       return;
     }
     List<ServiceInfo> serviceInfos = metaInfoXml.getServices();
@@ -487,7 +487,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
         stackInfo.setValid(false);
         setValid(false);
         stackInfo.setErrors(serviceModule.getErrors());
-        setErrors(serviceModule.getErrors());        
+        setErrors(serviceModule.getErrors());
       }
     }
     addServices(serviceModules);
@@ -648,6 +648,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
    * @throws AmbariException if unable to fully process the stack repositories
    */
   private void processRepositories() throws AmbariException {
+
     RepositoryXml rxml = stackDirectory.getRepoFile();
     if (rxml == null) {
       return;
@@ -658,15 +659,10 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
         ", stackVersion=" + stackInfo.getVersion() +
         ", repoFolder=" + stackDirectory.getRepoDir());
 
-    List<RepositoryInfo> repos = new ArrayList<RepositoryInfo>();
+    List<RepositoryInfo> repos = rxml.getRepositories();
 
-    for (RepositoryXml.Os o : rxml.getOses()) {
-      String osFamily = o.getFamily();
-      for (String os : osFamily.split(",")) {
-        for (RepositoryXml.Repo r : o.getRepos()) {
-          repos.add(processRepository(osFamily, os, r));
-        }
-      }
+    for (RepositoryInfo ri : repos) {
+      processRepository(ri);
     }
 
     stackInfo.getRepositories().addAll(repos);
@@ -683,19 +679,11 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
    * @param osType    OS type
    * @param r         repo
    */
-  private RepositoryInfo processRepository(String osFamily, String osType, 
RepositoryXml.Repo r) {
-    RepositoryInfo ri = new RepositoryInfo();
-    ri.setBaseUrl(r.getBaseUrl());
-    ri.setDefaultBaseUrl(r.getBaseUrl());
-    ri.setMirrorsList(r.getMirrorsList());
-    ri.setOsType(osType.trim());
-    ri.setRepoId(r.getRepoId());
-    ri.setRepoName(r.getRepoName());
-    ri.setLatestBaseUrl(r.getBaseUrl());
+  private RepositoryInfo processRepository(RepositoryInfo ri) {
 
     LOG.debug("Checking for override for base_url");
     String updatedUrl = stackContext.getUpdatedRepoUrl(stackInfo.getName(), 
stackInfo.getVersion(),
-        osFamily, r.getRepoId());
+        ri.getOsType(), ri.getRepoId());
 
     if (null != updatedUrl) {
       ri.setBaseUrl(updatedUrl);
@@ -709,6 +697,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
     return ri;
   }
 
+
   /**
    * Merge role command order with the parent stack
    *
@@ -716,9 +705,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
    */
 
   private void mergeRoleCommandOrder(StackModule parentStack) {
-
     
stackInfo.getRoleCommandOrder().merge(parentStack.stackInfo.getRoleCommandOrder());
-
   }
 
   @Override
@@ -732,7 +719,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
   }
 
   private Set<String> errorSet = new HashSet<String>();
-  
+
   @Override
   public void setErrors(String error) {
     errorSet.add(error);
@@ -741,11 +728,11 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
   @Override
   public Collection getErrors() {
     return errorSet;
-  }   
+  }
 
   @Override
   public void setErrors(Collection error) {
     this.errorSet.addAll(error);
   }
-  
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/java/org/apache/ambari/server/state/repository/AvailableService.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/AvailableService.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/AvailableService.java
new file mode 100644
index 0000000..ce42b69
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/AvailableService.java
@@ -0,0 +1,54 @@
+/**
+ * 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.repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+/**
+ * A representation of a {@link ManifestService} that is available for 
upgrading.  This
+ * object will be serialized directly in API responses.
+ */
+public class AvailableService {
+
+  @JsonProperty("name")
+  private String name;
+
+  @JsonProperty("display_name")
+  @JsonSerialize(include=Inclusion.NON_NULL)
+  private String displayName;
+
+  private List<AvailableVersion> versions = new ArrayList<>();
+
+  AvailableService(String service, String serviceDisplay) {
+    name = service;
+    displayName = serviceDisplay;
+  }
+
+  /**
+   * @return the list of versions to append additional versions.
+   */
+  public List<AvailableVersion> getVersions() {
+    return versions;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/java/org/apache/ambari/server/state/repository/AvailableVersion.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/AvailableVersion.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/AvailableVersion.java
new file mode 100644
index 0000000..b10a13e
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/AvailableVersion.java
@@ -0,0 +1,62 @@
+/**
+ * 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.repository;
+
+import java.util.Set;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+/**
+ * Represents a version of a {@link ManifestService} that is available for 
upgrading.
+ *
+ * This class is serialized directly in API responses.
+ */
+public class AvailableVersion {
+
+  @JsonProperty("version")
+  private String version;
+
+  @JsonProperty("version_id")
+  @JsonSerialize(include=Inclusion.NON_NULL)
+  private String versionId;
+
+  @JsonProperty
+  private Set<Component> components;
+
+  AvailableVersion(String version, String versionId, Set<Component> 
components) {
+    this.version = version;
+    this.versionId = versionId;
+    this.components = components;
+  }
+
+  static class Component {
+    @JsonProperty("name")
+    private String name;
+
+    @JsonProperty("display_name")
+    private String display;
+
+    Component(String name, String display) {
+      this.name = name;
+      this.display = display;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ManifestService.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ManifestService.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ManifestService.java
index 0097110..2bbacd5 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ManifestService.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/ManifestService.java
@@ -26,7 +26,7 @@ import javax.xml.bind.annotation.XmlAttribute;
 public class ManifestService {
 
   /**
-   * The unique id for the service and version.
+   * The XML unique id for the service and version.
    */
   @XmlAttribute(name="id")
   public String serviceId;

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
index 92ab6b3..a610bd0 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java
@@ -21,7 +21,13 @@ import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import javax.xml.XMLConstants;
 import javax.xml.bind.JAXBContext;
@@ -31,12 +37,17 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamReader;
 import javax.xml.transform.stream.StreamSource;
 import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 
+import org.apache.ambari.server.state.ComponentInfo;
+import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.StackInfo;
+import org.apache.ambari.server.state.repository.AvailableVersion.Component;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.commons.io.IOUtils;
 
@@ -58,7 +69,7 @@ public class VersionDefinitionXml {
    */
   @XmlElementWrapper(name="manifest")
   @XmlElement(name="service")
-  public List<ManifestService> manifestServices = new ArrayList<>();
+  List<ManifestService> manifestServices = new ArrayList<>();
 
   /**
    * For PATCH and SERVICE repositories, this dictates what is available for 
upgrade
@@ -66,7 +77,7 @@ public class VersionDefinitionXml {
    */
   @XmlElementWrapper(name="available-services")
   @XmlElement(name="service")
-  public List<AvailableServiceReference> availableServices = new ArrayList<>();
+  List<AvailableServiceReference> availableServices = new ArrayList<>();
 
   /**
    * Represents the repository details.  This is reused from stack repo info.
@@ -75,6 +86,79 @@ public class VersionDefinitionXml {
   public RepositoryXml repositoryInfo;
 
   /**
+   * The xsd location.  Never {@code null}.
+   */
+  @XmlTransient
+  public String xsdLocation;
+
+  @XmlTransient
+  private Map<String, AvailableService> availableMap;
+
+
+  /**
+   * @param stack the stack info needed to lookup service and component 
display names
+   * @return a collection of AvailableServices used for web service consumption
+   */
+  public Collection<AvailableService> getAvailableServices(StackInfo stack) {
+    if (availableServices.isEmpty()) {
+      return Collections.emptyList();
+    }
+
+    if (null == availableMap) {
+      Map<String, ManifestService> manifests = buildManifest();
+      availableMap = new HashMap<>();
+
+      for (AvailableServiceReference ref : availableServices) {
+        ManifestService ms = manifests.get(ref.serviceIdReference);
+        ServiceInfo service = stack.getService(ms.serviceName);
+
+        if (!availableMap.containsKey(ms.serviceName)) {
+          String display = (null == service) ? ms.serviceName: 
service.getDisplayName();
+
+          availableMap.put(ms.serviceName, new 
AvailableService(ms.serviceName, display));
+        }
+
+        AvailableService as = availableMap.get(ms.serviceName);
+        as.getVersions().add(new AvailableVersion(ms.version, ms.versionId,
+            buildComponents(service, ref.components)));
+      }
+    }
+
+    return availableMap.values();
+  }
+
+  /**
+   * @return the list of manifest services to a map for easier access.
+   */
+  private Map<String, ManifestService> buildManifest() {
+    Map<String, ManifestService> normalized = new HashMap<>();
+
+    for (ManifestService ms : manifestServices) {
+      normalized.put(ms.serviceId, ms);
+    }
+    return normalized;
+  }
+
+  /**
+   * @param service the service containing components
+   * @param components the set of components in the service
+   * @return the set of components name/display name pairs
+   */
+  private Set<Component> buildComponents(ServiceInfo service, Set<String> 
components) {
+    Set<Component> set = new HashSet<>();
+
+    for (String component : components) {
+      ComponentInfo ci = service.getComponentByName(component);
+      String display = (null == ci) ? component : ci.getDisplayName();
+      set.add(new Component(component, display));
+    }
+
+    return set;
+  }
+
+
+
+  /**
    * Parses a URL for a definition XML file into the object graph.
    * @param   url the URL to load.  Can be a file URL reference also.
    * @return  the definition
@@ -128,8 +212,13 @@ public class VersionDefinitionXml {
       unmarshaller.setSchema(schema);
     }
 
-    return (VersionDefinitionXml) unmarshaller.unmarshal(xmlReader);
+    VersionDefinitionXml xml = (VersionDefinitionXml) 
unmarshaller.unmarshal(xmlReader);
+    xml.xsdLocation = xsdName;
+
+    return xml;
   }
 
 
+
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java
index eff063b..f57b936 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/RepositoryXml.java
@@ -29,7 +29,9 @@ import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
+
 import org.apache.ambari.server.stack.Validable;
+import org.apache.ambari.server.state.RepositoryInfo;
 
 /**
  * Represents the repository file 
<code>$STACK_VERSION/repos/repoinfo.xml</code>.
@@ -47,7 +49,7 @@ public class RepositoryXml implements Validable{
   private boolean valid = true;
 
   /**
-   * 
+   *
    * @return valid xml flag
    */
   @Override
@@ -56,17 +58,17 @@ public class RepositoryXml implements Validable{
   }
 
   /**
-   * 
+   *
    * @param valid set validity flag
    */
   @Override
   public void setValid(boolean valid) {
     this.valid = valid;
-  }    
-  
+  }
+
   @XmlTransient
   private Set<String> errorSet = new HashSet<String>();
-  
+
   @Override
   public void setErrors(String error) {
     errorSet.add(error);
@@ -75,27 +77,27 @@ public class RepositoryXml implements Validable{
   @Override
   public Collection getErrors() {
     return errorSet;
-  } 
- 
+  }
+
   @Override
   public void setErrors(Collection error) {
     this.errorSet.addAll(error);
-  }  
-  
+  }
+
   /**
    * @return the latest URI defined, if any.
    */
   public String getLatestURI() {
     return latestUri;
   }
-  
+
   /**
    * @return the list of <code>os</code> elements.
    */
   public List<Os> getOses() {
     return oses;
   }
-  
+
   /**
    * The <code>os</code> tag.
    */
@@ -103,20 +105,20 @@ public class RepositoryXml implements Validable{
   public static class Os {
     @XmlAttribute(name="family")
     private String family;
-    
+
     @XmlElement(name="repo")
     private List<Repo> repos;
 
     private Os() {
     }
-    
+
     /**
      * @return the os family
      */
     public String getFamily() {
       return family;
     }
-    
+
     /**
      * @return the list of repo elements
      */
@@ -138,7 +140,7 @@ public class RepositoryXml implements Validable{
 
     private Repo() {
     }
-    
+
     /**
      * @return the base url
      */
@@ -152,27 +154,56 @@ public class RepositoryXml implements Validable{
     public String getMirrorsList() {
       return (null == mirrorslist || mirrorslist.isEmpty()) ? null : 
mirrorslist;
     }
-    
+
     /**
      * @return the repo id
      */
     public String getRepoId() {
       return repoid;
     }
-    
+
     /**
      * @return the repo name
      */
     public String getRepoName() {
       return reponame;
     }
-    
+
     public String getLatestUri() {
       return latest;
     }
-    
-    
-  }  
-  
+
+
+  }
+
+  /**
+   * @return the list of repositories consumable by the web service.
+   */
+  public List<RepositoryInfo> getRepositories() {
+    List<RepositoryInfo> repos = new ArrayList<>();
+
+    for (RepositoryXml.Os o : getOses()) {
+      String osFamily = o.getFamily();
+      for (String os : osFamily.split(",")) {
+        for (RepositoryXml.Repo r : o.getRepos()) {
+
+          RepositoryInfo ri = new RepositoryInfo();
+          ri.setBaseUrl(r.getBaseUrl());
+          ri.setDefaultBaseUrl(r.getBaseUrl());
+          ri.setMirrorsList(r.getMirrorsList());
+          ri.setOsType(os.trim());
+          ri.setRepoId(r.getRepoId());
+          ri.setRepoName(r.getRepoName());
+          ri.setLatestBaseUrl(r.getBaseUrl());
+
+          repos.add(ri);
+        }
+      }
+    }
+
+    return repos;
+  }
+
+
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql 
b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
index 72413ce..554f101 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -551,6 +551,9 @@ CREATE TABLE repo_version (
   version VARCHAR(255) NOT NULL,
   display_name VARCHAR(128) NOT NULL,
   repositories VARCHAR(3000) NOT NULL,
+  version_url VARCHAR(1024),
+  version_xml CLOB,
+  version_xsd VARCHAR(512),
   PRIMARY KEY(repo_version_id)
 );
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/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 3c23737..110c60c 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -557,19 +557,14 @@ CREATE TABLE repo_version (
   stack_id BIGINT NOT NULL,
   version VARCHAR(255) NOT NULL,
   display_name VARCHAR(128) NOT NULL,
-  repositories LONGTEXT NOT NULL,
+  repositories MEDIUMTEXT NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
+  version_url VARCHAR(1024),
+  version_xml MEDIUMTEXT,
+  version_xsd VARCHAR(512),
   PRIMARY KEY(repo_version_id)
 );
 
-CREATE TABLE repo_version_component (
-  repo_version_id BIGINT NOT NULL,
-  service VARCHAR(255) NOT NULL,
-  component VARCHAR(255) NOT NULL,
-  component_order BIGINT NOT NULL,
-  PRIMARY KEY(repo_version_id, service, component)
-);
-
 CREATE TABLE widget (
   id BIGINT NOT NULL,
   widget_name VARCHAR(255) NOT NULL,
@@ -776,7 +771,6 @@ ALTER TABLE servicecomponentdesiredstate ADD CONSTRAINT 
FK_scds_desired_stack_id
 ALTER TABLE servicedesiredstate ADD CONSTRAINT FK_sds_desired_stack_id FOREIGN 
KEY (desired_stack_id) REFERENCES stack(stack_id);
 ALTER TABLE blueprint ADD CONSTRAINT FK_blueprint_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
 ALTER TABLE repo_version ADD CONSTRAINT FK_repoversion_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
-ALTER TABLE repo_version_component ADD CONSTRAINT FK_repo_version_id FOREIGN 
KEY (repo_version_id) REFERENCES repo_version(repo_version_id);
 
 -- Kerberos
 CREATE TABLE kerberos_principal (

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/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 bcaee11..b90da45 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -548,17 +548,12 @@ CREATE TABLE repo_version (
   display_name VARCHAR2(128) NOT NULL,
   repositories CLOB NOT NULL,
   repo_type VARCHAR2(255) DEFAULT 'STANDARD' NOT NULL,
+  version_url VARCHAR(1024),
+  version_xml CLOB,
+  version_xsd VARCHAR(512),
   PRIMARY KEY(repo_version_id)
 );
 
-CREATE TABLE repo_version_component (
-  repo_version_id NUMBER(19) NOT NULL,
-  service VARCHAR2(255) NOT NULL,
-  component VARCHAR2(255) NOT NULL,
-  component_order NUMBER(19) NOT NULL,
-  PRIMARY KEY(repo_version_id, service, component)
-);
-
 CREATE TABLE widget (
   id NUMBER(19) NOT NULL,
   widget_name VARCHAR2(255) NOT NULL,
@@ -765,7 +760,6 @@ ALTER TABLE servicecomponentdesiredstate ADD CONSTRAINT 
FK_scds_desired_stack_id
 ALTER TABLE servicedesiredstate ADD CONSTRAINT FK_sds_desired_stack_id FOREIGN 
KEY (desired_stack_id) REFERENCES stack(stack_id);
 ALTER TABLE blueprint ADD CONSTRAINT FK_blueprint_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
 ALTER TABLE repo_version ADD CONSTRAINT FK_repoversion_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
-ALTER TABLE repo_version_component ADD CONSTRAINT FK_repo_version_id FOREIGN 
KEY (repo_version_id) REFERENCES repo_version(repo_version_id);
 
 -- Kerberos
 CREATE TABLE kerberos_principal (

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/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 6ebc3a9..1210131 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -552,17 +552,12 @@ CREATE TABLE repo_version (
   display_name VARCHAR(128) NOT NULL,
   repositories TEXT NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
+  version_url VARCHAR(1024),
+  version_xml VARCHAR TEXT,
+  version_xsd VARCHAR(512),
   PRIMARY KEY(repo_version_id)
 );
 
-CREATE TABLE repo_version_component (
-  repo_version_id BIGINT NOT NULL,
-  service VARCHAR(255) NOT NULL,
-  component VARCHAR(255) NOT NULL,
-  component_order BIGINT NOT NULL,
-  PRIMARY KEY (repo_version_id, service, component)
-);
-
 CREATE TABLE widget (
   id BIGINT NOT NULL,
   widget_name VARCHAR(255) NOT NULL,
@@ -767,7 +762,6 @@ ALTER TABLE servicecomponentdesiredstate ADD CONSTRAINT 
FK_scds_desired_stack_id
 ALTER TABLE servicedesiredstate ADD CONSTRAINT FK_sds_desired_stack_id FOREIGN 
KEY (desired_stack_id) REFERENCES stack(stack_id);
 ALTER TABLE blueprint ADD CONSTRAINT FK_blueprint_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
 ALTER TABLE repo_version ADD CONSTRAINT FK_repoversion_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
-ALTER TABLE repo_version_component ADD CONSTRAINT FK_repo_version_id FOREIGN 
KEY (repo_version_id) REFERENCES repo_version(repo_version_id);
 
 -- Kerberos
 CREATE TABLE kerberos_principal (

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/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 ee165bf..1c78e3b 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
@@ -621,19 +621,13 @@ CREATE TABLE ambari.repo_version (
   display_name VARCHAR(128) NOT NULL,
   repositories TEXT NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
+  version_url VARCHAR(1024),
+  version_xml TEXT,
+  version_xsd VARCHAR(512),
   PRIMARY KEY(repo_version_id)
 );
 GRANT ALL PRIVILEGES ON TABLE ambari.repo_version TO :username;
 
-CREATE TABLE ambari.repo_version_component (
-  repo_version_id BIGINT NOT NULL,
-  service VARCHAR(255) NOT NULL,
-  component VARCHAR(255) NOT NULL,
-  component_order BIGINT NOT NULL,
-  PRIMARY KEY (repo_version_id, service, component)
-);
-GRANT ALL PRIVILEGES ON TABLE ambari.repo_version_component TO :username;
-
 CREATE TABLE ambari.artifact (
   artifact_name VARCHAR(255) NOT NULL,
   artifact_data TEXT NOT NULL,
@@ -849,7 +843,6 @@ ALTER TABLE ambari.servicecomponentdesiredstate ADD 
CONSTRAINT FK_scds_desired_s
 ALTER TABLE ambari.servicedesiredstate ADD CONSTRAINT FK_sds_desired_stack_id 
FOREIGN KEY (desired_stack_id) REFERENCES ambari.stack(stack_id);
 ALTER TABLE ambari.blueprint ADD CONSTRAINT FK_blueprint_stack_id FOREIGN KEY 
(stack_id) REFERENCES ambari.stack(stack_id);
 ALTER TABLE ambari.repo_version ADD CONSTRAINT FK_repoversion_stack_id FOREIGN 
KEY (stack_id) REFERENCES ambari.stack(stack_id);
-ALTER TABLE ambari.repo_version_component ADD CONSTRAINT FK_repo_version_id 
FOREIGN KEY (repo_version_id) REFERENCES ambari.repo_version(repo_version_id);
 
 -- Kerberos
 CREATE TABLE ambari.kerberos_principal (

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql 
b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
index f7be93b..e796ced 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -549,17 +549,12 @@ CREATE TABLE repo_version (
   upgrade_package VARCHAR(255) NOT NULL,
   repositories TEXT NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
+  version_url VARCHAR(1024),
+  version_xml TEXT,
+  version_xsd VARCHAR(512),
   PRIMARY KEY(repo_version_id)
 );
 
-CREATE TABLE repo_version_component (
-  repo_version_id NUMERIC(19) NOT NULL,
-  service VARCHAR(255) NOT NULL,
-  component VARCHAR(255) NOT NULL,
-  component_order NUMERIC(19) NOT NULL,
-  PRIMARY KEY(repo_version_id, service, component)
-);
-
 CREATE TABLE widget (
   id NUMERIC(19) NOT NULL,
   widget_name VARCHAR(255) NOT NULL,
@@ -766,7 +761,6 @@ ALTER TABLE servicecomponentdesiredstate ADD CONSTRAINT 
FK_scds_desired_stack_id
 ALTER TABLE servicedesiredstate ADD CONSTRAINT FK_sds_desired_stack_id FOREIGN 
KEY (desired_stack_id) REFERENCES stack(stack_id);
 ALTER TABLE blueprint ADD CONSTRAINT FK_blueprint_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
 ALTER TABLE repo_version ADD CONSTRAINT FK_repoversion_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
-ALTER TABLE repo_version_component ADD CONSTRAINT FK_repo_version_id FOREIGN 
KEY (repo_version_id) REFERENCES repo_version(repo_version_id);
 
 -- Kerberos
 CREATE TABLE kerberos_principal (

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql 
b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index baf120f..ccfd71a 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -653,17 +653,12 @@ CREATE TABLE repo_version (
   display_name VARCHAR(128) NOT NULL,
   repositories VARCHAR(MAX) NOT NULL,
   repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL,
+  version_url VARCHAR(1024),
+  version_xml VARCHAR(MAX),
+  version_xsd VARCHAR(512),
   PRIMARY KEY CLUSTERED (repo_version_id)
   );
 
-CREATE TABLE repo_version_component (
-  repo_version_id BIGINT NOT NULL,
-  service VARCHAR(255) NOT NULL,
-  component VARCHAR(255) NOT NULL,
-  component_order BIGINT NOT NULL,
-  PRIMARY KEY CLUSTERED (repo_version_id, service, component)
-  );
-
 CREATE TABLE artifact (
   artifact_name VARCHAR(255) NOT NULL,
   artifact_data TEXT NOT NULL,
@@ -876,7 +871,6 @@ ALTER TABLE servicecomponentdesiredstate ADD CONSTRAINT 
FK_scds_desired_stack_id
 ALTER TABLE servicedesiredstate ADD CONSTRAINT FK_sds_desired_stack_id FOREIGN 
KEY (desired_stack_id) REFERENCES stack(stack_id);
 ALTER TABLE blueprint ADD CONSTRAINT FK_blueprint_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
 ALTER TABLE repo_version ADD CONSTRAINT FK_repoversion_stack_id FOREIGN KEY 
(stack_id) REFERENCES stack(stack_id);
-ALTER TABLE repo_version_component ADD CONSTRAINT FK_repo_version_id FOREIGN 
KEY (repo_version_id) REFERENCES repo_version(repo_version_id);
 
 -- Kerberos
 CREATE TABLE kerberos_principal (

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java
index 17e983e..12d2091 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProviderTest.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -32,6 +33,7 @@ import 
org.apache.ambari.server.controller.ResourceProviderFactory;
 import org.apache.ambari.server.controller.predicate.AndPredicate;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
@@ -52,6 +54,7 @@ import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.OperatingSystemInfo;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.RepositoryVersionState;
+import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.stack.UpgradePack;
@@ -155,12 +158,18 @@ public class RepositoryVersionResourceProviderTest {
         map.put("pack2", pack2);
         return map;
       }
+
+      @Override
+      public ServiceInfo getService(String name) {
+        return new ServiceInfo();
+      }
+
     };
     stackInfo.setName("HDP");
     stackInfo.setVersion("1.1");
     stacks.add(stackInfo);
-    Mockito.when(ambariMetaInfo.getStack(Mockito.anyString(), 
Mockito.anyString())).thenAnswer(new Answer<StackInfo>() {
 
+    Mockito.when(ambariMetaInfo.getStack(Mockito.anyString(), 
Mockito.anyString())).thenAnswer(new Answer<StackInfo>() {
       @Override
       public StackInfo answer(InvocationOnMock invocation) throws Throwable {
         final String stack = invocation.getArguments()[0].toString();
@@ -173,6 +182,7 @@ public class RepositoryVersionResourceProviderTest {
       }
 
     });
+
     Mockito.when(ambariMetaInfo.getStacks()).thenReturn(stacks);
     Mockito.when(ambariMetaInfo.getUpgradePacks(Mockito.anyString(), 
Mockito.anyString())).thenAnswer(new Answer<Map<String, UpgradePack>>() {
 
@@ -267,6 +277,61 @@ public class RepositoryVersionResourceProviderTest {
   }
 
   @Test
+  public void testCreateResourcesWithUrl() throws Exception {
+    Authentication authentication = 
TestAuthenticationFactory.createAdministrator();
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    File file = new 
File("src/test/resources/version_definition_resource_provider.xml");
+
+    final ResourceProvider provider = 
injector.getInstance(ResourceProviderFactory.class).getRepositoryVersionResourceProvider();
+
+    final Set<Map<String, Object>> propertySet = new LinkedHashSet<Map<String, 
Object>>();
+    final Map<String, Object> properties = new LinkedHashMap<String, Object>();
+    
properties.put(RepositoryVersionResourceProvider.REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID,
 "name");
+    
properties.put(RepositoryVersionResourceProvider.REPOSITORY_VERSION_DEFINITION_URL,
 file.toURI().toURL().toString());
+    propertySet.add(properties);
+
+    final Predicate predicateStackName = new 
PredicateBuilder().property(RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).equals("HDP").toPredicate();
+    final Predicate predicateStackVersion = new 
PredicateBuilder().property(RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).equals("1.1").toPredicate();
+    Request getRequest = 
PropertyHelper.getReadRequest(RepositoryVersionResourceProvider.REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID);
+    Assert.assertEquals(0, provider.getResources(getRequest, new 
AndPredicate(predicateStackName, predicateStackVersion)).size());
+
+    final Request createRequest = PropertyHelper.getCreateRequest(propertySet, 
null);
+    provider.createResources(createRequest);
+
+    Set<Resource> results = provider.getResources(getRequest, new 
AndPredicate(predicateStackName, predicateStackVersion));
+    Assert.assertEquals(1, results.size());
+
+    getRequest = PropertyHelper.getReadRequest(
+        
RepositoryVersionResourceProvider.REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID,
+        RepositoryVersionResourceProvider.REPOSITORY_VERSION_ID_PROPERTY_ID,
+        
RepositoryVersionResourceProvider.REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID,
+        
RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID,
+        
RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID,
+        "RepositoryVersions/release",
+        "RepositoryVersions/services",
+        
RepositoryVersionResourceProvider.SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID,
+        
RepositoryVersionResourceProvider.SUBRESOURCE_REPOSITORIES_PROPERTY_ID);
+
+    results = provider.getResources(getRequest, new 
AndPredicate(predicateStackName, predicateStackVersion));
+    Assert.assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+    Map<String, Map<String, Object>> map = r.getPropertiesMap();
+    Assert.assertTrue(map.containsKey("RepositoryVersions"));
+
+    Map<String, Object> vals = map.get("RepositoryVersions");
+    Assert.assertEquals("1.1.7.1-1234", vals.get("repository_version"));
+
+    Assert.assertTrue(map.containsKey("RepositoryVersions/release"));
+    vals = map.get("RepositoryVersions/release");
+    Assert.assertEquals("1234", vals.get("build"));
+    Assert.assertEquals("2.3.4.[1-9]", vals.get("compatible_with"));
+    
Assert.assertEquals("http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.3.4/";, 
vals.get("notes"));
+  }
+
+
+  @Test
   public void testGetResourcesAsAdministrator() throws Exception {
     testGetResources(TestAuthenticationFactory.createAdministrator());
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
index 9cf3aad..4ba5967 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/repository/VersionDefinitionTest.java
@@ -56,18 +56,18 @@ public class VersionDefinitionTest {
     assertEquals("2.3.4.[1-9]", xml.release.compatibleWith);
     assertEquals("http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.3.4/";, 
xml.release.releaseNotes);
 
-    assertEquals(3, xml.manifestServices.size());
+    assertEquals(4, xml.manifestServices.size());
     assertEquals("HDFS-271", xml.manifestServices.get(0).serviceId);
     assertEquals("HDFS", xml.manifestServices.get(0).serviceName);
     assertEquals("2.7.1", xml.manifestServices.get(0).version);
     assertEquals("10", xml.manifestServices.get(0).versionId);
 
-    assertEquals(2, xml.availableServices.size());
+    assertEquals(3, xml.availableServices.size());
     assertEquals("HDFS-271", xml.availableServices.get(0).serviceIdReference);
     assertEquals(0, xml.availableServices.get(0).components.size());
 
-    assertEquals("HIVE-110", xml.availableServices.get(1).serviceIdReference);
-    assertEquals(1, xml.availableServices.get(1).components.size());
+    assertEquals("HIVE-110", xml.availableServices.get(2).serviceIdReference);
+    assertEquals(1, xml.availableServices.get(2).components.size());
 
     assertNotNull(xml.repositoryInfo);
     assertEquals(2, xml.repositoryInfo.getOses().size());

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/test/resources/version_definition_resource_provider.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/resources/version_definition_resource_provider.xml 
b/ambari-server/src/test/resources/version_definition_resource_provider.xml
new file mode 100644
index 0000000..735f91d
--- /dev/null
+++ b/ambari-server/src/test/resources/version_definition_resource_provider.xml
@@ -0,0 +1,77 @@
+<?xml version="1.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.
+-->
+
+<repository-version xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+  xsi:noNamespaceSchemaLocation="version_definition.xsd">
+  
+  <release>
+    <type>PATCH</type>
+    <stack-id>HDP-1.1</stack-id>
+    <version>1.1.7.1</version>
+    <build>1234</build>
+    <compatible-with>2.3.4.[1-9]</compatible-with>
+    
<release-notes>http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.3.4/</release-notes>
+  </release>
+  
+  <manifest>
+    <service id="HDFS-271" name="HDFS" version="2.7.1" version-id="10" />
+    <service id="HIVE-110" name="HIVE" version="1.1.0" />
+    <service id="HIVE-200" name="HIVE" version="2.0.0" />
+  </manifest>
+  
+  <available-services>
+    <service idref="HDFS-271" />
+    <service idref="HIVE-110">
+      <component>HIVE_METASTORE</component>
+    </service>
+  </available-services>
+  
+  <repository-info>
+    <os family="redhat6">
+      <repo>
+        
<baseurl>http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.3.0.0</baseurl>
+        <repoid>HDP-2.3</repoid>
+        <reponame>HDP</reponame>
+      </repo>
+      <repo>
+        
<baseurl>http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6</baseurl>
+        <repoid>HDP-UTILS-1.1.0.20</repoid>
+        <reponame>HDP-UTILS</reponame>
+      </repo>
+    </os>
+    <os family="redhat7">
+      <repo>
+        
<baseurl>http://public-repo-1.hortonworks.com/HDP/centos7/2.x/updates/2.3.0.0</baseurl>
+        <repoid>HDP-2.3</repoid>
+        <reponame>HDP</reponame>
+      </repo>
+      <repo>
+        
<baseurl>http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos7</baseurl>
+        <repoid>HDP-UTILS-1.1.0.20</repoid>
+        <reponame>HDP-UTILS</reponame>
+      </repo>
+    </os>
+
+  </repository-info>
+  
+  <upgrade>
+    <configuration type="hdfs-site">
+      <set key="foo" value="bar" />
+    </configuration>
+  </upgrade>
+</repository-version>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ee623b7f/ambari-server/src/test/resources/version_definition_test.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/version_definition_test.xml 
b/ambari-server/src/test/resources/version_definition_test.xml
index fadfeea..69ea581 100644
--- a/ambari-server/src/test/resources/version_definition_test.xml
+++ b/ambari-server/src/test/resources/version_definition_test.xml
@@ -32,10 +32,12 @@
     <service id="HDFS-271" name="HDFS" version="2.7.1" version-id="10" />
     <service id="HIVE-110" name="HIVE" version="1.1.0" />
     <service id="HIVE-200" name="HIVE" version="2.0.0" />
+    <service id="HBASE-899" name="HBASE" version="8.9.9" />
   </manifest>
   
   <available-services>
     <service idref="HDFS-271" />
+    <service idref="HIVE-200" />
     <service idref="HIVE-110">
       <component>HIVE_METASTORE</component>
     </service>

Reply via email to