You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jl...@apache.org on 2017/07/24 23:52:04 UTC

ambari git commit: AMBARI-21558: Software Registry Recommendations API - Initial patch (jluniya)

Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-14714 c34c86935 -> 332053bcd


AMBARI-21558: Software Registry Recommendations API - Initial patch (jluniya)


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

Branch: refs/heads/branch-feature-AMBARI-14714
Commit: 332053bcddca0f1f36249d5f43ee64a1716fe58d
Parents: c34c869
Author: Jayush Luniya <jl...@hortonworks.com>
Authored: Mon Jul 24 16:51:59 2017 -0700
Committer: Jayush Luniya <jl...@hortonworks.com>
Committed: Mon Jul 24 16:51:59 2017 -0700

----------------------------------------------------------------------
 ...egistryRecommendationResourceDefinition.java |  48 +++
 .../RegistryValidationResourceDefinition.java   |  60 ++++
 .../resources/ResourceInstanceFactoryImpl.java  |   8 +
 .../registry/RegistryRecommendationService.java |  74 ++++
 .../api/services/registry/RegistryService.java  |   2 +-
 .../registry/RegistryValidationService.java     |  74 ++++
 .../ambari/server/controller/AmbariServer.java  |   3 +
 .../AbstractControllerResourceProvider.java     |   4 +
 .../internal/DefaultProviderModule.java         |  10 +
 .../RegistryAdvisorResourceProvider.java        | 134 ++++++++
 .../RegistryRecommendationResourceProvider.java | 125 +++++++
 .../RegistryValidationResourceProvider.java     | 122 +++++++
 .../ambari/server/controller/spi/Resource.java  |   4 +
 .../exceptions/RegistryAdvisorException.java    |  41 +++
 .../ambari/server/registry/MpackEntry.java      |  71 ++++
 .../ambari/server/registry/RegistryAdvisor.java | 341 +++++++++++++++++++
 .../server/registry/RegistryAdvisorRequest.java | 131 +++++++
 .../registry/RegistryAdvisorResponse.java       | 121 +++++++
 .../RegistryRecommendationResponse.java         | 115 +++++++
 .../registry/RegistryValidationResponse.java    | 124 +++++++
 .../apache/ambari/server/utils/SetUtils.java    |  40 +++
 21 files changed, 1651 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RegistryRecommendationResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RegistryRecommendationResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RegistryRecommendationResourceDefinition.java
