ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From yus...@apache.org
Subject [10/51] [partial] AMBARI-7718. Rebase branch-windows-dev against trunk. (Jayush Luniya and Florian Barca via yusaku)
Date Thu, 16 Oct 2014 20:11:34 GMT
http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/RecommendationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RecommendationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RecommendationService.java
new file mode 100644
index 0000000..ca5646e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RecommendationService.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
+ *
+ *     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;
+
+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.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Service responsible for preparing recommendations for host-layout and
+ * configurations.
+ */
+@Path("/stacks/{stackName}/versions/{stackVersion}/recommendations")
+public class RecommendationService extends BaseService {
+
+  /**
+   * Returns host-layout recommendations for list of hosts and services.
+   *
+   * @param body http body
+   * @param headers http headers
+   * @param ui uri info
+   * @param stackName stack name
+   * @param stackVersion stack version
+   * @return recommendations for host-layout
+   */
+  @POST
+  @Produces(MediaType.TEXT_PLAIN)
+  public Response getRecommendation(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+      @PathParam("stackName") String stackName, @PathParam("stackVersion") String stackVersion) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createRecommendationResource(stackName, stackVersion));
+  }
+
+  ResourceInstance createRecommendationResource(String stackName, String stackVersion) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Stack, stackName);
+    mapIds.put(Resource.Type.StackVersion, stackVersion);
+
+    return createResource(Resource.Type.Recommendation, mapIds);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java
index 9483254..fc1b515 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestService.java
@@ -24,6 +24,7 @@ import org.apache.ambari.server.controller.spi.Resource;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -104,6 +105,23 @@ public class RequestService extends BaseService {
   }
 
   /**
+   * Handles: PUT /clusters/{clusterId}/requests/{requestId} or /requests/{requestId}
+   * Change state of existing requests. Usually used to cancel running requests
+   *
+   * @param body        http body
+   * @param headers     http headers
+   * @param ui          uri info
+   * @return information regarding the created services
+   */
+  @PUT
+  @Path("{requestId}")
+  @Produces("text/plain")
+  public Response updateRequests(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                 @PathParam("requestId") String requestId) {
+    return handleRequest(headers, body, ui, Request.Type.PUT, createRequestResource(m_clusterName, requestId));
+  }
+
+  /**
    * Handles: POST /clusters/{clusterId}/requests or /requests
    * Create multiple services.
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
new file mode 100644
index 0000000..03a64e2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceConfigVersionService.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ServiceConfigVersionService extends BaseService {
+  /**
+   * Parent cluster name.
+   */
+  private String m_clusterName;
+
+  public ServiceConfigVersionService(String m_clusterName) {
+    this.m_clusterName = m_clusterName;
+  }
+
+  @GET
+  @Produces("text/plain")
+  public Response getServiceConfigVersions(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET, createServiceConfigResource(m_clusterName));
+  }
+
+
+  ResourceInstance createServiceConfigResource(String clusterName) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, clusterName);
+    mapIds.put(Resource.Type.ServiceConfigVersion, null);
+
+    return createResource(Resource.Type.ServiceConfigVersion, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
index 069f216..a51b50b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java
@@ -18,14 +18,24 @@
 
 package org.apache.ambari.server.api.services;
 
-import org.apache.ambari.server.api.resources.ResourceInstance;
-import org.apache.ambari.server.controller.spi.Resource;
-
-import javax.ws.rs.*;
-import javax.ws.rs.core.*;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+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.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
 /**
  * Service responsible for services resource requests.
  */
@@ -181,6 +191,33 @@ public class ServiceService extends BaseService {
   }
 
   /**
+   * Gets the alerts sub-resource.
+   */
+  @Path("{serviceName}/alerts")
+  public AlertService getAlertHandler(
+      @PathParam("serviceName") String serviceName) {
+    return new AlertService(m_clusterName, serviceName, null);
+  }
+
+  /**
+   * Gets the alert history service
+   *
+   * @param request
+   *          the request
+   * @param serviceName
+   *          the service name
+   *
+   * @return the alert history service
+   */
+  @Path("{serviceName}/alert_history")
+  public AlertHistoryService getAlertHistoryService(
+      @Context javax.ws.rs.core.Request request,
+      @PathParam("serviceName") String serviceName) {
+
+    return new AlertHistoryService(m_clusterName, serviceName, null);
+  }
+
+  /**
    * Create a service resource instance.
    *
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
index fc6e821..7861a95 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
@@ -92,7 +92,6 @@ public class StacksService extends BaseService {
         createStackVersionResource(stackName, stackVersion));
   }
 
-
   @GET
   @Path("{stackName}/versions/{stackVersion}/operating_systems/{osType}/repositories")
   @Produces("text/plain")
@@ -133,6 +132,30 @@ public class StacksService extends BaseService {
         createRepositoryResource(stackName, stackVersion, osType, repoId));
   }
 
+  @GET
+  @Path("{stackName}/versions/{stackVersion}/configurations")
+  @Produces("text/plain")
+  public Response getStackLevelConfigurations(String body, @Context HttpHeaders headers,
+                                   @Context UriInfo ui, @PathParam("stackName") String stackName,
+                                   @PathParam("stackVersion") String stackVersion) {
+
+    return handleRequest(headers, body, new StackUriInfo(ui), Request.Type.GET,
+        createStackLevelConfigurationsResource(stackName, stackVersion, null));
+  }
+
+  @GET
+  @Path("{stackName}/versions/{stackVersion}/configurations/{propertyName}")
+  @Produces("text/plain")
+  public Response getStackLevelConfiguration(String body, @Context HttpHeaders headers,
+                                        @Context UriInfo ui, @PathParam("stackName") String stackName,
+                                        @PathParam("stackVersion") String stackVersion,
+                                        @PathParam("serviceName") String serviceName,
+                                        @PathParam("propertyName") String propertyName) {
+
+    return handleRequest(headers, body, new StackUriInfo(ui), Request.Type.GET,
+        createStackLevelConfigurationsResource(stackName, stackVersion, propertyName));
+  }
+
 
   @GET
   @Path("{stackName}/versions/{stackVersion}/services")
@@ -344,6 +367,16 @@ public class StacksService extends BaseService {
     return createResource(Resource.Type.StackVersion, mapIds);
   }
 
+  ResourceInstance createStackLevelConfigurationsResource(String stackName,
+      String stackVersion, String propertyName) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Stack, stackName);
+    mapIds.put(Resource.Type.StackVersion, stackVersion);
+    mapIds.put(Resource.Type.StackLevelConfiguration, propertyName);
+
+    return createResource(Resource.Type.StackLevelConfiguration, mapIds);
+  }
+
   ResourceInstance createStackResource(String stackName) {
 
     return createResource(Resource.Type.Stack,
@@ -358,10 +391,10 @@ public class StacksService extends BaseService {
    * This should be removed when /stacks2 is removed and we can change the property names
    * in the resource definitions to the new form.
    */
-  private static class StackUriInfo implements UriInfo {
+  public static class StackUriInfo implements UriInfo {
     private UriInfo m_delegate;
 
-    private StackUriInfo(UriInfo delegate) {
+    public StackUriInfo(UriInfo delegate) {
       m_delegate = delegate;
     }
     @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserPrivilegeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserPrivilegeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserPrivilegeService.java
new file mode 100644
index 0000000..80769cf
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserPrivilegeService.java
@@ -0,0 +1,79 @@
+/**
+ * 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 privileges and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+/**
+ *  Service responsible for user privilege resource requests.
+ */
+public class UserPrivilegeService extends PrivilegeService {
+
+  private final String userName;
+
+  public UserPrivilegeService(String userName) {
+    this.userName = userName;
+  }
+
+  // ----- PrivilegeService --------------------------------------------------
+
+  @Override
+  public Response createPrivilege(String body, HttpHeaders headers, UriInfo ui) {
+    return Response.status(HttpServletResponse.SC_NOT_IMPLEMENTED).build();
+  }
+
+  @Override
+  public Response updatePrivilege(String body, HttpHeaders headers, UriInfo ui,
+      String privilegeId) {
+    return Response.status(HttpServletResponse.SC_NOT_IMPLEMENTED).build();
+  }
+
+  @Override
+  public Response updatePrivileges(String body, HttpHeaders headers, UriInfo ui) {
+    return Response.status(HttpServletResponse.SC_NOT_IMPLEMENTED).build();
+  }
+
+  @Override
+  public Response deletePrivilege(HttpHeaders headers, UriInfo ui,
+      String privilegeId) {
+    return Response.status(HttpServletResponse.SC_NOT_IMPLEMENTED).build();
+  }
+
+  @Override
+  public Response deletePrivileges(String body, HttpHeaders headers, UriInfo ui) {
+    return Response.status(HttpServletResponse.SC_NOT_IMPLEMENTED).build();
+  }
+
+  @Override
+  protected ResourceInstance createPrivilegeResource(String privilegeId) {
+    final Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.User, userName);
+    mapIds.put(Resource.Type.UserPrivilege, privilegeId);
+    return createResource(Resource.Type.UserPrivilege, mapIds);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java
index 87cb3ba..00be99c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/UserService.java
@@ -129,6 +129,16 @@ public class UserService extends BaseService {
   }
 
   /**
+   * Gets the user privilege service
+   */
+  @Path("{userName}/privileges")
+  public PrivilegeService getPrivilegeService(@Context javax.ws.rs.core.Request request,
+                                              @PathParam ("userName") String userName) {
+
+    return new UserPrivilegeService(userName);
+  }
+
+  /**
    * Create a user resource instance.
    *
    * @param userName  user name

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/ValidationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ValidationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ValidationService.java
new file mode 100644
index 0000000..03f0b1e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ValidationService.java
@@ -0,0 +1,70 @@
+/**
+ * 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;
+
+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.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Service responsible for validation of host-layout and configurations.
+ */
+@Path("/stacks/{stackName}/versions/{stackVersion}/validations")
+public class ValidationService extends BaseService {
+
+  /**
+   * Returns validation of host-layout.
+   *
+   * @param body http body
+   * @param headers http headers
+   * @param ui uri info
+   * @param stackName stack name
+   * @param stackVersion stack version
+   * @return validation items if any
+   */
+  @POST
+  @Produces(MediaType.TEXT_PLAIN)
+  public Response getValidation(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+      @PathParam("stackName") String stackName, @PathParam("stackVersion") String stackVersion) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createValidationResource(stackName, stackVersion));
+  }
+
+  ResourceInstance createValidationResource(String stackName, String stackVersion) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Stack, stackName);
+    mapIds.put(Resource.Type.StackVersion, stackVersion);
+
+    return createResource(Resource.Type.Validation, mapIds);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
index c32abe6..05c5079 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
@@ -30,6 +30,7 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
@@ -51,6 +52,11 @@ public class ViewInstanceService extends BaseService {
    */
   private final String version;
 
+  /**
+   * The view registry;
+   */
+  private final ViewRegistry viewRegistry;
+
 
   // ----- Constructors ------------------------------------------------------
 
@@ -63,6 +69,8 @@ public class ViewInstanceService extends BaseService {
   public ViewInstanceService(String viewName, String version) {
     this.viewName = viewName;
     this.version  = version;
+
+    viewRegistry = ViewRegistry.getInstance();
   }
 
 
@@ -84,6 +92,7 @@ public class ViewInstanceService extends BaseService {
   public Response getService(String body, @Context HttpHeaders headers, @Context UriInfo ui,
                              @PathParam("instanceName") String instanceName) {
 
+    hasPermission(Request.Type.GET, instanceName);
     return handleRequest(headers, body, ui, Request.Type.GET,
         createResource(viewName, version, instanceName));
   }
@@ -100,6 +109,8 @@ public class ViewInstanceService extends BaseService {
   @GET
   @Produces("text/plain")
   public Response getServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+
+    hasPermission(Request.Type.GET, null);
     return handleRequest(headers, body, ui, Request.Type.GET,
         createResource(viewName, version,  null));
   }
@@ -120,6 +131,7 @@ public class ViewInstanceService extends BaseService {
   @Produces("text/plain")
   public Response createService(String body, @Context HttpHeaders headers, @Context UriInfo ui,
                                 @PathParam("instanceName") String instanceName) {
+    hasPermission(Request.Type.POST, instanceName);
     return handleRequest(headers, body, ui, Request.Type.POST,
         createResource(viewName, version,  instanceName));
   }
@@ -138,6 +150,7 @@ public class ViewInstanceService extends BaseService {
   @Produces("text/plain")
   public Response createServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
 
+    hasPermission(Request.Type.POST, null);
     return handleRequest(headers, body, ui, Request.Type.POST,
         createResource(viewName, version,  null));
   }
@@ -159,6 +172,7 @@ public class ViewInstanceService extends BaseService {
   public Response updateService(String body, @Context HttpHeaders headers, @Context UriInfo ui,
                                 @PathParam("instanceName") String instanceName) {
 
+    hasPermission(Request.Type.PUT, instanceName);
     return handleRequest(headers, body, ui, Request.Type.PUT, createResource(viewName, version,  instanceName));
   }
 
@@ -176,6 +190,7 @@ public class ViewInstanceService extends BaseService {
   @Produces("text/plain")
   public Response updateServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
 
+    hasPermission(Request.Type.PUT, null);
     return handleRequest(headers, body, ui, Request.Type.PUT, createResource(viewName, version,  null));
   }
 
@@ -195,6 +210,7 @@ public class ViewInstanceService extends BaseService {
   public Response deleteService(@Context HttpHeaders headers, @Context UriInfo ui,
                                 @PathParam("instanceName") String instanceName) {
 
+    hasPermission(Request.Type.DELETE, instanceName);
     return handleRequest(headers, null, ui, Request.Type.DELETE, createResource(viewName, version,  instanceName));
   }
 
@@ -206,8 +222,11 @@ public class ViewInstanceService extends BaseService {
    * @return the service
    */
   @Path("{instanceName}/{resources}")
-  public Object getResourceHandler(@PathParam("instanceName") String instanceName,
-                                            @PathParam("resources") String resources) {
+  public Object getResourceHandler(@Context javax.ws.rs.core.Request request,
+                                   @PathParam("instanceName") String instanceName,
+                                   @PathParam("resources") String resources) {
+
+    hasPermission(Request.Type.valueOf(request.getMethod()), instanceName);
 
     ViewInstanceEntity instanceDefinition =
         ViewRegistry.getInstance().getInstanceDefinition(viewName, version, instanceName);
@@ -226,6 +245,18 @@ public class ViewInstanceService extends BaseService {
     return service;
   }
 
+  /**
+   * Gets the admin privilege service
+   */
+  @Path("{instanceName}/privileges")
+  public PrivilegeService getPrivilegeService(@Context javax.ws.rs.core.Request request,
+                                              @PathParam ("instanceName") String instanceName) {
+
+    hasPermission(Request.Type.valueOf(request.getMethod()), instanceName);
+
+    return new ViewPrivilegeService(viewName, version, instanceName);
+  }
+
 
   // ----- helper methods ----------------------------------------------------
 
@@ -244,4 +275,20 @@ public class ViewInstanceService extends BaseService {
     mapIds.put(Resource.Type.ViewInstance, instanceName);
     return createResource(Resource.Type.ViewInstance, mapIds);
   }
+
+  /**
+   * Determine whether or not the access specified by the given request type
+   * is permitted for the current user on the view instance resource identified
+   * by the given instance name.
+   *
+   * @param requestType   the request method type
+   * @param instanceName  the name of the view instance resource
+   *
+   * @throws WebApplicationException if access is forbidden
+   */
+  private void hasPermission(Request.Type requestType, String instanceName) {
+    if (!viewRegistry.checkPermission(viewName, version, instanceName, requestType == Request.Type.GET)) {
+      throw new WebApplicationException(Response.Status.FORBIDDEN);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
new file mode 100644
index 0000000..711e85b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPermissionService.java
@@ -0,0 +1,185 @@
+/**
+ * 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;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+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.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Service responsible for custom view permission resource requests.
+ */
+public class ViewPermissionService extends BaseService {
+
+  /**
+   * Parent view name.
+   */
+  private final String viewName;
+
+  /**
+   * The view version.
+   */
+  private final String version;
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view permission service.
+   *
+   * @param viewName  the view id
+   * @param version   the version
+   */
+  public ViewPermissionService(String viewName, String version) {
+    this.viewName = viewName;
+    this.version  = version;
+  }
+
+
+  // ----- ViewPermissionService -----------------------------------------------
+
+  /**
+   * Handles: GET /permissions/{permissionID}
+   * Get a specific permission.
+   *
+   * @param headers        http headers
+   * @param ui             uri info
+   * @param permissionId   permission id
+   *
+   * @return permission instance representation
+   */
+  @GET
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response getPermission(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, null, ui, Request.Type.GET, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+  /**
+   * Handles: GET  /permissions
+   * Get all permissions.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   *
+   * @return permission collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  public Response getPermissions(@Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, null, ui, Request.Type.GET, createPermissionResource(
+        viewName, version, null));
+  }
+
+  /**
+   * Handles: POST /permissions/{permissionID}
+   * Create a specific permission.
+   *
+   * @param headers    http headers
+   * @param ui         uri info
+   * @param permissionId   permission id
+   *
+   * @return information regarding the created permission
+   */
+  @POST
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response createPermission(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                   @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+  /**
+   * Handles: PUT /permissions/{permissionID}
+   * Update a specific permission.
+   *
+   * @param headers   http headers
+   * @param ui        uri info
+   * @param permissionId  permission id
+   *
+   * @return information regarding the updated permission
+   */
+  @PUT
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response updatePermission(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                   @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+  /**
+   * Handles: DELETE /permissions/{permissionID}
+   * Delete a specific permission.
+   *
+   * @param headers   http headers
+   * @param ui        uri info
+   * @param permissionId  permission id
+   *
+   * @return information regarding the deleted permission
+   */
+  @DELETE
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response deletePermission(@Context HttpHeaders headers, @Context UriInfo ui,
+                                   @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Create a permission resource.
+   *
+   * @param permissionId permission name
+   *
+   * @return a permission resource instance
+   */
+  protected ResourceInstance createPermissionResource(String viewName, String viewVersion, String permissionId) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewVersion, viewVersion);
+    mapIds.put(Resource.Type.ViewPermission, permissionId);
+
+    return createResource(Resource.Type.ViewPermission, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPrivilegeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPrivilegeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPrivilegeService.java
new file mode 100644
index 0000000..ab41241
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewPrivilegeService.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 privileges and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *  Service responsible for view privilege resource requests.
+ */
+public class ViewPrivilegeService extends PrivilegeService {
+
+  private final String viewName;
+  private final String viewVersion;
+  private final String instanceName;
+
+  public ViewPrivilegeService(String viewName, String viewVersion, String instanceName) {
+    this.viewName = viewName;
+    this.viewVersion = viewVersion;
+    this.instanceName = instanceName;
+  }
+
+  // ----- PrivilegeService --------------------------------------------------
+
+  @Override
+  protected ResourceInstance createPrivilegeResource(String privilegeId) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewVersion, viewVersion);
+    mapIds.put(Resource.Type.ViewInstance, instanceName);
+    mapIds.put(Resource.Type.ViewPrivilege, privilegeId);
+
+    return createResource(Resource.Type.ViewPrivilege, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
index 0dac300..8152ae6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewVersionService.java
@@ -166,6 +166,19 @@ public class ViewVersionService extends BaseService {
     return new ViewInstanceService(viewName, version);
   }
 
+  /**
+   * Get the permissions sub-resource
+   *
+   * @param version  the version
+   *
+   * @return the permission service
+   */
+  @Path("{version}/permissions")
+  public ViewPermissionService getPermissionHandler(@PathParam("version") String version) {
+
+    return new ViewPermissionService(viewName, version);
+  }
+
 
   // ----- helper methods ----------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java
index 0d75a8e..bbe7647 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/JsonRequestBodyParser.java
@@ -18,6 +18,15 @@
 
 package org.apache.ambari.server.api.services.parsers;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.ambari.server.api.services.NamedPropertySet;
 import org.apache.ambari.server.api.services.RequestBody;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
@@ -26,9 +35,6 @@ import org.codehaus.jackson.map.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.util.*;
-
 /**
  * JSON parser which parses a JSON string into a map of properties and values.
  */
@@ -113,13 +119,24 @@ public class JsonRequestBodyParser implements RequestBodyParser {
         //array
         Iterator<JsonNode>       arrayIter = child.getElements();
         Set<Map<String, Object>> arraySet  = new HashSet<Map<String, Object>>();
+        List<String> primitives = new ArrayList<String>();
 
         while (arrayIter.hasNext()) {
-          NamedPropertySet arrayPropertySet = new NamedPropertySet(name, new HashMap<String, Object>());
-          processNode(arrayIter.next(), "", arrayPropertySet, requestInfoProps);
-          arraySet.add(arrayPropertySet.getProperties());
+          JsonNode next = arrayIter.next();
+
+          if (next.isValueNode()) {
+            // All remain nodes will be also primitives
+            primitives.add(next.asText());
+          } else {
+            NamedPropertySet arrayPropertySet = new NamedPropertySet(name,
+                new HashMap<String, Object>());
+            processNode(next, "", arrayPropertySet, requestInfoProps);
+            arraySet.add(arrayPropertySet.getProperties());
+          }
         }
-        propertySet.getProperties().put(PropertyHelper.getPropertyId(path, name), arraySet);
+
+        Object properties = primitives.isEmpty() ? arraySet : primitives;
+        propertySet.getProperties().put(PropertyHelper.getPropertyId(path, name), properties);
       } else if (child.isContainerNode()) {
         // object
         if (name.equals(BODY_TITLE)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/persistence/PersistenceManagerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/persistence/PersistenceManagerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/persistence/PersistenceManagerImpl.java
index 595ad00..2013fe4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/persistence/PersistenceManagerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/persistence/PersistenceManagerImpl.java
@@ -67,7 +67,7 @@ public class PersistenceManagerImpl implements PersistenceManager {
       for (Map.Entry<Resource.Type, String> entry : mapResourceIds.entrySet()) {
         Map<String, Object> mapProperties = propertySet.getProperties();
         String property = schema.getKeyPropertyId(entry.getKey());
-        if (! mapProperties.containsKey(property)) {
+        if (!mapProperties.containsKey(property)) {
           mapProperties.put(property, entry.getValue());
         }
       }
@@ -79,25 +79,25 @@ public class PersistenceManagerImpl implements PersistenceManager {
   public RequestStatus update(ResourceInstance resource, RequestBody requestBody)
       throws UnsupportedPropertyException, SystemException, NoSuchParentResourceException, NoSuchResourceException {
 
-    // Allow for multiple property sets in an update request body...
+    Map<Resource.Type, String> mapResourceIds = resource.getKeyValueMap();
+    Resource.Type type = resource.getResourceDefinition().getType();
+    Schema schema = m_controller.getSchema(type);
+
     Set<NamedPropertySet> setProperties = requestBody.getNamedPropertySets();
-    if (setProperties.size() > 1) {
-      Map<Resource.Type, String> mapResourceIds = resource.getKeyValueMap();
-      Resource.Type type = resource.getResourceDefinition().getType();
-      Schema schema = m_controller.getSchema(type);
 
-      for (NamedPropertySet propertySet : setProperties) {
-        for (Map.Entry<Resource.Type, String> entry : mapResourceIds.entrySet()) {
+    for (NamedPropertySet propertySet : setProperties) {
+      for (Map.Entry<Resource.Type, String> entry : mapResourceIds.entrySet()) {
+        if (entry.getValue() != null) {
           Map<String, Object> mapProperties = propertySet.getProperties();
           String property = schema.getKeyPropertyId(entry.getKey());
-          if (! mapProperties.containsKey(property)) {
+          if (!mapProperties.containsKey(property)) {
             mapProperties.put(property, entry.getValue());
           }
         }
       }
     }
-    return m_controller.updateResources(resource.getResourceDefinition().getType(),
-        createControllerRequest(requestBody), resource.getQuery().getPredicate());
+
+    return m_controller.updateResources(type, createControllerRequest(requestBody), resource.getQuery().getPredicate());
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/serializers/JsonSerializer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/serializers/JsonSerializer.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/serializers/JsonSerializer.java
index 59d5a8a..7f57f7f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/serializers/JsonSerializer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/serializers/JsonSerializer.java
@@ -115,7 +115,10 @@ public class JsonSerializer implements ResultSerializer {
     }
 
     if (isArray(node)) {
-      m_generator.writeArrayFieldStart(node.getName());
+      if (node.getName() != null)
+        m_generator.writeArrayFieldStart(node.getName());
+      else
+        m_generator.writeStartArray();
     }
 
     for (TreeNode<Resource> child : node.getChildren()) {
@@ -139,7 +142,9 @@ public class JsonSerializer implements ResultSerializer {
 
   // Determines whether or not the given node is an array
   private boolean isArray(TreeNode<Resource> node) {
-    return node.getObject() == null && node.getName() != null;
+    return (node.getObject() == null && node.getName() != null) ||
+            (node.getObject() == null && node.getName() == null &&
+             node.getChildren().size() > 1);
   }
 
   private TreeNode<Map<String, Object>> getTreeProperties (Map<String, Map<String, Object>> propertiesMap) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorException.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorException.java
new file mode 100644
index 0000000..b13e1e5
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorException.java
@@ -0,0 +1,31 @@
+/**
+ * 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.stackadvisor;
+
+@SuppressWarnings("serial")
+public class StackAdvisorException extends Exception {
+
+  public StackAdvisorException(String message) {
+    super(message);
+  }
+
+  public StackAdvisorException(String message, Throwable cause) {
+    super(message, cause);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
new file mode 100644
index 0000000..f5c81a4
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
@@ -0,0 +1,128 @@
+/**
+ * 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.stackadvisor;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest.StackAdvisorRequestType;
+import org.apache.ambari.server.api.services.stackadvisor.commands.GetComponentLayoutRecommnedationCommand;
+import org.apache.ambari.server.api.services.stackadvisor.commands.GetComponentLayoutValidationCommand;
+import org.apache.ambari.server.api.services.stackadvisor.commands.GetConfigurationRecommnedationCommand;
+import org.apache.ambari.server.api.services.stackadvisor.commands.GetConfigurationValidationCommand;
+import org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommand;
+import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
+import org.apache.ambari.server.api.services.stackadvisor.validations.ValidationResponse;
+import org.apache.ambari.server.configuration.Configuration;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class StackAdvisorHelper {
+
+  private File recommendationsDir;
+  private String stackAdvisorScript;
+  private final AmbariMetaInfo metaInfo;
+
+  /* Monotonically increasing requestid */
+  private int requestId = 0;
+  private StackAdvisorRunner saRunner;
+
+  @Inject
+  public StackAdvisorHelper(Configuration conf, StackAdvisorRunner saRunner,
+                            AmbariMetaInfo metaInfo) throws IOException {
+    this.recommendationsDir = conf.getRecommendationsDir();
+    this.stackAdvisorScript = conf.getStackAdvisorScript();
+    this.saRunner = saRunner;
+    this.metaInfo = metaInfo;
+  }
+
+  /**
+   * Returns validation (component-layout or configurations) result for the
+   * request.
+   *
+   * @param request the validation request
+   * @return {@link ValidationResponse} instance
+   * @throws StackAdvisorException in case of stack advisor script errors
+   */
+  public synchronized ValidationResponse validate(StackAdvisorRequest request)
+      throws StackAdvisorException {
+    requestId += 1;
+
+    StackAdvisorCommand<ValidationResponse> command = createValidationCommand(request
+        .getRequestType());
+
+    return command.invoke(request);
+  }
+
+  StackAdvisorCommand<ValidationResponse> createValidationCommand(
+      StackAdvisorRequestType requestType) throws StackAdvisorException {
+    StackAdvisorCommand<ValidationResponse> command;
+    if (requestType == StackAdvisorRequestType.HOST_GROUPS) {
+      command = new GetComponentLayoutValidationCommand(recommendationsDir, stackAdvisorScript,
+          requestId, saRunner, metaInfo);
+    } else if (requestType == StackAdvisorRequestType.CONFIGURATIONS) {
+      command = new GetConfigurationValidationCommand(recommendationsDir, stackAdvisorScript,
+          requestId, saRunner, metaInfo);
+    } else {
+      throw new StackAdvisorRequestException(String.format("Unsupported request type, type=%s",
+          requestType));
+    }
+
+    return command;
+  }
+
+  /**
+   * Returns recommendation (component-layout or configurations) based on the
+   * request.
+   *
+   * @param request the recommendation request
+   * @return {@link RecommendationResponse} instance
+   * @throws StackAdvisorException in case of stack advisor script errors
+   */
+  public synchronized RecommendationResponse recommend(StackAdvisorRequest request)
+      throws StackAdvisorException {
+    requestId += 1;
+
+    StackAdvisorCommand<RecommendationResponse> command = createRecommendationCommand(request
+        .getRequestType());
+
+    return command.invoke(request);
+  }
+
+  StackAdvisorCommand<RecommendationResponse> createRecommendationCommand(
+      StackAdvisorRequestType requestType) throws StackAdvisorException {
+    StackAdvisorCommand<RecommendationResponse> command;
+    if (requestType == StackAdvisorRequestType.HOST_GROUPS) {
+      command = new GetComponentLayoutRecommnedationCommand(recommendationsDir, stackAdvisorScript,
+          requestId, saRunner, metaInfo);
+    } else if (requestType == StackAdvisorRequestType.CONFIGURATIONS) {
+      command = new GetConfigurationRecommnedationCommand(recommendationsDir, stackAdvisorScript,
+          requestId, saRunner, metaInfo);
+    } else {
+      throw new StackAdvisorRequestException(String.format("Unsupported request type, type=%s",
+          requestType));
+    }
+
+    return command;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java
new file mode 100644
index 0000000..991f198
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java
@@ -0,0 +1,175 @@
+/**
+ * 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.stackadvisor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Stack advisor request.
+ */
+public class StackAdvisorRequest {
+
+  private String stackName;
+  private String stackVersion;
+  private StackAdvisorRequestType requestType;
+  private List<String> hosts = new ArrayList<String>();
+  private List<String> services = new ArrayList<String>();
+  private Map<String, Set<String>> componentHostsMap = new HashMap<String, Set<String>>();
+  private Map<String, Set<String>> hostComponents = new HashMap<String, Set<String>>();
+  private Map<String, Set<String>> hostGroupBindings = new HashMap<String, Set<String>>();
+  private Map<String, Map<String, Map<String, String>>> configurations = new HashMap<String, Map<String, Map<String, String>>>();
+
+  public String getStackName() {
+    return stackName;
+  }
+
+  public String getStackVersion() {
+    return stackVersion;
+  }
+
+  public StackAdvisorRequestType getRequestType() {
+    return requestType;
+  }
+
+  public List<String> getHosts() {
+    return hosts;
+  }
+
+  public List<String> getServices() {
+    return services;
+  }
+
+  public Map<String, Set<String>> getComponentHostsMap() {
+    return componentHostsMap;
+  }
+
+  public String getHostsCommaSeparated() {
+    return StringUtils.join(hosts, ",");
+  }
+
+  public String getServicesCommaSeparated() {
+    return StringUtils.join(services, ",");
+  }
+
+  public Map<String, Set<String>> getHostComponents() {
+    return hostComponents;
+  }
+
+  public Map<String, Set<String>> getHostGroupBindings() {
+    return hostGroupBindings;
+  }
+
+  public Map<String, Map<String, Map<String, String>>> getConfigurations() {
+    return configurations;
+  }
+
+  private StackAdvisorRequest(String stackName, String stackVersion) {
+    this.stackName = stackName;
+    this.stackVersion = stackVersion;
+  }
+
+  public static class StackAdvisorRequestBuilder {
+    StackAdvisorRequest instance;
+
+    private StackAdvisorRequestBuilder(String stackName, String stackVersion) {
+      this.instance = new StackAdvisorRequest(stackName, stackVersion);
+    }
+
+    public static StackAdvisorRequestBuilder forStack(String stackName, String stackVersion) {
+      return new StackAdvisorRequestBuilder(stackName, stackVersion);
+    }
+
+    public StackAdvisorRequestBuilder ofType(StackAdvisorRequestType requestType) {
+      this.instance.requestType = requestType;
+      return this;
+    }
+
+    public StackAdvisorRequestBuilder forHosts(List<String> hosts) {
+      this.instance.hosts = hosts;
+      return this;
+    }
+
+    public StackAdvisorRequestBuilder forServices(List<String> services) {
+      this.instance.services = services;
+      return this;
+    }
+
+    public StackAdvisorRequestBuilder withComponentHostsMap(
+        Map<String, Set<String>> componentHostsMap) {
+      this.instance.componentHostsMap = componentHostsMap;
+      return this;
+    }
+
+    public StackAdvisorRequestBuilder forHostComponents(Map<String, Set<String>> hostComponents) {
+      this.instance.hostComponents = hostComponents;
+      return this;
+    }
+
+    public StackAdvisorRequestBuilder forHostsGroupBindings(
+        Map<String, Set<String>> hostGroupBindings) {
+      this.instance.hostGroupBindings = hostGroupBindings;
+      return this;
+    }
+
+    public StackAdvisorRequestBuilder withConfigurations(
+        Map<String, Map<String, Map<String, String>>> configurations) {
+      this.instance.configurations = configurations;
+      return this;
+    }
+
+    public StackAdvisorRequest build() {
+      return this.instance;
+    }
+  }
+
+  public enum StackAdvisorRequestType {
+    HOST_GROUPS("host_groups"), CONFIGURATIONS("configurations");
+
+    private String type;
+
+    private StackAdvisorRequestType(String type) {
+      this.type = type;
+    }
+
+    @Override
+    public String toString() {
+      return type;
+    }
+
+    public static StackAdvisorRequestType fromString(String text) throws StackAdvisorException {
+      if (text != null) {
+        for (StackAdvisorRequestType next : StackAdvisorRequestType.values()) {
+          if (text.equalsIgnoreCase(next.type)) {
+            return next;
+          }
+        }
+      }
+      throw new StackAdvisorException(String.format(
+          "Unknown request type: %s, possible values: %s", text,
+          Arrays.toString(StackAdvisorRequestType.values())));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestException.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestException.java
new file mode 100644
index 0000000..93e6d7b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestException.java
@@ -0,0 +1,27 @@
+/**
+ * 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.stackadvisor;
+
+@SuppressWarnings("serial")
+public class StackAdvisorRequestException extends StackAdvisorException {
+
+  public StackAdvisorRequestException(String message) {
+    super(message);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorResponse.java
new file mode 100644
index 0000000..b6d7de7
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorResponse.java
@@ -0,0 +1,73 @@
+/**
+ * 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.stackadvisor;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * Abstract stack advisor response POJO.
+ */
+public abstract class StackAdvisorResponse {
+
+  private int id;
+
+  @JsonProperty("Versions")
+  private Version version;
+
+  public int getId() {
+    return id;
+  }
+
+  public void setId(int id) {
+    this.id = id;
+  }
+
+  public Version getVersion() {
+    return version;
+  }
+
+  public void setVersion(Version version) {
+    this.version = version;
+  }
+
+  public static class Version {
+    @JsonProperty("stack_name")
+    private String stackName;
+
+    @JsonProperty("stack_version")
+    private String stackVersion;
+
+    public String getStackName() {
+      return stackName;
+    }
+
+    public void setStackName(String stackName) {
+      this.stackName = stackName;
+    }
+
+    public String getStackVersion() {
+      return stackVersion;
+    }
+
+    public void setStackVersion(String stackVersion) {
+      this.stackVersion = stackVersion;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunner.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunner.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunner.java
new file mode 100644
index 0000000..97f688b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunner.java
@@ -0,0 +1,149 @@
+/**
+ * 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.stackadvisor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommandType;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Singleton;
+
+@Singleton
+public class StackAdvisorRunner {
+
+  private final static Logger LOG = LoggerFactory.getLogger(StackAdvisorRunner.class);
+
+  /**
+   * Runs stack_advisor.py script in the specified {@code actionDirectory}.
+   *
+   * @param script stack advisor script
+   * @param saCommandType {@link StackAdvisorCommandType} to run.
+   * @param actionDirectory directory for the action
+   */
+  public void runScript(String script, StackAdvisorCommandType saCommandType, File actionDirectory)
+      throws StackAdvisorException {
+    LOG.info(String.format("Script=%s, actionDirectory=%s, command=%s", script, actionDirectory,
+        saCommandType));
+
+    String outputFile = actionDirectory + File.separator + "stackadvisor.out";
+    String errorFile = actionDirectory + File.separator + "stackadvisor.err";
+
+    ProcessBuilder builder = prepareShellCommand(script, saCommandType,
+        actionDirectory, outputFile,
+        errorFile);
+
+    try {
+      Process process = builder.start();
+
+      try {
+        LOG.info("Stack-advisor output={}, error={}", outputFile, errorFile);
+
+        int exitCode = process.waitFor();
+        String outMessage;
+        String errMessage = null;
+        try {
+          outMessage = FileUtils.readFileToString(new File(outputFile)).trim();
+          errMessage = FileUtils.readFileToString(new File(errorFile)).trim();
+          LOG.info("Stack advisor output files");
+          LOG.info("    advisor script stdout: {}", outMessage);
+          LOG.info("    advisor script stderr: {}", errMessage);
+        } catch (IOException io) {
+          LOG.error("Error in reading script log files", io);
+        }
+        if (exitCode > 0) {
+          String errorMessage;
+          if (errMessage != null) {
+            // We want to get the last line.
+            int index = errMessage.lastIndexOf("\n");
+            if (index > 0 && index == (errMessage.length() - 1)) {
+              index = errMessage.lastIndexOf("\n", index - 1); // sentence ended with newline
+            }
+            if (index > -1) {
+              errMessage = errMessage.substring(index + 1).trim();
+            }
+            errorMessage = errMessage;
+          } else {
+            errorMessage = "Error occurred during stack advisor execution";
+          }
+          switch (exitCode) {
+            case 1:
+              throw new StackAdvisorRequestException(errorMessage);
+            case 2:
+              throw new StackAdvisorException(errorMessage);
+          }
+        }
+      } finally {
+        process.destroy();
+      }
+    } catch (StackAdvisorException ex) {
+      throw ex;
+    } catch (Exception ioe) {
+      String message = "Error executing stack advisor: ";
+      LOG.error(message, ioe);
+      throw new StackAdvisorException(message + ioe.getMessage());
+    }
+  }
+
+  /**
+   * Gets an instance of a {@link ProcessBuilder} that's ready to execute the
+   * shell command to run the stack advisor script. This will take the
+   * environment variables from the current process.
+   *
+   * @param script
+   * @param saCommandType
+   * @param actionDirectory
+   * @param outputFile
+   * @param errorFile
+   * @return
+   */
+  ProcessBuilder prepareShellCommand(String script,
+      StackAdvisorCommandType saCommandType,
+      File actionDirectory, String outputFile, String errorFile) {
+    String hostsFile = actionDirectory + File.separator + "hosts.json";
+    String servicesFile = actionDirectory + File.separator + "services.json";
+
+    // includes the original command plus the arguments for it
+    List<String> builderParameters = new ArrayList<String>();
+    builderParameters.add("sh");
+    builderParameters.add("-c");
+
+    // for the 3rd argument, build a single parameter since we use -c
+    // ProcessBuilder doesn't support output redirection until JDK 1.7
+    String commandStringParameters[] = new String[] { script,
+        saCommandType.toString(), hostsFile,
+        servicesFile, "1>", outputFile, "2>", errorFile };
+
+    StringBuilder commandString = new StringBuilder();
+    for (String command : commandStringParameters) {
+      commandString.append(command).append(" ");
+    }
+
+    builderParameters.add(commandString.toString());
+
+    LOG.debug("Stack advisor command is {}", builderParameters);
+
+    return new ProcessBuilder(builderParameters);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutRecommnedationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutRecommnedationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutRecommnedationCommand.java
new file mode 100644
index 0000000..b91f912
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutRecommnedationCommand.java
@@ -0,0 +1,64 @@
+/**
+ * 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.stackadvisor.commands;
+
+import java.io.File;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
+import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
+
+/**
+ * {@link StackAdvisorCommand} implementation for component-layout
+ * recommendation.
+ */
+public class GetComponentLayoutRecommnedationCommand extends
+    StackAdvisorCommand<RecommendationResponse> {
+
+  public GetComponentLayoutRecommnedationCommand(File recommendationsDir,
+      String stackAdvisorScript, int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+    super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+  }
+
+  @Override
+  protected StackAdvisorCommandType getCommandType() {
+    return StackAdvisorCommandType.RECOMMEND_COMPONENT_LAYOUT;
+  }
+
+  @Override
+  protected void validate(StackAdvisorRequest request) throws StackAdvisorException {
+    if (request.getHosts() == null || request.getHosts().isEmpty() || request.getServices() == null
+        || request.getServices().isEmpty()) {
+      throw new StackAdvisorException("Hosts and services must not be empty");
+    }
+  }
+
+  @Override
+  protected RecommendationResponse updateResponse(StackAdvisorRequest request, RecommendationResponse response) {
+    return response;
+  }
+
+  @Override
+  protected String getResultFileName() {
+    return "component-layout.json";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutValidationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutValidationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutValidationCommand.java
new file mode 100644
index 0000000..1a1fc98
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutValidationCommand.java
@@ -0,0 +1,63 @@
+/**
+ * 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.stackadvisor.commands;
+
+import java.io.File;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
+import org.apache.ambari.server.api.services.stackadvisor.validations.ValidationResponse;
+
+/**
+ * {@link StackAdvisorCommand} implementation for component-layout validation.
+ */
+public class GetComponentLayoutValidationCommand extends StackAdvisorCommand<ValidationResponse> {
+
+  public GetComponentLayoutValidationCommand(File recommendationsDir, String stackAdvisorScript,
+      int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+    super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+  }
+
+  @Override
+  protected StackAdvisorCommandType getCommandType() {
+    return StackAdvisorCommandType.VALIDATE_COMPONENT_LAYOUT;
+  }
+
+  @Override
+  protected void validate(StackAdvisorRequest request) throws StackAdvisorException {
+    if (request.getHosts() == null || request.getHosts().isEmpty() || request.getServices() == null
+        || request.getServices().isEmpty() || request.getComponentHostsMap() == null
+        || request.getComponentHostsMap().isEmpty()) {
+      throw new StackAdvisorException("Hosts, services and recommendations must not be empty");
+    }
+  }
+
+  @Override
+  protected ValidationResponse updateResponse(StackAdvisorRequest request, ValidationResponse response) {
+    return response;
+  }
+
+  @Override
+  protected String getResultFileName() {
+    return "component-layout-validation.json";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationRecommnedationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationRecommnedationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationRecommnedationCommand.java
new file mode 100644
index 0000000..b20c966
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationRecommnedationCommand.java
@@ -0,0 +1,113 @@
+/**
+ * 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.stackadvisor.commands;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
+import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
+import static org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse.*;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * {@link org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommand} implementation for
+ * configuration recommendation.
+ */
+public class GetConfigurationRecommnedationCommand extends
+    StackAdvisorCommand<RecommendationResponse> {
+
+  public GetConfigurationRecommnedationCommand(File recommendationsDir, String stackAdvisorScript, int requestId,
+                                               StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+    super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+  }
+
+  @Override
+  protected StackAdvisorCommandType getCommandType() {
+    return StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS;
+  }
+
+  @Override
+  protected void validate(StackAdvisorRequest request) throws StackAdvisorException {
+    if (request.getHosts() == null || request.getHosts().isEmpty() || request.getServices() == null
+        || request.getServices().isEmpty()) {
+      throw new StackAdvisorException("Hosts and services must not be empty");
+    }
+  }
+
+  @Override
+  protected RecommendationResponse updateResponse(StackAdvisorRequest request, RecommendationResponse response) {
+    response.getRecommendations().getBlueprint().setHostGroups(processHostGroups(request));
+    response.getRecommendations().getBlueprintClusterBinding().setHostGroups(processHostGroupBindings(request));
+    return response;
+  }
+
+  protected Set<HostGroup> processHostGroups(StackAdvisorRequest request) {
+    Set<HostGroup> resultSet = new HashSet<HostGroup>();
+    for (Map.Entry<String, Set<String>> componentHost : request.getHostComponents().entrySet()) {
+      String hostGroupName = componentHost.getKey();
+      Set<String> components = componentHost.getValue();
+      if (hostGroupName != null && components != null) {
+        HostGroup hostGroup = new HostGroup();
+        Set<Map<String, String>> componentsSet = new HashSet<Map<String, String>>();
+        for (String component : components) {
+          Map<String, String> componentMap = new HashMap<String, String>();
+          componentMap.put("name", component);
+          componentsSet.add(componentMap);
+        }
+        hostGroup.setComponents(componentsSet);
+        hostGroup.setName(hostGroupName);
+        resultSet.add(hostGroup);
+      }
+    }
+    return resultSet;
+  }
+
+  private Set<BindingHostGroup> processHostGroupBindings(StackAdvisorRequest request) {
+    Set<BindingHostGroup> resultSet = new HashSet<BindingHostGroup>();
+    for (Map.Entry<String, Set<String>> hostBinding : request.getHostGroupBindings().entrySet()) {
+      String hostGroupName = hostBinding.getKey();
+      Set<String> hosts = hostBinding.getValue();
+      if (hostGroupName != null && hosts != null) {
+        BindingHostGroup bindingHostGroup = new BindingHostGroup();
+        Set<Map<String, String>> hostsSet = new HashSet<Map<String, String>>();
+        for (String host : hosts) {
+          Map<String, String> hostMap = new HashMap<String, String>();
+          hostMap.put("name", host);
+          hostsSet.add(hostMap);
+        }
+        bindingHostGroup.setHosts(hostsSet);
+        bindingHostGroup.setName(hostGroupName);
+        resultSet.add(bindingHostGroup);
+      }
+    }
+    return resultSet;
+  }
+
+  @Override
+  protected String getResultFileName() {
+    return "configurations.json";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationValidationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationValidationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationValidationCommand.java
new file mode 100644
index 0000000..36fe6cb
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationValidationCommand.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.api.services.stackadvisor.commands;
+
+import java.io.File;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
+import org.apache.ambari.server.api.services.stackadvisor.validations.ValidationResponse;
+
+/**
+ * {@link StackAdvisorCommand} implementation for configuration validation.
+ */
+public class GetConfigurationValidationCommand extends StackAdvisorCommand<ValidationResponse> {
+
+  public GetConfigurationValidationCommand(File recommendationsDir, String stackAdvisorScript,
+      int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+    super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
+  }
+
+  @Override
+  protected StackAdvisorCommandType getCommandType() {
+    return StackAdvisorCommandType.VALIDATE_CONFIGURATIONS;
+  }
+
+  @Override
+  protected void validate(StackAdvisorRequest request) throws StackAdvisorException {
+    if (request.getHosts() == null || request.getHosts().isEmpty() || request.getServices() == null
+        || request.getServices().isEmpty()) {
+      throw new StackAdvisorException("Hosts, services and configurations must not be empty");
+    }
+  }
+
+  @Override
+  protected ValidationResponse updateResponse(StackAdvisorRequest request,
+      ValidationResponse response) {
+    return response;
+  }
+
+  @Override
+  protected String getResultFileName() {
+    return "configurations-validation.json";
+  }
+}


Mime
View raw message