new file mode 100644
index 0000000..69e6b69
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RegistryRecommendationResourceDefinition.java
@@ -0,0 +1,48 @@
+/*
+ * 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.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Registry recommendation resource definition.
+ */
+public class RegistryRecommendationResourceDefinition extends BaseResourceDefinition {
+  /**
+   * Constructor.
+   */
+  public RegistryRecommendationResourceDefinition() {
+    super(Resource.Type.RegistryRecommendation);
+  }
+
+  @Override
+  public String getPluralName() {
+    return "recommendations";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "recommendation";
+  }
+
+  @Override
+  public boolean isCreatable() {
+    return false;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RegistryValidationResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RegistryValidationResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RegistryValidationResourceDefinition.java
new file mode 100644
index 0000000..af4dcde
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RegistryValidationResourceDefinition.java
@@ -0,0 +1,60 @@
+/*
+ * 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.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Registry validation resource definition.
+ */
+public class RegistryValidationResourceDefinition extends BaseResourceDefinition {
+  /**
+   * Constructor.
+   */
+  public RegistryValidationResourceDefinition() {
+    super(Resource.Type.RegistryValidation);
+  }
+
+  /**
+   * {@inheritDoc}
+   * @return
+   */
+  @Override
+  public String getPluralName() {
+    return "validations";
+  }
+
+  /**
+   * {@inheritDoc}
+   * @return
+   */
+  @Override
+  public String getSingularName() {
+    return "validation";
+  }
+
+  /**
+   * {@inheritDoc}
+   * @return
+   */
+  @Override
+  public boolean isCreatable() {
+    return false;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index 34070e1..73963df 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -153,6 +153,14 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new RegistryResourceDefinition();
         break;
 
+      case RegistryRecommendation:
+        resourceDefinition = new RegistryRecommendationResourceDefinition();
+        break;
+
+      case RegistryValidation:
+        resourceDefinition = new RegistryValidationResourceDefinition();
+        break;
+
       case RegistryScenario:
         resourceDefinition = new RegistryScenarioResourceDefinition();
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryRecommendationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryRecommendationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryRecommendationService.java
new file mode 100644
index 0000000..8a01dae
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryRecommendationService.java
@@ -0,0 +1,74 @@
+/*
+ * 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.api.services.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.annotations.ApiIgnore;
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+
+
+/**
+ * REST API endpoint for registry recommendations
+ */
+@Path("/registries/{registryId}/recommendations")
+public class RegistryRecommendationService extends BaseService {
+
+  /**
+   * Create registry recommendation
+   * @param body        Request body
+   * @param headers     Http headers
+   * @param ui          Uri info
+   * @param registryId  Registry id
+   * @return            {@link Response} containing registry recommendation response
+   */
+  @POST
+  @Produces(MediaType.TEXT_PLAIN)
+  @ApiIgnore // until documented
+  public Response createRegistryRecommendation(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+    @PathParam("registryId") String registryId) {
+    return handleRequest(headers, body, ui, Request.Type.POST,
+      createRegistryRecommendationResource(registryId));
+  }
+
+  /**
+   * Create registry recommendation resource instance
+   * @param registryId  Registry id
+   * @return            Registry recommendation resource instance
+   */
+  ResourceInstance createRegistryRecommendationResource(String registryId) {
+    Map<Resource.Type, String> mapIds = new HashMap<>();
+    mapIds.put(Resource.Type.Registry, registryId);
+    return createResource(Resource.Type.RegistryRecommendation, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryService.java
index 7704149..05ac1b9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryService.java
@@ -64,9 +64,9 @@ public class RegistryService extends BaseService {
   /**
    * Handles: POST /registries/
    *
+   * @param body    request body
    * @param headers http headers
    * @param ui      uri info
-   * @param body    request body
    * @return        information regarding the software registry created
    */
   @POST

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryValidationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryValidationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryValidationService.java
new file mode 100644
index 0000000..20e4b4f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/registry/RegistryValidationService.java
@@ -0,0 +1,74 @@
+/*
+ * 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.api.services.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.annotations.ApiIgnore;
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+
+
+/**
+ * REST API endpoint for registry validations
+ */
+@Path("/registries/{registryId}/validations")
+public class RegistryValidationService extends BaseService {
+
+  /**
+   * Create registry validation
+   * @param body        Request body
+   * @param headers     Http headers
+   * @param ui          Uri info
+   * @param registryId  Registry id
+   * @return            {@link Response} containing registry validation response
+   */
+  @POST
+  @Produces(MediaType.TEXT_PLAIN)
+  @ApiIgnore // until documented
+  public Response createRegistryValidation(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+    @PathParam("registryId") String registryId) {
+    return handleRequest(headers, body, ui, Request.Type.POST,
+      createRegistryValidationResource(registryId));
+  }
+
+  /**
+   * Create registry validation resource
+   * @param registryId  Registry id
+   * @return            Registry validation resource instance
+   */
+  ResourceInstance createRegistryValidationResource(String registryId) {
+    Map<Resource.Type, String> mapIds = new HashMap<>();
+    mapIds.put(Resource.Type.Registry, registryId);
+    return createResource(Resource.Type.RegistryValidation, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 8988be0..6d4d1c9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -69,6 +69,7 @@ import org.apache.ambari.server.controller.internal.ClusterResourceProvider;
 import org.apache.ambari.server.controller.internal.HostResourceProvider;
 import org.apache.ambari.server.controller.internal.PermissionResourceProvider;
 import org.apache.ambari.server.controller.internal.PrivilegeResourceProvider;
+import org.apache.ambari.server.controller.internal.RegistryAdvisorResourceProvider;
 import org.apache.ambari.server.controller.internal.StackAdvisorResourceProvider;
 import org.apache.ambari.server.controller.internal.StackDefinedPropertyProvider;
 import org.apache.ambari.server.controller.internal.StackDependencyResourceProvider;
@@ -91,6 +92,7 @@ import org.apache.ambari.server.orm.dao.ResourceDAO;
 import org.apache.ambari.server.orm.dao.UserDAO;
 import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
 import org.apache.ambari.server.orm.entities.MetainfoEntity;
+import org.apache.ambari.server.registry.RegistryAdvisor;
 import org.apache.ambari.server.resources.ResourceManager;
 import org.apache.ambari.server.resources.api.rest.GetResource;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
@@ -908,6 +910,7 @@ public class AmbariServer {
     KeyService.init(injector.getInstance(PersistKeyValueImpl.class));
     BootStrapResource.init(injector.getInstance(BootStrapImpl.class));
     StackAdvisorResourceProvider.init(injector.getInstance(StackAdvisorHelper.class));
+    RegistryAdvisorResourceProvider.init(injector.getInstance(RegistryAdvisor.class));
     StageUtils.setGson(injector.getInstance(Gson.class));
     StageUtils.setTopologyManager(injector.getInstance(TopologyManager.class));
     StageUtils.setConfiguration(injector.getInstance(Configuration.class));

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index 5cfcdc7..3228a7f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@ -182,6 +182,10 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori
         return new StackResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Registry:
         return new RegistryResourceProvider(managementController);
+      case RegistryRecommendation:
+        return new RegistryRecommendationResourceProvider(managementController);
+      case RegistryValidation:
+        return new RegistryValidationResourceProvider(managementController);
       case RegistryScenario:
         return new RegistryScenarioResourceProvider(managementController);
       case RegistryMpack:

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
index 7466bb4..248abad 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
@@ -92,6 +92,16 @@ public class DefaultProviderModule extends AbstractProviderModule {
         return new AlertResourceProvider(managementController);
       case Registry:
         return new RegistryResourceProvider(managementController);
+      case RegistryRecommendation:
+        return new RegistryRecommendationResourceProvider(managementController);
+      case RegistryValidation:
+        return new RegistryValidationResourceProvider(managementController);
+      case RegistryScenario:
+        return new RegistryScenarioResourceProvider(managementController);
+      case RegistryMpack:
+        return new RegistryMpackResourceProvider(managementController);
+      case RegistryMpackVersion:
+        return new RegistryMpackVersionResourceProvider(managementController);
       case Mpack:
         return new MpackResourceProvider(managementController);
       case AlertDefinition:

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryAdvisorResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryAdvisorResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryAdvisorResourceProvider.java
new file mode 100644
index 0000000..87d8102
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryAdvisorResourceProvider.java
@@ -0,0 +1,134 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.controller.internal;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.registry.MpackEntry;
+import org.apache.ambari.server.registry.RegistryAdvisor;
+import org.apache.ambari.server.registry.RegistryAdvisorRequest;
+import org.apache.ambari.server.registry.RegistryAdvisorRequest.RegistryAdvisorRequestBuilder;
+import org.apache.ambari.server.registry.RegistryAdvisorRequest.RegistryAdvisorRequestType;
+
+import com.google.inject.Inject;
+
+/**
+ * Abstract superclass for registry recommendations and validations.
+ */
+public abstract class RegistryAdvisorResourceProvider extends AbstractControllerResourceProvider {
+
+  public static final String REGISTRY_ID =  PropertyHelper.getPropertyId("RegistryInfo", "registry_id");
+  protected static final String SELECTED_SCENARIOS_PROPERTY_ID = "selected_scenarios";
+  protected static final String SELECTED_MPACKS_PROPERTY_ID = "selected_mpacks";
+
+  protected static RegistryAdvisor registryAdvisor;
+
+  @Inject
+  public static void init(RegistryAdvisor instance) {
+    registryAdvisor = instance;
+  }
+
+  /**
+   * Constructor
+   * @param propertyIds           Property ids
+   * @param keyPropertyIds        Key property ids
+   * @param managementController  Ambari management controller instance
+   */
+  protected RegistryAdvisorResourceProvider(Set<String> propertyIds, Map<Resource.Type, String> keyPropertyIds,
+    AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  /**
+   * Get property containing {@link RegistryAdvisorRequestType}
+   * @return  Property id
+   */
+  protected abstract String getRequestTypePropertyId();
+
+  /**
+   * Create registry advisor request instance
+   * @param request {@link Request} input
+   * @return  {@link RegistryAdvisorRequest} instance
+   */
+  protected RegistryAdvisorRequest createRegistryAdvisorRequest(Request request) {
+    try {
+      Long registryId = Long.valueOf((String) getRequestProperty(request, REGISTRY_ID));
+      RegistryAdvisorRequestType requestType = RegistryAdvisorRequestType.fromString(
+        (String) getRequestProperty(request, getRequestTypePropertyId()));
+      List<String> selectedScenarios = (List<String>) getRequestProperty(request, SELECTED_SCENARIOS_PROPERTY_ID);
+      List<MpackEntry> selectedMpacks = parseSelectedMpacksProperty(request);
+      return RegistryAdvisorRequestBuilder.forRegistry(registryId)
+        .ofType(requestType)
+        .forScenarios(selectedScenarios)
+        .forMpacks(selectedMpacks)
+        .build();
+    } catch (Exception e) {
+      LOG.warn("Error occurred during preparation of registry advisor request", e);
+      Response response = Response.status(Response.Status.BAD_REQUEST)
+        .entity(String.format("Request body is not correct, error: %s", e.getMessage())).build();
+      // TODO: Hosts and services must not be empty
+      throw new WebApplicationException(response);
+    }
+  }
+
+  /**
+   * Parse selected mpacks property from the reuqest
+   * @param request {@link Request} input
+   * @return        List of selected mpacks
+   */
+  private List<MpackEntry> parseSelectedMpacksProperty(Request request) {
+    List<MpackEntry> selectedMpacks = new LinkedList<>();request.getProperties();
+    Set<Map<String, String>> selectedMpacksProperties =
+      (Set<Map<String, String>>) getRequestProperty(request, SELECTED_MPACKS_PROPERTY_ID);
+    if(selectedMpacksProperties != null) {
+      for (Map<String, String> properties : selectedMpacksProperties) {
+        String mpackName = properties.get("mpack_name");
+        String mpackVersion = properties.get("mpack_version");
+        MpackEntry mpackEntry = new MpackEntry(mpackName, mpackVersion);
+        selectedMpacks.add(mpackEntry);
+      }
+    }
+    return selectedMpacks;
+  }
+
+  /**
+   * Get value of property in the request
+   * @param request       {@link Request} input
+   * @param propertyName  Property name
+   * @return              Property value
+   */
+  protected Object getRequestProperty(Request request, String propertyName) {
+    for (Map<String, Object> propertyMap : request.getProperties()) {
+      if (propertyMap.containsKey(propertyName)) {
+        return propertyMap.get(propertyName);
+      }
+    }
+    return null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryRecommendationResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryRecommendationResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryRecommendationResourceProvider.java
new file mode 100644
index 0000000..e2b8ea6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryRecommendationResourceProvider.java
@@ -0,0 +1,125 @@
+/*
+ * 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.controller.internal;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.registry.RegistryAdvisorRequest;
+import org.apache.ambari.server.registry.RegistryRecommendationResponse;
+
+
+/**
+ * Registry recommendation resource provider
+ */
+public class RegistryRecommendationResourceProvider extends RegistryAdvisorResourceProvider {
+
+  protected static final String RECOMMEND_PROPERTY_ID = "recommend";
+  protected static final String RECOMMENDATION_ID_PROPERTY_ID = PropertyHelper.getPropertyId(
+    "RegistryRecommendation", "id");
+  protected static final String RECOMMEND_MPACK_BUNDLES_PROPERTY_ID = PropertyHelper
+    .getPropertyId("recommendations", "mpack_bundles");
+
+  private static Set<String> pkPropertyIds = new HashSet<>(
+    Arrays.asList(REGISTRY_ID, RECOMMENDATION_ID_PROPERTY_ID));
+
+  /**
+   * The property ids for a software registry resource.
+   */
+  private static final Set<String> PROPERTY_IDS = new HashSet<>();
+
+  /**
+   * The key property ids for a software registry resource.
+   */
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<>();
+
+  static {
+    // properties
+    PROPERTY_IDS.add(REGISTRY_ID);
+    PROPERTY_IDS.add(RECOMMENDATION_ID_PROPERTY_ID);
+    PROPERTY_IDS.add(RECOMMEND_PROPERTY_ID);
+    PROPERTY_IDS.add(SELECTED_SCENARIOS_PROPERTY_ID);
+    PROPERTY_IDS.add(RECOMMEND_MPACK_BUNDLES_PROPERTY_ID);
+
+    // keys
+    KEY_PROPERTY_IDS.put(Resource.Type.Registry, REGISTRY_ID);
+    KEY_PROPERTY_IDS.put(Resource.Type.RegistryRecommendation, RECOMMENDATION_ID_PROPERTY_ID);
+
+  }
+
+  /**
+   * Constructor
+   * @param managementController  Ambari management controller instance
+   */
+  protected RegistryRecommendationResourceProvider(
+    final AmbariManagementController managementController) {
+    super(PROPERTY_IDS, KEY_PROPERTY_IDS, managementController);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public RequestStatus createResourcesAuthorized(Request request)
+    throws NoSuchParentResourceException, ResourceAlreadyExistsException, SystemException {
+    RegistryAdvisorRequest registryAdvisorRequest = createRegistryAdvisorRequest(request);
+    RegistryRecommendationResponse response = createResources(new Command<RegistryRecommendationResponse>() {
+      @Override
+      public RegistryRecommendationResponse invoke() throws AmbariException {
+        return registryAdvisor.recommend(registryAdvisorRequest);
+      }
+    });
+    Resource resource = new ResourceImpl(Resource.Type.RegistryRecommendation);
+    resource.setProperty(REGISTRY_ID, response.getRegistryId());
+    resource.setProperty(RECOMMENDATION_ID_PROPERTY_ID, response.getId());
+    resource.setProperty(RECOMMEND_PROPERTY_ID, response.getRequestType().toString());
+    resource.setProperty(SELECTED_SCENARIOS_PROPERTY_ID, response.getSelectedScenarios());
+    resource.setProperty(RECOMMEND_MPACK_BUNDLES_PROPERTY_ID, response.getRecommendations().getMpackBundles());
+
+    Set<Resource> associatedResources = new HashSet<>(Arrays.asList(resource));
+    return getRequestStatus(null, associatedResources);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected String getRequestTypePropertyId() {
+    return RECOMMEND_PROPERTY_ID;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryValidationResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryValidationResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryValidationResourceProvider.java
new file mode 100644
index 0000000..bedbb04
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryValidationResourceProvider.java
@@ -0,0 +1,122 @@
+/*
+ * 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.controller.internal;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.registry.RegistryAdvisorRequest;
+import org.apache.ambari.server.registry.RegistryValidationResponse;
+
+
+/**
+ * Registry validation resource provider
+ */
+public class RegistryValidationResourceProvider extends RegistryAdvisorResourceProvider {
+
+  protected static final String VALIDATE_PROPERTY_ID = "validate";
+  protected static final String VALIDATION_ID_PROPERTY_ID = PropertyHelper.getPropertyId(
+    "RegistryValidation", "id");
+  protected static final String ITEMS_PROPERTY_ID = "items";
+
+  private static Set<String> pkPropertyIds = new HashSet<>(
+    Arrays.asList(REGISTRY_ID, VALIDATION_ID_PROPERTY_ID));
+
+  /**
+   * The property ids for a software registry resource.
+   */
+  private static final Set<String> PROPERTY_IDS = new HashSet<>();
+
+  /**
+   * The key property ids for a software registry resource.
+   */
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<>();
+
+  static {
+    // properties
+    PROPERTY_IDS.add(REGISTRY_ID);
+    PROPERTY_IDS.add(VALIDATION_ID_PROPERTY_ID);
+    PROPERTY_IDS.add(VALIDATE_PROPERTY_ID);
+    PROPERTY_IDS.add(SELECTED_SCENARIOS_PROPERTY_ID);
+    PROPERTY_IDS.add(SELECTED_MPACKS_PROPERTY_ID);
+    PROPERTY_IDS.add(ITEMS_PROPERTY_ID);
+
+    // keys
+    KEY_PROPERTY_IDS.put(Resource.Type.Registry, REGISTRY_ID);
+    KEY_PROPERTY_IDS.put(Resource.Type.RegistryValidation, VALIDATION_ID_PROPERTY_ID);
+
+  }
+
+  protected RegistryValidationResourceProvider(
+    final AmbariManagementController managementController) {
+    super(PROPERTY_IDS, KEY_PROPERTY_IDS, managementController);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public RequestStatus createResourcesAuthorized(Request request)
+    throws NoSuchParentResourceException, ResourceAlreadyExistsException, SystemException {
+    RegistryAdvisorRequest registryAdvisorRequest = createRegistryAdvisorRequest(request);
+    RegistryValidationResponse response = createResources(new Command<RegistryValidationResponse>() {
+      @Override
+      public RegistryValidationResponse invoke() throws AmbariException {
+        return registryAdvisor.validate(registryAdvisorRequest);
+      }
+    });
+    Resource resource = new ResourceImpl(Resource.Type.RegistryValidation);
+    setResourceProperty(resource, REGISTRY_ID, response.getRegistryId(), getPropertyIds());
+    setResourceProperty(resource, VALIDATION_ID_PROPERTY_ID, response.getId(), getPropertyIds());
+    setResourceProperty(resource, VALIDATE_PROPERTY_ID, response.getRequestType().toString(), getPropertyIds());
+    setResourceProperty(resource, SELECTED_SCENARIOS_PROPERTY_ID, response.getSelectedScenarios(), getPropertyIds());
+    setResourceProperty(resource, SELECTED_MPACKS_PROPERTY_ID, response.getSelectedMpacks(), getPropertyIds());
+    setResourceProperty(resource, ITEMS_PROPERTY_ID, response.getItems(), getPropertyIds());
+
+    Set<Resource> associatedResources = new HashSet<>(Arrays.asList(resource));
+    return getRequestStatus(null, associatedResources);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected String getRequestTypePropertyId() {
+    return VALIDATE_PROPERTY_ID;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index f07ca79..1994501 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -91,6 +91,8 @@ public interface Resource {
     Group,
     Member,
     Registry,
+    RegistryRecommendation,
+    RegistryValidation,
     RegistryScenario,
     RegistryMpack,
     RegistryMpackVersion,
@@ -217,6 +219,8 @@ public interface Resource {
     public static final Type Group = InternalType.Group.getType();
     public static final Type Member = InternalType.Member.getType();
     public static final Type Registry = InternalType.Registry.getType();
+    public static final Type RegistryRecommendation = InternalType.RegistryRecommendation.getType();
+    public static final Type RegistryValidation = InternalType.RegistryValidation.getType();
     public static final Type RegistryScenario = InternalType.RegistryScenario.getType();
     public static final Type RegistryMpack = InternalType.RegistryMpack.getType();
     public static final Type RegistryMpackVersion = InternalType.RegistryMpackVersion.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/exceptions/RegistryAdvisorException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/exceptions/RegistryAdvisorException.java b/ambari-server/src/main/java/org/apache/ambari/server/exceptions/RegistryAdvisorException.java
new file mode 100644
index 0000000..c90300f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/exceptions/RegistryAdvisorException.java
@@ -0,0 +1,41 @@
+/*
+ * 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.exceptions;
+
+/**
+ * Registry advisor exception
+ */
+public class RegistryAdvisorException extends Exception {
+
+  /**
+   * Constructor
+   * @param message Exception message
+   */
+  public RegistryAdvisorException(String message) {
+    super(message);
+  }
+
+  /**
+   * Constructor
+   * @param message Exception message
+   * @param cause   Exception cause
+   */
+  public RegistryAdvisorException(String message, Throwable cause) {
+    super(message, cause);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackEntry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackEntry.java b/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackEntry.java
new file mode 100644
index 0000000..c1029af
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackEntry.java
@@ -0,0 +1,71 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.registry;
+
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ *  Mpack version recommenation
+ */
+public class MpackEntry {
+  private String mpackName;
+  private String mpackVersion;
+  private RegistryMpackVersion registryMpackVersion;
+
+  public MpackEntry(String mpackName, String mpackVersion) {
+    this.mpackName = mpackName;
+    this.mpackVersion = mpackVersion;
+    this.registryMpackVersion = registryMpackVersion;
+  }
+
+  /**
+   * Get mpack name
+   * @return
+   */
+  @JsonProperty("mpack_name")
+  public String getMpackName() {
+    return mpackName;
+  }
+
+  /**
+   * Get version
+   * @return
+   */
+  @JsonProperty("mpack_version")
+  public String getMpackVersion() {
+    return mpackVersion;
+  }
+
+  /**
+   * Set registry mpack version
+   * @param registryMpackVersion
+   */
+  public void setRegistryMpackVersion(RegistryMpackVersion registryMpackVersion) {
+    this.registryMpackVersion = registryMpackVersion;
+  }
+
+  /**
+   * Get registry mpack version
+   * @return
+   */
+  @JsonIgnore
+  public RegistryMpackVersion getRegistryMpackVersion() {
+    return registryMpackVersion;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisor.java b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisor.java
new file mode 100644
index 0000000..025338d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisor.java
@@ -0,0 +1,341 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.registry;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ObjectNotFoundException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.registry.RegistryRecommendationResponse.RegistryRecommendationResponseBuilder;
+import org.apache.ambari.server.registry.RegistryRecommendationResponse.RegistryRecommendations;
+import org.apache.ambari.server.registry.RegistryValidationResponse.RegistryValidationItem;
+import org.apache.ambari.server.registry.RegistryValidationResponse.RegistryValidationResponseBuilder;
+import org.apache.ambari.server.utils.SetUtils;
+import org.apache.ambari.server.utils.VersionUtils;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+
+/**
+ * Registry Advisor
+ */
+@Singleton
+public class RegistryAdvisor {
+
+  private AmbariManagementController managementController;
+  private long requestId = 0;
+
+  /**
+   * Given list of all possible mpack bundles, check compatibility and return compatible mpack bundles.
+   * @param mpackBundles  all possible mpack bundles
+   * @return              filtered compatible mpack bundles
+   */
+  private List<Collection<MpackEntry>> filterCompatibleMpackBundles(List<Collection<MpackEntry>> mpackBundles) {
+    List<Collection<MpackEntry>> compatibleMpackBundles = new LinkedList<>();
+    for(Collection<MpackEntry> mpackBundle : mpackBundles) {
+      if(isCompatibleMpackBundle(mpackBundle)) {
+        compatibleMpackBundles.add(mpackBundle);
+      }
+    }
+    return compatibleMpackBundles;
+  }
+
+  /**
+   * Check if the mpack bundle is compatible.
+   * @param mpackBundle mpack bundle to check
+   * @return True if the mpack bundle is compatible, else False
+   */
+  private boolean isCompatibleMpackBundle(Collection<MpackEntry> mpackBundle) {
+    Map<String, MpackEntry> mpackMap = new HashMap<>();
+    for(MpackEntry mvr : mpackBundle) {
+      mpackMap.put(mvr.getMpackName(), mvr);
+    }
+    for(MpackEntry mvr: mpackMap.values()) {
+      RegistryMpackVersion rmv = mvr.getRegistryMpackVersion();
+      List<RegistryMpackCompatiblity> compatiblities = (List<RegistryMpackCompatiblity>) rmv.getCompatibleMpacks();
+      if(compatiblities != null && !compatiblities.isEmpty()) {
+        for(RegistryMpackCompatiblity compatiblity : compatiblities) {
+          if(mpackMap.containsKey(compatiblity.getName())) {
+            String selectedVersion = mpackMap.get(compatiblity.getName()).getMpackVersion();
+            String minVersion = compatiblity.getMinVersion();
+            String maxVersion = compatiblity.getMaxVersion();
+            if(minVersion != null && !minVersion.isEmpty()
+              && VersionUtils.compareVersions(selectedVersion, minVersion) < 0) {
+              return false;
+            }
+            if(maxVersion != null && !maxVersion.isEmpty()
+              && VersionUtils.compareVersions(selectedVersion, maxVersion) > 0) {
+              return false;
+            }
+          }
+        }
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Get merged list of mpacks that support the selected scenarios.
+   * @param registry      registry to use for getting list of mpacks for selected scenarios
+   * @param scenarioNames selected scenario names
+   * @return              merged list of scenario mpacks
+   * @throws AmbariException
+   */
+  private Collection<String> getScenarioMpacks(Registry registry, Collection<String> scenarioNames)
+    throws AmbariException {
+    Set<String> scenarioMpackNames = new HashSet<>();
+    for(String selectedScenario : scenarioNames) {
+      RegistryScenario registryScenario = registry.getRegistryScenario(selectedScenario);
+      for(RegistryScenarioMpack scenarioMpack : registryScenario.getScenarioMpacks()) {
+        if(!scenarioMpackNames.contains(scenarioMpack.getName())) {
+          scenarioMpackNames.add(scenarioMpack.getName());
+        }
+      }
+    }
+    return scenarioMpackNames;
+  }
+
+  /**
+   * Given a list of mpacks, find all mpack versions for each mpack
+   * @param registry    registry to use for getting list of mpack versions
+   * @param mpackNames  list of mpack names
+   * @return            all mpack versions group by mpack
+   * @throws AmbariException
+   */
+  private List<Collection<MpackEntry>> getAllMpackEntries(Registry registry, Collection<String> mpackNames)
+    throws AmbariException {
+    List<Collection<MpackEntry>> allMpackEntries = new LinkedList<>();
+    for(String mpackName : mpackNames) {
+      RegistryMpack registryMpack = registry.getRegistryMpack(mpackName);
+      List<MpackEntry> mpackEntries = new LinkedList<>();
+      for(RegistryMpackVersion registryMpackVersion : registryMpack.getMpackVersions()) {
+        MpackEntry mpackEntry = new MpackEntry(
+          registryMpack.getMpackName(), registryMpackVersion.getMpackVersion());
+        mpackEntry.setRegistryMpackVersion(registryMpackVersion);
+        mpackEntries.add(mpackEntry);
+      }
+      allMpackEntries.add(mpackEntries);
+    }
+    return allMpackEntries;
+  }
+
+  /**
+   * Create a mpacks hash map with key [mpack_name]-[mpack_version]
+   * @param mpackEntries  collection of mpacks
+   * @return  hash map of mpacks
+   */
+  private HashMap<String, MpackEntry> convertToMpackVersionsMap(Collection<MpackEntry> mpackEntries) {
+    HashMap<String, MpackEntry> mpacksMap = new HashMap<>();
+    for(MpackEntry mpackEntry : mpackEntries) {
+      String key = mpackEntry.getMpackName() + "-" + mpackEntry.getMpackVersion();
+      mpacksMap.put(key, mpackEntry);
+    }
+    return mpacksMap;
+  }
+
+  /**
+   * Create a mpacks map with key [mpack_name]
+   * @param mpackEntries  collection of mpacks
+   * @return  hash map of mpacks
+   */
+  private HashMap<String, MpackEntry> convertToMpacksMap(Collection<MpackEntry> mpackEntries) {
+    HashMap<String, MpackEntry> mpacksMap = new HashMap<>();
+    for(MpackEntry mpackEntry : mpackEntries) {
+      String key = mpackEntry.getMpackName();
+      mpacksMap.put(key, mpackEntry);
+    }
+    return mpacksMap;
+  }
+
+  /**
+   * Find a compatible mpack bundle that matches the selected list of mpacks.
+   * @param compatibleMpackBundles  all compatible mpack bundles
+   * @param selectedMpacks          selected mpacks
+   * @return                        compatible mpack bundle
+   */
+  private Collection<MpackEntry> findCompatibleMpackBundle(
+    List<Collection<MpackEntry>> compatibleMpackBundles, Collection<MpackEntry> selectedMpacks) {
+
+    HashMap<String, MpackEntry> selectedMpacksMap = convertToMpackVersionsMap(selectedMpacks);
+    for(Collection<MpackEntry> compatibleMpackBundle : compatibleMpackBundles) {
+      boolean isCompatible = true;
+      for(MpackEntry mpackEntry: compatibleMpackBundle) {
+        String key = mpackEntry.getMpackName() + "-" + mpackEntry.getMpackVersion();
+        if(!selectedMpacksMap.containsKey(key)) {
+          isCompatible = false;
+          break;
+        }
+      }
+      if(isCompatible) {
+        return compatibleMpackBundle;
+      }
+    }
+    return null;
+  }
+
+  @Inject
+  public RegistryAdvisor(AmbariManagementController managementController) {
+    this.managementController = managementController;
+  }
+
+  /**
+   * Returns registry recommendation response based on the request [scenario-mpacks]
+   * @param request the recommendation request
+   * @return        {@link RegistryRecommendationResponse} for the request
+   * @throws AmbariException
+   */
+  public synchronized RegistryRecommendationResponse recommend(RegistryAdvisorRequest request) throws AmbariException {
+    // Get registry
+    Registry registry = managementController.getRegistry(request.getRegistryId());
+    // Get all scenario mpacks
+    Collection<String> scenarioMpackNames = getScenarioMpacks(registry, request.getSelectedScenarios());
+    // Get all mpack versions for each scenario mpack
+    List<Collection<MpackEntry>> allMpackEntries = getAllMpackEntries(registry, scenarioMpackNames);
+    // Get all possible mpack bundles
+    List<Collection<MpackEntry>> allMpackBundles = SetUtils.permutations(allMpackEntries);
+    // Filter down to compatible mpack bundles
+    List<Collection<MpackEntry>> compatibleMpackBundles = filterCompatibleMpackBundles(allMpackBundles);
+    // Order recommentations by versions with latest at pole position.
+    compatibleMpackBundles.sort(new Comparator<Collection<MpackEntry>>() {
+      @Override
+      public int compare(final Collection<MpackEntry> o1, final Collection<MpackEntry> o2) {
+        int o1Wins = 0;
+        int o2Wins = 0;
+        HashMap<String, MpackEntry> o1Map = convertToMpacksMap(o1);
+        HashMap<String, MpackEntry> o2Map = convertToMpacksMap(o2);
+        for(Map.Entry<String, MpackEntry> mapEntry : o1Map.entrySet()) {
+          MpackEntry o1Entry = mapEntry.getValue();
+          MpackEntry o2Entry = o2Map.get(mapEntry.getKey());
+          int compareResult = VersionUtils.compareVersions(o1Entry.getMpackVersion(), o2Entry.getMpackVersion());
+          if(compareResult > 0) {
+            o1Wins++;
+          } else if(compareResult < 0) {
+            o2Wins++;
+          }
+        }
+        // Order in reverse order
+        return o2Wins - o1Wins;
+      }
+    });
+    // Create recommendations
+    RegistryRecommendations recommendations = new RegistryRecommendations();
+    recommendations.setMpackBundles(compatibleMpackBundles);
+    return RegistryRecommendationResponseBuilder.forRegistry(request.getRegistryId())
+      .ofType(request.getRequestType())
+      .forScenarios(request.getSelectedScenarios())
+      .forMpacks(request.getSelectedMpacks())
+      .withId(generateRequestId())
+      .withRecommendations(recommendations).build();
+  }
+
+  /**
+   * Returns registry validation response based on the request [scenario-mpacks]
+   * @param request the validation request
+   * @return        {@link RegistryValidationResponse} for the request
+   * @throws AmbariException
+   */
+  public synchronized RegistryValidationResponse validate(RegistryAdvisorRequest request) throws AmbariException {
+    Registry registry = managementController.getRegistry(request.getRegistryId());
+    List<RegistryValidationItem> validationItems = new LinkedList<>();
+
+    // Get all mpacks required for the selected scenarios
+    Collection<String> scenarioMpackNames = getScenarioMpacks(registry, request.getSelectedScenarios());
+
+    // Validate that all mpacks required for the selected scenarios have been selected
+    for(String mpackName : scenarioMpackNames) {
+      boolean isSelected = false;
+      for(MpackEntry mpackEntry : request.getSelectedMpacks()) {
+        if(mpackName.equals(mpackEntry.getMpackName())) {
+          isSelected = true;
+          break;
+        }
+      }
+      if(!isSelected) {
+        // Validation failure
+        String type = "ScenarioMpackValidation";
+        String level = "FATAL";
+        String message = "Selected mpacks does not contain " + mpackName +
+          " mpack which is required for supporting the selected scenarios.";
+        RegistryValidationItem validationItem = new RegistryValidationItem(type, level, message);
+        validationItems.add(validationItem);
+      }
+    }
+
+    // Validate if any selected mpack is not in the registry
+    List<String> knownSelectedMpackNames = new LinkedList<>();
+    for(MpackEntry mpackEntry : request.getSelectedMpacks()) {
+      try {
+        RegistryMpack registryMpack = registry.getRegistryMpack(mpackEntry.getMpackName());
+        RegistryMpackVersion registryMpackVersion = registryMpack.getMpackVersion(mpackEntry.getMpackVersion());
+        knownSelectedMpackNames.add(registryMpack.getMpackName());
+      } catch (ObjectNotFoundException ex) {
+        String type = "UnknownMpackValidation";
+        String level = "WARN";
+        String mpackFullName = mpackEntry.getMpackName() + "-" + mpackEntry.getMpackVersion();
+        String message = "Mpack " + mpackFullName + " not found in the registry. "
+          + "Cannot validate compatility with other mpacks.";
+        RegistryValidationItem validationItem = new RegistryValidationItem(type, level, message);
+        validationItems.add(validationItem);
+      }
+    }
+
+    // Get all mpack versions for each known selected mpack
+    List<Collection<MpackEntry>> allMpackEntries = getAllMpackEntries(registry, knownSelectedMpackNames);
+    // Get all possible permutations
+    List<Collection<MpackEntry>> allMpackBundles = SetUtils.permutations(allMpackEntries);
+    // Filter down to compatible permutations
+    List<Collection<MpackEntry>> compatibleMpackBundles = filterCompatibleMpackBundles(allMpackBundles);
+
+    // Validate that the selected mpacks is present in a compatible mpack bundle
+    Collection<MpackEntry> compatibleMpackBundle = findCompatibleMpackBundle(compatibleMpackBundles, request.getSelectedMpacks());
+    if(compatibleMpackBundle == null) {
+      // Selected mpacks are not compatible
+      String type = "CompatibleMpackValidation";
+      String level = "FATAL";
+      String message = "Selected mpacks are not compatible and can cause issues during cluster installation.";
+      RegistryValidationItem validationItem = new RegistryValidationItem(type, level, message);
+      validationItems.add(validationItem);
+    }
+
+    return RegistryValidationResponseBuilder.forRegistry(request.getRegistryId())
+      .ofType(request.getRequestType())
+      .forScenarios(request.getSelectedScenarios())
+      .forMpacks(request.getSelectedMpacks())
+      .withId(generateRequestId())
+      .withValidations(validationItems).build();
+  }
+
+  /**
+   * Generate registry advisor request id
+   * TODO: Store registry advisor requests in database.
+   * @return
+   */
+  public long generateRequestId() {
+    requestId += 1;
+    return requestId;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorRequest.java
new file mode 100644
index 0000000..72e9279
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorRequest.java
@@ -0,0 +1,131 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.registry;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.ambari.server.exceptions.RegistryAdvisorException;
+
+/**
+ * Represents a registry advisor request
+ */
+public class RegistryAdvisorRequest {
+  private Long registryId;
+  private RegistryAdvisorRequestType requestType;
+  private List<String> selectedScenarios;
+  private List<MpackEntry> selectedMpacks;
+
+  /**
+   * Constructor
+   * @param registryId          ID of software registry
+   */
+  public RegistryAdvisorRequest(Long registryId) {
+    this.registryId = registryId;
+  }
+
+  public Long getRegistryId() {
+    return registryId;
+  }
+
+  public RegistryAdvisorRequestType getRequestType() {
+    return requestType;
+  }
+
+  public List<String> getSelectedScenarios() {
+    return selectedScenarios;
+  }
+
+  public List<MpackEntry> getSelectedMpacks() {
+    return selectedMpacks;
+  }
+
+  /**
+   * Registry advisor request builder
+   */
+  public static class RegistryAdvisorRequestBuilder {
+    RegistryAdvisorRequest instance;
+
+    private RegistryAdvisorRequestBuilder(Long registryId) {
+      this.instance = new RegistryAdvisorRequest(registryId);
+    }
+
+    public static RegistryAdvisorRequestBuilder forRegistry(Long registryId) {
+      return new RegistryAdvisorRequestBuilder(registryId);
+    }
+
+    public RegistryAdvisorRequestBuilder ofType(RegistryAdvisorRequestType requestType) {
+      this.instance.requestType = requestType;
+      return this;
+    }
+
+    public RegistryAdvisorRequestBuilder forScenarios(List<String> selectedScenarios) {
+      this.instance.selectedScenarios = selectedScenarios;
+      return this;
+    }
+
+    public RegistryAdvisorRequestBuilder forMpacks(List<MpackEntry> selectedMpacks) {
+      this.instance.selectedMpacks = selectedMpacks;
+      return this;
+    }
+
+    public RegistryAdvisorRequest build() {
+      return this.instance;
+    }
+  }
+
+  /**
+   *
+   */
+  public enum RegistryAdvisorRequestType {
+    SCENARIO_MPACKS("scenario-mpacks");
+
+    private String type;
+
+    RegistryAdvisorRequestType(String type) {
+      this.type = type;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+      return type;
+    }
+
+    /**
+     * Get registry advisor request type from string
+     * @param text  string input
+     * @return  {@link RegistryAdvisorRequestType}
+     * @throws RegistryAdvisorException
+     */
+    public static RegistryAdvisorRequestType fromString(String text) throws RegistryAdvisorException {
+      if (text != null) {
+        for (RegistryAdvisorRequestType next : RegistryAdvisorRequestType.values()) {
+          if (text.equalsIgnoreCase(next.type)) {
+            return next;
+          }
+        }
+      }
+      throw new RegistryAdvisorException(String.format(
+        "Unknown request type: %s, possible values: %s", text,
+        Arrays.toString(RegistryAdvisorRequestType.values())));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorResponse.java
new file mode 100644
index 0000000..38db4c3
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorResponse.java
@@ -0,0 +1,121 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.registry;
+
+import java.util.List;
+
+import org.apache.ambari.server.registry.RegistryAdvisorRequest.RegistryAdvisorRequestType;
+
+/**
+ * Abstract registry advisor response POJO
+ */
+public abstract class RegistryAdvisorResponse {
+  private Long id;
+  private Long registryId;
+  private RegistryAdvisorRequest.RegistryAdvisorRequestType requestType;
+  private List<String> selectedScenarios;
+  private List<MpackEntry> selectedMpacks;
+
+  /**
+   * Set registry advisor request id
+   * @param id
+   */
+  public void setId(Long id) {
+    this.id = id;
+  }
+
+  /**
+   * Get registry advisor request id
+   * @return
+   */
+  public Long getId() {
+    return id;
+  }
+
+  /**
+   * Set registry id
+   * @param registryId
+   */
+  public void setRegistryId(Long registryId) {
+    this.registryId = registryId;
+  }
+
+  /**
+   * Get registry id
+   * @return
+   */
+  public Long getRegistryId() {
+    return registryId;
+  }
+
+  /**
+   * Set request type
+   * @param requestType
+   */
+  public void setRequestType(RegistryAdvisorRequestType requestType) {
+    this.requestType = requestType;
+  }
+
+  /**
+   * Get request type
+   * @return
+   */
+  public RegistryAdvisorRequestType getRequestType() {
+    return requestType;
+  }
+
+  /**
+   * Set selected scenarios
+   * @param selectedScenarios
+   */
+  public void setSelectedScenarios(List<String> selectedScenarios) {
+    this.selectedScenarios = selectedScenarios;
+  }
+
+  /**
+   * Get selected scenarios
+   * @return
+   */
+  public List<String> getSelectedScenarios() {
+    return selectedScenarios;
+  }
+
+  /**
+   * Set selected mpacks
+   * @param selectedMpacks
+   */
+  public void setSelectedMpacks(List<MpackEntry> selectedMpacks) {
+    this.selectedMpacks = selectedMpacks;
+  }
+
+  /**
+   * Get selected mpacks
+   * @return
+   */
+  public List<MpackEntry> getSelectedMpacks() {
+    return selectedMpacks;
+  }
+
+  /**
+   * Constructor
+   * @param registryId          ID of software registry
+   */
+  public RegistryAdvisorResponse(Long registryId) {
+    this.registryId = registryId;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryRecommendationResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryRecommendationResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryRecommendationResponse.java
new file mode 100644
index 0000000..923b409
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryRecommendationResponse.java
@@ -0,0 +1,115 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.registry;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.ambari.server.registry.RegistryAdvisorRequest.RegistryAdvisorRequestType;
+
+/**
+ * Registry recommendation response
+ */
+public class RegistryRecommendationResponse extends RegistryAdvisorResponse {
+
+
+  private RegistryRecommendations recommendations;
+
+  /**
+   * Constructor
+   * @param registryId          ID of software registry
+   */
+  public RegistryRecommendationResponse(Long registryId) {
+    super(registryId);
+  }
+
+  /**
+   * Set recommendations
+   * @param recommendations
+   */
+  public void setRecommendations(RegistryRecommendations recommendations) {
+    this.recommendations = recommendations;
+  }
+
+  /**
+   * Get recommentations
+   * @return
+   */
+  public RegistryRecommendations getRecommendations() {
+    return recommendations;
+  }
+
+  /**
+   * Registry advisor request builder
+   */
+  public static class RegistryRecommendationResponseBuilder {
+    RegistryRecommendationResponse instance;
+
+    private RegistryRecommendationResponseBuilder(Long registryId) {
+      this.instance = new RegistryRecommendationResponse(registryId);
+    }
+
+    public static RegistryRecommendationResponseBuilder forRegistry(Long registryId) {
+      return new RegistryRecommendationResponseBuilder(registryId);
+    }
+
+    public RegistryRecommendationResponseBuilder ofType(RegistryAdvisorRequestType requestType) {
+      this.instance.setRequestType(requestType);
+      return this;
+    }
+
+    public RegistryRecommendationResponseBuilder forScenarios(List<String> selectedScenarios) {
+      this.instance.setSelectedScenarios(selectedScenarios);
+      return this;
+    }
+
+    public RegistryRecommendationResponseBuilder forMpacks(List<MpackEntry> selectedMpacks) {
+      this.instance.setSelectedMpacks(selectedMpacks);
+      return this;
+    }
+
+    public RegistryRecommendationResponseBuilder withId(Long id) {
+      this.instance.setId(id);
+      return this;
+    }
+
+    public RegistryRecommendationResponseBuilder withRecommendations(RegistryRecommendations recommendations) {
+      this.instance.recommendations = recommendations;
+      return this;
+    }
+
+    public RegistryRecommendationResponse build() {
+      return this.instance;
+    }
+  }
+
+  /**
+   * Registry recommendations
+   */
+  public static class RegistryRecommendations {
+    public List<Collection<MpackEntry>> mpackBundles;
+
+    public void setMpackBundles(List<Collection<MpackEntry>> mpackBundles) {
+      this.mpackBundles = mpackBundles;
+    }
+
+    public List<Collection<MpackEntry>> getMpackBundles() {
+      return mpackBundles;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryValidationResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryValidationResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryValidationResponse.java
new file mode 100644
index 0000000..ed3b137
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryValidationResponse.java
@@ -0,0 +1,124 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.registry;
+
+import java.util.List;
+
+import org.apache.ambari.server.registry.RegistryAdvisorRequest.RegistryAdvisorRequestType;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * Registry validation response
+ */
+public class RegistryValidationResponse extends  RegistryAdvisorResponse {
+
+  @JsonProperty
+  private List<RegistryValidationItem> items;
+
+  public List<RegistryValidationItem> getItems() {
+    return items;
+  }
+
+  public void setItems(List<RegistryValidationItem> items) {
+    this.items = items;
+  }
+  
+  /**
+   * Constructor
+   *
+   * @param registryId ID of software registry
+   */
+  public RegistryValidationResponse(final Long registryId) {
+    super(registryId);
+  }
+
+  /**
+   * Registry advisor request builder
+   */
+  public static class RegistryValidationResponseBuilder {
+    RegistryValidationResponse instance;
+
+    private RegistryValidationResponseBuilder(Long registryId) {
+      this.instance = new RegistryValidationResponse(registryId);
+    }
+
+    public static RegistryValidationResponseBuilder forRegistry(Long registryId) {
+      return new RegistryValidationResponseBuilder(registryId);
+    }
+
+    public RegistryValidationResponseBuilder ofType(RegistryAdvisorRequestType requestType) {
+      this.instance.setRequestType(requestType);
+      return this;
+    }
+
+    public RegistryValidationResponseBuilder forScenarios(List<String> selectedScenarios) {
+      this.instance.setSelectedScenarios(selectedScenarios);
+      return this;
+    }
+
+    public RegistryValidationResponseBuilder forMpacks(List<MpackEntry> selectedMpacks) {
+      this.instance.setSelectedMpacks(selectedMpacks);
+      return this;
+    }
+
+    public RegistryValidationResponseBuilder withId(Long id) {
+      this.instance.setId(id);
+      return this;
+    }
+
+    public RegistryValidationResponseBuilder withValidations(List<RegistryValidationItem> items) {
+      this.instance.items = items;
+      return this;
+    }
+
+    public RegistryValidationResponse build() {
+      return this.instance;
+    }
+  }
+
+  /**
+   * Registry validation item
+   */
+  public static class RegistryValidationItem {
+    @JsonProperty
+    private String type;
+
+    @JsonProperty
+    private String level;
+
+    @JsonProperty
+    private String message;
+
+    public RegistryValidationItem(String type, String level, String message) {
+      this.type = type;
+      this.level = level;
+      this.message = message;
+    }
+    public String getType() {
+      return type;
+    }
+    public String getLevel() {
+      return level;
+    }
+    public String getMessage() {
+      return message;
+    }
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/332053bc/ambari-server/src/main/java/org/apache/ambari/server/utils/SetUtils.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/SetUtils.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/SetUtils.java
index 5aeb02d..7748a11 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/utils/SetUtils.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/SetUtils.java
@@ -18,9 +18,11 @@
 package org.apache.ambari.server.utils;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
@@ -59,4 +61,42 @@ public class SetUtils {
     }
     return subsets;
   }
+
+  /**
+   * Create all possible permutations of a list of collections.
+   * @param collections List of collections
+   * @param <T>
+   * @return  Permutations between the collections
+   */
+  public static <T> List<Collection<T>> permutations(List<Collection<T>> collections) {
+    if(collections == null || collections.isEmpty()) {
+      return Collections.emptyList();
+    } else {
+      List<Collection<T>> results = new LinkedList<>();
+      permutationsImpl(collections, results, 0, new LinkedList<T>());
+      return results;
+    }
+  }
+
+  /**
+   * Permutations implementation
+   * @param original
+   * @param results
+   * @param depth
+   * @param current
+   * @param <T>
+   */
+  private static <T> void permutationsImpl(List<Collection<T>> original,
+    List<Collection<T>> results, int depth, Collection<T> current) {
+    if(depth == original.size()) {
+      results.add(current);
+      return;
+    }
+    Collection<T> currentList = original.get(depth);
+    for(T element : currentList) {
+      List<T> copyList = new LinkedList<T>(current);
+      copyList.add(element);
+      permutationsImpl(original, results, depth + 1, copyList);
+    }
+  }
 }