You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by vb...@apache.org on 2017/11/02 15:59:34 UTC

[2/2] ambari git commit: AMBARI-22249. Add service group dependencies.(vbrodetskyi)

AMBARI-22249. Add service group dependencies.(vbrodetskyi)


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

Branch: refs/heads/branch-feature-AMBARI-14714
Commit: 16913b201706c416cea6cf441f4800dd600568f1
Parents: eaeed81
Author: Vitaly Brodetskyi <vb...@hortonworks.com>
Authored: Thu Nov 2 17:59:14 2017 +0200
Committer: Vitaly Brodetskyi <vb...@hortonworks.com>
Committed: Thu Nov 2 17:59:14 2017 +0200

----------------------------------------------------------------------
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 ...erviceGroupDependencyResourceDefinition.java |  41 ++
 .../ServiceGroupResourceDefinition.java         |   1 +
 .../server/api/services/ServiceGroupKey.java    |  89 ++++
 .../api/services/ServiceGroupService.java       | 151 +++++-
 .../server/controller/ControllerModule.java     |   2 +
 .../controller/ResourceProviderFactory.java     |   5 +-
 .../ServiceGroupDependencyRequest.java          |  75 +++
 .../ServiceGroupDependencyResponse.java         | 166 +++++++
 .../AbstractControllerResourceProvider.java     |   2 +
 .../internal/DefaultProviderModule.java         |   2 +
 .../ServiceGroupDependencyResourceProvider.java | 484 +++++++++++++++++++
 .../ambari/server/controller/spi/Resource.java  |   2 +
 .../server/orm/entities/ServiceGroupEntity.java |  29 +-
 .../org/apache/ambari/server/state/Cluster.java |   4 +
 .../ambari/server/state/ServiceGroup.java       |  15 +-
 .../server/state/ServiceGroupFactory.java       |   6 +-
 .../ambari/server/state/ServiceGroupImpl.java   | 121 ++++-
 .../server/state/cluster/ClusterImpl.java       |  62 ++-
 .../ambari/server/topology/AmbariContext.java   |  12 +-
 .../main/resources/Ambari-DDL-Derby-CREATE.sql  |   9 +
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   9 +
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   9 +
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   9 +
 .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql |   9 +
 .../resources/Ambari-DDL-SQLServer-CREATE.sql   |   9 +
 26 files changed, 1317 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/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 2c5edb7..c009cbb 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
@@ -112,6 +112,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new ServiceGroupResourceDefinition();
         break;
 
+      case ServiceGroupDependency:
+        resourceDefinition = new ServiceGroupDependencyResourceDefinition();
+        break;
+
       case Service:
         resourceDefinition = new ServiceResourceDefinition();
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupDependencyResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupDependencyResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupDependencyResourceDefinition.java
new file mode 100644
index 0000000..5c99161
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupDependencyResourceDefinition.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
+ * <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.api.resources;
+
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+public class ServiceGroupDependencyResourceDefinition extends BaseResourceDefinition {
+
+  /**
+   * Constructor.
+   */
+  public ServiceGroupDependencyResourceDefinition() {
+    super(Resource.Type.ServiceGroupDependency);
+  }
+
+  @Override
+  public String getPluralName() {
+    return "dependencies";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "dependency";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupResourceDefinition.java
index 13bdd7b..1d123d8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ServiceGroupResourceDefinition.java
@@ -49,6 +49,7 @@ public class ServiceGroupResourceDefinition extends BaseResourceDefinition {
   public Set<SubResourceDefinition> getSubResourceDefinitions() {
     Set<SubResourceDefinition> subs = new HashSet<SubResourceDefinition>();
     subs.add(new SubResourceDefinition(Resource.Type.Service));
+    subs.add(new SubResourceDefinition(Resource.Type.ServiceGroupDependency));
     return subs;
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupKey.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupKey.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupKey.java
new file mode 100644
index 0000000..9389f0c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupKey.java
@@ -0,0 +1,89 @@
+/**
+ * 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.api.services;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ServiceGroupKey {
+
+  private Long clusterId;
+  private Long serviceGroupId;
+  private String clusterName;
+  private String serviceGroupName;
+
+  @JsonProperty("cluster_name")
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+  @JsonProperty("service_group_name")
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  public Long getClusterId() {
+    return clusterId;
+  }
+
+  public void setClusterId(Long clusterId) {
+    this.clusterId = clusterId;
+  }
+
+  public Long getServiceGroupId() {
+    return serviceGroupId;
+  }
+
+  public void setServiceGroupId(Long serviceGroupId) {
+    this.serviceGroupId = serviceGroupId;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (!(o instanceof ServiceGroupKey)) return false;
+
+    ServiceGroupKey that = (ServiceGroupKey) o;
+
+    if (clusterId != null ? !clusterId.equals(that.clusterId) : that.clusterId != null) return false;
+    if (clusterName != null ? !clusterName.equals(that.clusterName) : that.clusterName != null) return false;
+    if (serviceGroupId != null ? !serviceGroupId.equals(that.serviceGroupId) : that.serviceGroupId != null)
+      return false;
+    if (serviceGroupName != null ? !serviceGroupName.equals(that.serviceGroupName) : that.serviceGroupName != null)
+      return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = clusterId != null ? clusterId.hashCode() : 0;
+    result = 31 * result + (serviceGroupId != null ? serviceGroupId.hashCode() : 0);
+    result = 31 * result + (clusterName != null ? clusterName.hashCode() : 0);
+    result = 31 * result + (serviceGroupName != null ? serviceGroupName.hashCode() : 0);
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupService.java
index 1e2eaf4..0638a06 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceGroupService.java
@@ -35,6 +35,7 @@ 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.ServiceGroupDependencyResponse;
 import org.apache.ambari.server.controller.ServiceGroupResponse;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.http.HttpStatus;
@@ -47,13 +48,14 @@ import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
 
-
 /**
  * Service responsible for servicegroups resource requests.
  */
 @Api(value = "Service Groups", description = "Endpoint for servicegroup specific operations")
 public class ServiceGroupService extends BaseService {
   private static final String SERVICE_GROUP_REQUEST_TYPE = "org.apache.ambari.server.controller.ServiceGroupRequestSwagger";
+  private static final String SERVICE_GROUP_DEPENDENCY_REQUEST_TYPE = "org.apache.ambari.server.controller.ServiceGroupDependencyRequestSwagger";
+
 
   /**
    * Parent cluster Name.
@@ -279,6 +281,143 @@ public class ServiceGroupService extends BaseService {
   }
 
   /**
+   * Handles URL: /clusters/{clusterName}/servicegroups/{serviceGroupName}/dependencies
+   * Get all servicegroupdependencies for a cluster.
+   *
+   * @param headers http headers
+   * @param ui      uri info
+   * @return service group dependencies collection resource representation
+   */
+  @GET
+  @Path("{serviceGroupName}/dependencies")
+  @Produces(MediaType.TEXT_PLAIN)
+  @ApiOperation(value = "Get all servicegroupdependencies",
+          nickname = "ServiceGroupService#getServiceGroupDependencies",
+          notes = "Returns all servicegroupdependencies.",
+          response = ServiceGroupDependencyResponse.ServiceGroupDependencyResponseSwagger.class,
+          responseContainer = RESPONSE_CONTAINER_LIST)
+  @ApiImplicitParams({
+          @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION,
+                  defaultValue = "ServiceGroupInfo/service_group_name, ServiceGroupInfo/cluster_name",
+                  dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY),
+          @ApiImplicitParam(name = QUERY_SORT, value = QUERY_SORT_DESCRIPTION,
+                  defaultValue = "ServiceGroupInfo/service_group_name.asc, ServiceGroupInfo/cluster_name.asc",
+                  dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY),
+          @ApiImplicitParam(name = QUERY_PAGE_SIZE, value = QUERY_PAGE_SIZE_DESCRIPTION, defaultValue = DEFAULT_PAGE_SIZE, dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
+          @ApiImplicitParam(name = QUERY_FROM, value = QUERY_FROM_DESCRIPTION, defaultValue = DEFAULT_FROM, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY),
+          @ApiImplicitParam(name = QUERY_TO, value = QUERY_TO_DESCRIPTION, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY)
+  })
+  @ApiResponses(value = {
+          @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+          @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR)
+  })
+  public Response getServiceGroupDependencies(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                  @PathParam("serviceGroupName") String serviceGroupName) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET,
+            createServiceGroupDependencyResource(m_clusterName, serviceGroupName, null));
+  }
+
+  /**
+   * Handles URL: /clusters/{clusterName}/servicegroups/{serviceGroupName}/dependencies/{serviceGroupDependency}
+   * Get a specific servicegroupdependency.
+   *
+   * @param headers                 http headers
+   * @param ui                      uri info
+   * @param serviceGroupName        service group name
+   * @param serviceGroupDependency  service group dependency name
+   * @return servicegroupdependency    resource representation
+   */
+  @GET
+  @Path("{serviceGroupName}/dependencies/{serviceGroupDependency}")
+  @Produces(MediaType.TEXT_PLAIN)
+  @ApiOperation(value = "Get the details of a servicegroupdependency",
+          nickname = "ServiceGroupService#getServiceGroupDependency",
+          notes = "Returns the details of a servicegroupdependency",
+          response = ServiceGroupResponse.ServiceGroupResponseSwagger.class,
+          responseContainer = RESPONSE_CONTAINER_LIST)
+  @ApiImplicitParams({
+          @ApiImplicitParam(name = QUERY_FIELDS, value = QUERY_FILTER_DESCRIPTION, defaultValue = "ServiceGroupInfo/*",
+                  dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY)
+  })
+  @ApiResponses(value = {
+          @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+          @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+          @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR)
+  })
+  public Response getServiceGroupDependency(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                              @PathParam("serviceGroupName") String serviceGroupName,
+                                              @PathParam("serviceGroupDependency") String serviceGroupDependency) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET,
+            createServiceGroupDependencyResource(m_clusterName, serviceGroupName, serviceGroupDependency));
+  }
+
+  /**
+   * Handles: POST /clusters/{clusterName}/servicegroups/{serviceGroupName}/dependencies
+   * Create multiple servicegroupdependencies.
+   *
+   * @param body        http body
+   * @param headers     http headers
+   * @param ui          uri info
+   * @return information regarding the created servicegroupdependencies
+   */
+  @POST
+  @Path("{serviceGroupName}/dependencies")
+  @Produces(MediaType.TEXT_PLAIN)
+  @ApiOperation(value = "Creates a servicegroupdependency",
+          nickname = "ServiceGroupService#addServiceGroupDependency"
+  )
+  @ApiImplicitParams({
+          @ApiImplicitParam(dataType = SERVICE_GROUP_DEPENDENCY_REQUEST_TYPE, paramType = PARAM_TYPE_BODY)
+  })
+  @ApiResponses({
+          @ApiResponse(code = HttpStatus.SC_CREATED, message = MSG_SUCCESSFUL_OPERATION),
+          @ApiResponse(code = HttpStatus.SC_ACCEPTED, message = MSG_REQUEST_ACCEPTED),
+          @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = MSG_INVALID_ARGUMENTS),
+          @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+          @ApiResponse(code = HttpStatus.SC_CONFLICT, message = MSG_RESOURCE_ALREADY_EXISTS),
+          @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+          @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+          @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
+  })
+  public Response addServiceGroupDependency(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                              @PathParam("serviceGroupName") String serviceGroupName) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST,
+            createServiceGroupDependencyResource(m_clusterName, serviceGroupName, null));
+  }
+
+  /**
+   * Handles: DELETE /clusters/{clusterName}/servicegroups/{serviceGroupName}/dependencies/{serviceGroupDependency}
+   * Delete a specific servicegroupdependency.
+
+   * @param headers                 http headers
+   * @param ui                      uri info
+   * @param serviceGroupName        service group name
+   * @param serviceGroupDependency  service group dependency name
+   * @return information regarding the deleted servicegroupdependency
+   */
+  @DELETE
+  @Path("{serviceGroupName}/dependencies/{serviceGroupDependency}")
+  @Produces(MediaType.TEXT_PLAIN)
+  @ApiOperation(value = "Deletes a servicegroupdependency",
+          nickname = "ServiceGroupService#deleteServiceGroupDependency"
+  )
+  @ApiResponses({
+          @ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
+          @ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
+          @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = MSG_NOT_AUTHENTICATED),
+          @ApiResponse(code = HttpStatus.SC_FORBIDDEN, message = MSG_PERMISSION_DENIED),
+          @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR),
+  })
+  public Response deleteServiceGroupDependency(@Context HttpHeaders headers, @Context UriInfo ui,
+                                     @PathParam("serviceGroupName") String serviceGroupName,
+                                     @PathParam("serviceGroupDependency") String serviceGroupDependency) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createServiceGroupDependencyResource(m_clusterName, serviceGroupName, serviceGroupDependency));
+  }
+  /**
    * Create a service resource instance.
    *
    * @param clusterName  cluster Name
@@ -294,4 +433,14 @@ public class ServiceGroupService extends BaseService {
 
     return createResource(Resource.Type.ServiceGroup, mapIds);
   }
+
+  ResourceInstance createServiceGroupDependencyResource(String clusterName, String serviceGroupName, String serviceGroupDependency) {
+    Map<Resource.Type, String> mapIds = new HashMap<>();
+    mapIds.put(Resource.Type.Cluster, clusterName);
+    mapIds.put(Resource.Type.ServiceGroup, serviceGroupName);
+    mapIds.put(Resource.Type.ServiceGroupDependency, serviceGroupDependency);
+
+
+    return createResource(Resource.Type.ServiceGroupDependency, mapIds);
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index ee805b1..cb19099 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -73,6 +73,7 @@ import org.apache.ambari.server.controller.internal.HostResourceProvider;
 import org.apache.ambari.server.controller.internal.KerberosDescriptorResourceProvider;
 import org.apache.ambari.server.controller.internal.MemberResourceProvider;
 import org.apache.ambari.server.controller.internal.RepositoryVersionResourceProvider;
+import org.apache.ambari.server.controller.internal.ServiceGroupDependencyResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceGroupResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
 import org.apache.ambari.server.controller.internal.UpgradeResourceProvider;
@@ -477,6 +478,7 @@ public class ControllerModule extends AbstractModule {
         .implement(ResourceProvider.class, Names.named("hostComponent"), HostComponentResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("service"), ServiceResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("servicegroup"), ServiceGroupResourceProvider.class)
+        .implement(ResourceProvider.class, Names.named("servicegroupdependency"), ServiceGroupDependencyResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("component"), ComponentResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("member"), MemberResourceProvider.class)
         .implement(ResourceProvider.class, Names.named("repositoryVersion"), RepositoryVersionResourceProvider.class)

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
index b5a6547..20f4864 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java
@@ -48,6 +48,9 @@ public interface ResourceProviderFactory {
   @Named("servicegroup")
   ResourceProvider getServiceGroupResourceProvider(AmbariManagementController managementController);
 
+  @Named("servicegroupdependency")
+  ResourceProvider getServiceGroupDependencyResourceProvider(AmbariManagementController managementController);
+
   @Named("component")
   ResourceProvider getComponentResourceProvider(AmbariManagementController managementController);
 
@@ -83,4 +86,4 @@ public interface ResourceProviderFactory {
   @Named("viewInstance")
   ViewInstanceResourceProvider getViewInstanceResourceProvider();
 
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupDependencyRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupDependencyRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupDependencyRequest.java
new file mode 100644
index 0000000..e9cf937
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupDependencyRequest.java
@@ -0,0 +1,75 @@
+/**
+ * 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;
+
+
+public class ServiceGroupDependencyRequest {
+
+  private String clusterName; // REF
+  private String serviceGroupName; // GET/CREATE/UPDATE/DELETE
+  private String dependencyServiceGroupName;
+
+  public ServiceGroupDependencyRequest(String clusterName, String serviceGroupName, String dependencyServiceGroupName) {
+    this.clusterName = clusterName;
+    this.serviceGroupName = serviceGroupName;
+    this.dependencyServiceGroupName = dependencyServiceGroupName;
+  }
+
+  /**
+   * @return the clusterName
+   */
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  /**
+   * @param clusterName the clusterName to set
+   */
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+  /**
+   * @return the serviceGroupName
+   */
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  /**
+   * @param serviceGroupName the service group name to set
+   */
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  public String getDependencyServiceGroupName() {
+    return dependencyServiceGroupName;
+  }
+
+  public void setDependencyServiceGroupName(String dependencyServiceGroupName) {
+    this.dependencyServiceGroupName = dependencyServiceGroupName;
+  }
+
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("clusterName=" + clusterName
+            + ", serviceGroupName=" + serviceGroupName);
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupDependencyResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupDependencyResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupDependencyResponse.java
new file mode 100644
index 0000000..1a4b4ed
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceGroupDependencyResponse.java
@@ -0,0 +1,166 @@
+/**
+ * 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;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class ServiceGroupDependencyResponse {
+
+  private Long clusterId;
+  private Long serviceGroupId;
+  private Long dependencyClusterId;
+  private Long dependencyGroupId;
+  private String clusterName;
+  private String serviceGroupName;
+  private String dependencyGroupName;
+  private String dependencyClusterName;
+
+  public ServiceGroupDependencyResponse(Long clusterId, String clusterName, Long serviceGroupId, String serviceGroupName,
+                                        Long dependencyClusterId, String dependencyClusterName,
+                                        Long dependencyGroupId, String dependencyGroupName) {
+    this.clusterId = clusterId;
+    this.serviceGroupId = serviceGroupId;
+    this.clusterName = clusterName;
+    this.serviceGroupName = serviceGroupName;
+    this.dependencyGroupId = dependencyGroupId;
+    this.dependencyGroupName = dependencyGroupName;
+    this.dependencyClusterId = dependencyClusterId;
+    this.dependencyClusterName = dependencyClusterName;
+  }
+
+  /**
+   * @return the clusterId
+   */
+  public Long getClusterId() {
+    return clusterId;
+  }
+
+  /**
+   * @param clusterId the clusterId to set
+   */
+  public void setClusterId(Long clusterId) {
+    this.clusterId = clusterId;
+  }
+
+  /**
+   * @return the clusterName
+   */
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  /**
+   * @param clusterName the clusterName to set
+   */
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+  /**
+   * @return the service group Id
+   */
+  public Long getServiceGroupId() {
+    return serviceGroupId;
+  }
+
+  /**
+   * @param  serviceGroupId the service group Id
+   */
+  public void setServiceGroupId(Long serviceGroupId) {
+    this.serviceGroupId = serviceGroupId;
+  }
+
+  /**
+   * @return the service group name
+   */
+  public String getServiceGroupName() {
+    return serviceGroupName;
+  }
+
+  /**
+   * @param  serviceGroupName the service group name
+   */
+  public void setServiceGroupName(String serviceGroupName) {
+    this.serviceGroupName = serviceGroupName;
+  }
+
+  public Long getDependencyGroupId() {
+    return dependencyGroupId;
+  }
+
+  public void setDependencyGroupId(Long dependencyGroupId) {
+    this.dependencyGroupId = dependencyGroupId;
+  }
+
+  public String getDependencyGroupName() {
+    return dependencyGroupName;
+  }
+
+  public void setDependencyGroupName(String dependencyGroupName) {
+    this.dependencyGroupName = dependencyGroupName;
+  }
+
+  public Long getDependencyClusterId() {
+    return dependencyClusterId;
+  }
+
+  public void setDependencyClusterId(Long dependencyClusterId) {
+    this.dependencyClusterId = dependencyClusterId;
+  }
+
+  public String getDependencyClusterName() {
+    return dependencyClusterName;
+  }
+
+  public void setDependencyClusterName(String dependencyClusterName) {
+    this.dependencyClusterName = dependencyClusterName;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ServiceGroupResponse that = (ServiceGroupResponse) o;
+
+    if (clusterId != null ?
+            !clusterId.equals(this.clusterId) : this.clusterId != null) {
+      return false;
+    }
+    if (clusterName != null ?
+            !clusterName.equals(this.clusterName) : this.clusterName != null) {
+      return false;
+    }
+    if (serviceGroupName != null ?
+            !serviceGroupName.equals(this.serviceGroupName) : this.serviceGroupName != null) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * Interface to help correct Swagger documentation generation
+   */
+  public interface ServiceGroupDependencyResponseSwagger extends ApiModel {
+    @ApiModelProperty(name = "ServiceGroupDependencyInfo")
+    ServiceResponse getServiceGroupDependencyResponse();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/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 60a845d..123f2fe 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
@@ -156,6 +156,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori
         return resourceProviderFactory.getServiceResourceProvider(managementController);
       case ServiceGroup:
         return resourceProviderFactory.getServiceGroupResourceProvider(managementController);
+      case ServiceGroupDependency:
+        return resourceProviderFactory.getServiceGroupDependencyResourceProvider(managementController);
       case Component:
         return resourceProviderFactory.getComponentResourceProvider(managementController);
       case Host:

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/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 c3293af..c219d23 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
@@ -88,6 +88,8 @@ public class DefaultProviderModule extends AbstractProviderModule {
         return new AlertResourceProvider(managementController);
       case ServiceGroup:
         return new ServiceGroupResourceProvider(managementController);
+      case ServiceGroupDependency:
+        return new ServiceGroupDependencyResourceProvider(managementController);
       case Registry:
         return new RegistryResourceProvider(managementController);
       case RegistryRecommendation:

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupDependencyResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupDependencyResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupDependencyResourceProvider.java
new file mode 100644
index 0000000..78610d2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceGroupDependencyResourceProvider.java
@@ -0,0 +1,484 @@
+/**
+ * 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.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ClusterNotFoundException;
+import org.apache.ambari.server.ObjectNotFoundException;
+import org.apache.ambari.server.ParentObjectNotFoundException;
+import org.apache.ambari.server.ServiceGroupNotFoundException;
+import org.apache.ambari.server.api.services.ServiceGroupKey;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.RequestStatusResponse;
+import org.apache.ambari.server.controller.ServiceGroupDependencyRequest;
+import org.apache.ambari.server.controller.ServiceGroupDependencyResponse;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+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.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.security.authorization.AuthorizationException;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.ResourceType;
+import org.apache.ambari.server.security.authorization.RoleAuthorization;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.ServiceGroup;
+import org.apache.ambari.server.utils.StageUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.Validate;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+
+public class ServiceGroupDependencyResourceProvider extends AbstractControllerResourceProvider {
+
+
+  // ----- Property ID constants ---------------------------------------------
+
+  public static final String RESPONSE_KEY = "ServiceGroupDependencyInfo";
+  public static final String ALL_PROPERTIES = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "*";
+  public static final String SERVICE_GROUP_DEPENDENCY_CLUSTER_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_id";
+  public static final String SERVICE_GROUP_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_name";
+  public static final String SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "service_group_id";
+  public static final String SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "service_group_name";
+  public static final String SERVICE_GROUP_DEPENDENCY_DEPENDENCY_CLUSTER_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "dependency_cluster_id";
+  public static final String SERVICE_GROUP_DEPENDENCY_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "dependency_cluster_name";
+  public static final String SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "dependency_service_group_id";
+  public static final String SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "dependency_service_group_name";
+
+  protected ObjectMapper mapper = new ObjectMapper();;
+
+  private static Set<String> pkPropertyIds =
+    new HashSet<String>(Arrays.asList(new String[]{
+      SERVICE_GROUP_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID,
+      SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID,
+      SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID}));
+
+  private static Gson gson = StageUtils.getGson();
+
+  /**
+   * The property ids for an service group resource.
+   */
+  private static final Set<String> PROPERTY_IDS = new HashSet<>();
+
+  /**
+   * The key property ids for an service group resource.
+   */
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<>();
+
+  static {
+    // properties
+    PROPERTY_IDS.add(SERVICE_GROUP_DEPENDENCY_CLUSTER_ID_PROPERTY_ID);
+    PROPERTY_IDS.add(SERVICE_GROUP_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID);
+    PROPERTY_IDS.add(SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_ID_PROPERTY_ID);
+    PROPERTY_IDS.add(SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID);
+    PROPERTY_IDS.add(SERVICE_GROUP_DEPENDENCY_DEPENDENCY_CLUSTER_ID_PROPERTY_ID);
+    PROPERTY_IDS.add(SERVICE_GROUP_DEPENDENCY_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID);
+    PROPERTY_IDS.add(SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_ID_PROPERTY_ID);
+    PROPERTY_IDS.add(SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID);
+
+    // keys
+    KEY_PROPERTY_IDS.put(Resource.Type.Cluster, SERVICE_GROUP_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID);
+    KEY_PROPERTY_IDS.put(Resource.Type.ServiceGroup, SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID);
+    KEY_PROPERTY_IDS.put(Resource.Type.ServiceGroupDependency, SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID);
+  }
+
+  private Clusters clusters;
+
+  /**
+   * kerberos helper
+   */
+  @Inject
+  private KerberosHelper kerberosHelper;
+
+  // ----- Constructors ----------------------------------------------------
+
+  /**
+   * Create a  new resource provider for the given management controller.
+   *
+   * @param managementController the management controller
+   */
+  @AssistedInject
+  public ServiceGroupDependencyResourceProvider(@Assisted AmbariManagementController managementController) {
+    super(Resource.Type.ServiceGroupDependency, PROPERTY_IDS, KEY_PROPERTY_IDS, managementController);
+  }
+
+  // ----- ResourceProvider ------------------------------------------------
+
+  @Override
+  protected RequestStatus createResourcesAuthorized(Request request)
+    throws SystemException,
+    UnsupportedPropertyException,
+    ResourceAlreadyExistsException,
+    NoSuchParentResourceException {
+
+    final Set<ServiceGroupDependencyRequest> requests = new HashSet<>();
+    for (Map<String, Object> propertyMap : request.getProperties()) {
+      requests.add(getRequest(propertyMap));
+    }
+    Set<ServiceGroupDependencyResponse> createServiceGroups = null;
+    createServiceGroups = createResources(new Command<Set<ServiceGroupDependencyResponse>>() {
+      @Override
+      public Set<ServiceGroupDependencyResponse> invoke() throws AmbariException, AuthorizationException {
+        return createServiceGroupDependencies(requests);
+      }
+    });
+    Set<Resource> associatedResources = new HashSet<>();
+    if (createServiceGroups != null) {
+      Iterator<ServiceGroupDependencyResponse> itr = createServiceGroups.iterator();
+      while (itr.hasNext()) {
+        ServiceGroupDependencyResponse response = itr.next();
+        notifyCreate(Resource.Type.ServiceGroupDependency, request);
+        Resource resource = new ResourceImpl(Resource.Type.ServiceGroupDependency);
+        resource.setProperty(SERVICE_GROUP_DEPENDENCY_CLUSTER_ID_PROPERTY_ID, response.getClusterId());
+        resource.setProperty(SERVICE_GROUP_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID, response.getClusterName());
+        resource.setProperty(SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_ID_PROPERTY_ID, response.getServiceGroupId());
+        resource.setProperty(SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID, response.getServiceGroupName());
+        resource.setProperty(SERVICE_GROUP_DEPENDENCY_DEPENDENCY_CLUSTER_ID_PROPERTY_ID, response.getDependencyClusterId());
+        resource.setProperty(SERVICE_GROUP_DEPENDENCY_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID, response.getDependencyClusterName());
+        resource.setProperty(SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_ID_PROPERTY_ID, response.getDependencyGroupId());
+        resource.setProperty(SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID, response.getDependencyGroupName());
+
+        associatedResources.add(resource);
+      }
+      return getRequestStatus(null, associatedResources);
+    }
+
+    return getRequestStatus(null);
+  }
+
+  @Override
+  protected Set<Resource> getResourcesAuthorized(Request request, Predicate predicate) throws
+    SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ServiceGroupDependencyRequest> requests = new HashSet<>();
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      requests.add(getRequest(propertyMap));
+    }
+
+    Set<ServiceGroupDependencyResponse> responses = getResources(new Command<Set<ServiceGroupDependencyResponse>>() {
+      @Override
+      public Set<ServiceGroupDependencyResponse> invoke() throws AmbariException {
+        return getServiceGroupDependencies(requests);
+      }
+    });
+
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+    Set<Resource> resources = new HashSet<Resource>();
+
+    for (ServiceGroupDependencyResponse response : responses) {
+      Resource resource = new ResourceImpl(Resource.Type.ServiceGroupDependency);
+      setResourceProperty(resource, SERVICE_GROUP_DEPENDENCY_CLUSTER_ID_PROPERTY_ID,
+              response.getClusterId(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID,
+              response.getClusterName(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_ID_PROPERTY_ID,
+              response.getServiceGroupId(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID,
+              response.getServiceGroupName(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_DEPENDENCY_DEPENDENCY_CLUSTER_ID_PROPERTY_ID,
+              response.getDependencyClusterId(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_DEPENDENCY_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID,
+              response.getDependencyClusterName(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_ID_PROPERTY_ID,
+              response.getDependencyGroupId(), requestedIds);
+      setResourceProperty(resource, SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID,
+              response.getDependencyGroupName(), requestedIds);
+      resources.add(resource);
+    }
+    return resources;
+  }
+
+  @Override
+  protected RequestStatus updateResourcesAuthorized(final Request request, Predicate predicate)
+    throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    // TODO : Add functionality for updating SG : RENAME, START ALL, STOP ALL services.
+    RequestStatusResponse response = null;
+    return getRequestStatus(response);
+  }
+
+  @Override
+  protected RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate)
+    throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ServiceGroupDependencyRequest> requests = new HashSet<>();
+    DeleteStatusMetaData deleteStatusMetaData = null;
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      requests.add(getRequest(propertyMap));
+    }
+    deleteStatusMetaData = modifyResources(new Command<DeleteStatusMetaData>() {
+      @Override
+      public DeleteStatusMetaData invoke() throws AmbariException, AuthorizationException {
+        deleteServiceGroupDependencies(requests);
+        return new DeleteStatusMetaData();
+      }
+    });
+
+    notifyDelete(Resource.Type.ServiceGroupDependency, predicate);
+    for(ServiceGroupDependencyRequest svgReq : requests) {
+      deleteStatusMetaData.addDeletedKey("cluster_name: " + svgReq.getClusterName() + ", " + " service_group_name: " + svgReq.getServiceGroupName()
+                                        + "dependency_service_group_name: " + svgReq.getDependencyServiceGroupName());
+    }
+    return getRequestStatus(null, null, deleteStatusMetaData);
+  }
+
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    propertyIds = super.checkPropertyIds(propertyIds);
+
+    if (propertyIds.isEmpty()) {
+      return propertyIds;
+    }
+    Set<String> unsupportedProperties = new HashSet<String>();
+    return unsupportedProperties;
+  }
+
+
+  // ----- AbstractResourceProvider ----------------------------------------
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  // ----- utility methods -------------------------------------------------
+
+  /**
+   * Get a service group request object from a map of property values.
+   *
+   * @param properties the predicate
+   * @return the service request object
+   */
+  private ServiceGroupDependencyRequest getRequest(Map<String, Object> properties) {
+    String clusterName = (String) properties.get(SERVICE_GROUP_DEPENDENCY_CLUSTER_NAME_PROPERTY_ID);
+    String serviceGroupName = (String) properties.get(SERVICE_GROUP_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID);
+    String dependencyServiceGroupName = (String) properties.get(SERVICE_GROUP_DEPENDENCY_DEPENDENCY_SERVICE_GROUP_NAME_PROPERTY_ID);
+    ServiceGroupDependencyRequest svcRequest = new ServiceGroupDependencyRequest(clusterName, serviceGroupName, dependencyServiceGroupName);
+    return svcRequest;
+  }
+
+  protected Set<ServiceGroupKey> getServiceGroupDependenciesSet(Set<Map<String, String>> serviceGroupDependencies) {
+    Set<ServiceGroupKey> serviceGroupKeys = new HashSet<>();
+    if (serviceGroupDependencies != null) {
+      for (Map<String, String> dependencyProperties : serviceGroupDependencies) {
+        ServiceGroupKey serviceGroupKey = mapper.convertValue(dependencyProperties, ServiceGroupKey.class);
+        serviceGroupKeys.add(serviceGroupKey);
+      }
+    }
+    return serviceGroupKeys;
+  }
+
+  // Create services from the given request.
+  public synchronized Set<ServiceGroupDependencyResponse> createServiceGroupDependencies(Set<ServiceGroupDependencyRequest> requests)
+    throws AmbariException, AuthorizationException {
+
+    if (requests.isEmpty()) {
+      LOG.warn("Received an empty requests set");
+      return null;
+    }
+    AmbariManagementController controller = getManagementController();
+    Clusters clusters = controller.getClusters();
+
+    // do all validation checks
+    validateCreateRequests(requests, clusters);
+
+    Set<ServiceGroupDependencyResponse> createdServiceGroupDependencies = new HashSet<>();
+    for (ServiceGroupDependencyRequest request : requests) {
+      Cluster cluster = clusters.getCluster(request.getClusterName());
+
+      // Already checked that service group does not exist
+      ServiceGroup sg = cluster.addServiceGroupDependency(request.getServiceGroupName(), request.getDependencyServiceGroupName());
+      createdServiceGroupDependencies.addAll(sg.getServiceGroupDependencyResponses());
+    }
+    return createdServiceGroupDependencies;
+  }
+
+  // Get services from the given set of requests.
+  protected Set<ServiceGroupDependencyResponse> getServiceGroupDependencies(Set<ServiceGroupDependencyRequest> requests)
+    throws AmbariException {
+    Set<ServiceGroupDependencyResponse> response = new HashSet<ServiceGroupDependencyResponse>();
+    for (ServiceGroupDependencyRequest request : requests) {
+      try {
+        response.addAll(getServiceGroupDependencies(request));
+      } catch (ServiceGroupNotFoundException e) {
+        if (requests.size() == 1) {
+          // only throw exception if 1 request.
+          // there will be > 1 request in case of OR predicate
+          throw e;
+        }
+      }
+    }
+    return response;
+  }
+
+  // Get services from the given request.
+  private Set<ServiceGroupDependencyResponse> getServiceGroupDependencies(ServiceGroupDependencyRequest request)
+    throws AmbariException {
+    if (request.getClusterName() == null) {
+      throw new AmbariException("Invalid arguments, cluster id"
+        + " cannot be null");
+    }
+    AmbariManagementController controller = getManagementController();
+    Clusters clusters = controller.getClusters();
+    String clusterName = request.getClusterName();
+
+    final Cluster cluster;
+    try {
+      cluster = clusters.getCluster(clusterName);
+    } catch (ObjectNotFoundException e) {
+      throw new ParentObjectNotFoundException("Parent Cluster resource doesn't exist", e);
+    }
+
+    Set<ServiceGroupDependencyResponse> responses = new HashSet<>();
+    if (request.getServiceGroupName() != null) {
+      ServiceGroup sg = cluster.getServiceGroup(request.getServiceGroupName());
+      responses.addAll(sg.getServiceGroupDependencyResponses());
+      return responses;
+    }
+    return responses;
+  }
+
+
+  // Delete services based on the given set of requests
+  protected void deleteServiceGroupDependencies(Set<ServiceGroupDependencyRequest> request)
+    throws AmbariException, AuthorizationException {
+
+    Clusters clusters = getManagementController().getClusters();
+
+    Set<ServiceGroupDependencyRequest> removable = new HashSet<>();
+
+    for (ServiceGroupDependencyRequest serviceGroupDependencyRequest : request) {
+      if (null == serviceGroupDependencyRequest.getClusterName()
+        || StringUtils.isEmpty(serviceGroupDependencyRequest.getServiceGroupName())) {
+        throw new AmbariException("invalid arguments");
+      } else {
+
+        if (!AuthorizationHelper.isAuthorized(
+          ResourceType.CLUSTER, getClusterResourceId(serviceGroupDependencyRequest.getClusterName()),
+          RoleAuthorization.SERVICE_ADD_DELETE_SERVICES)) {
+          throw new AuthorizationException("The user is not authorized to delete service groups");
+        }
+
+        Cluster cluster = clusters.getCluster(serviceGroupDependencyRequest.getClusterName());
+        ServiceGroup serviceGroup = cluster.getServiceGroup(serviceGroupDependencyRequest.getServiceGroupName());
+        Set<ServiceGroupKey> serviceGroupKeys = serviceGroup.getServiceGroupDependencies();
+        if (serviceGroupKeys == null || serviceGroupKeys.isEmpty()) {
+          throw new AmbariException("Servcie group name " + serviceGroupDependencyRequest.getServiceGroupName() + " has no" +
+                  "dependencies, so nothing to remove.");
+        } else {
+          boolean dependencyAvailable = false;
+          for (ServiceGroupKey serviceGroupKey : serviceGroupKeys) {
+            if (serviceGroupKey.getServiceGroupName().equals(serviceGroupDependencyRequest.getDependencyServiceGroupName())) {
+              dependencyAvailable = true;
+            }
+          }
+          if (!dependencyAvailable) {
+            throw new AmbariException("Servcie group name " + serviceGroupDependencyRequest.getServiceGroupName() + " has no" +
+                    "dependency " + serviceGroupDependencyRequest.getDependencyServiceGroupName() + ", so nothing to remove.");
+          }
+
+          serviceGroup.getCluster().deleteServiceGroupDependency(serviceGroupDependencyRequest.getServiceGroupName(),
+                  serviceGroupDependencyRequest.getDependencyServiceGroupName());
+        }
+      }
+    }
+  }
+
+
+  private void validateCreateRequests(Set<ServiceGroupDependencyRequest> requests, Clusters clusters)
+    throws AuthorizationException, AmbariException {
+
+    Map<String, Set<String>> serviceGroupNames = new HashMap<>();
+    Set<String> duplicates = new HashSet<>();
+    for (ServiceGroupDependencyRequest request : requests) {
+      final String clusterName = request.getClusterName();
+      final String serviceGroupName = request.getServiceGroupName();
+      final String dependencyServiceGroupName = request.getDependencyServiceGroupName();
+
+      Validate.notNull(clusterName, "Cluster name should be provided when creating a service group");
+
+      // validating service group dependencies
+      if (StringUtils.isEmpty(dependencyServiceGroupName)) {
+        throw new AmbariException("Service group name is empty or null!");
+      } else {
+        Cluster cluster = clusters.getCluster(clusterName);
+        //throws service group not found exception
+        ServiceGroup serviceGroup = cluster.getServiceGroup(dependencyServiceGroupName);
+
+      }
+
+      Validate.notEmpty(serviceGroupName, "Service group name should be provided when adding a service group dependency");
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Received a createServiceGroupDependency request" +
+          ", clusterName=" + clusterName + ", serviceGroupName=" + serviceGroupName + ", request=" + request);
+      }
+
+      if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER,
+              getClusterResourceId(clusterName), RoleAuthorization.SERVICE_ADD_DELETE_SERVICES)) {
+        throw new AuthorizationException("The user is not authorized to create service groups");
+      }
+
+
+      Cluster cluster;
+      try {
+        cluster = clusters.getCluster(clusterName);
+      } catch (ClusterNotFoundException e) {
+        throw new ParentObjectNotFoundException("Attempted to add a service group to a cluster which doesn't exist", e);
+      }
+
+      // throws service group not found exception if theere is no such SG
+      ServiceGroup sg = cluster.getServiceGroup(serviceGroupName);
+      Set<ServiceGroupKey> dependencies = sg.getServiceGroupDependencies();
+      if (dependencies != null) {
+        for (ServiceGroupKey serviceGroupKey : dependencies) {
+          if (serviceGroupKey.getServiceGroupName().equals(dependencyServiceGroupName)) {
+            throw new AmbariException("Service group " + serviceGroupName + " already have dependency for service group "
+                    + dependencyServiceGroupName);
+          }
+        }
+      }
+
+    }
+  }
+}
+
+
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/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 ebf0e9f..3699cd0 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
@@ -78,6 +78,7 @@ public interface Resource {
     RootClusterSetting,
     Service,
     ServiceGroup,
+    ServiceGroupDependency,
     Setting,
     Host,
     Component,
@@ -208,6 +209,7 @@ public interface Resource {
     public static final Type Cluster = InternalType.Cluster.getType();
     public static final Type RootClusterSetting = InternalType.RootClusterSetting.getType();
     public static final Type ServiceGroup = InternalType.ServiceGroup.getType();
+    public static final Type ServiceGroupDependency = InternalType.ServiceGroupDependency.getType();
     public static final Type Service = InternalType.Service.getType();
     public static final Type Setting = InternalType.Setting.getType();
     public static final Type Host = InternalType.Host.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceGroupEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceGroupEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceGroupEntity.java
index 7f8facb..1bcdd80 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceGroupEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceGroupEntity.java
@@ -18,6 +18,9 @@
 
 package org.apache.ambari.server.orm.entities;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
@@ -25,6 +28,8 @@ import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.IdClass;
 import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
 import javax.persistence.ManyToOne;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
@@ -32,7 +37,6 @@ import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 
 
-
 @IdClass(ServiceGroupEntityPK.class)
 @Table(name = "servicegroups")
 @NamedQueries({
@@ -66,6 +70,19 @@ public class ServiceGroupEntity {
   @JoinColumn(name = "cluster_id", referencedColumnName = "cluster_id", nullable = false)
   private ClusterEntity clusterEntity;
 
+  @ManyToMany
+  @JoinTable(
+    name = "servicegroupdependencies",
+    joinColumns = {@JoinColumn(name = "service_group_id", referencedColumnName = "id", nullable = false),
+                   @JoinColumn(name = "service_group_cluster_id", referencedColumnName = "cluster_id", nullable = false)},
+    inverseJoinColumns = {@JoinColumn(name = "dependent_service_group_id", referencedColumnName = "id", nullable = false),
+                          @JoinColumn(name = "dependent_service_group_cluster_id", referencedColumnName = "cluster_id", nullable = false)}
+  )
+  private List<ServiceGroupEntity> serviceGroupDependencies = new ArrayList<>();
+
+  @ManyToMany(mappedBy="serviceGroupDependencies")
+  private List<ServiceGroupEntity> dependencies = new ArrayList<>();
+
   public Long getClusterId() {
     return clusterId;
   }
@@ -91,6 +108,14 @@ public class ServiceGroupEntity {
     this.serviceGroupName = serviceGroupName;
   }
 
+  public List<ServiceGroupEntity> getServiceGroupDependencies() {
+    return serviceGroupDependencies;
+  }
+
+  public void setServiceGroupDependencies(List<ServiceGroupEntity> serviceGroupDependencies) {
+    this.serviceGroupDependencies = serviceGroupDependencies;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
@@ -120,4 +145,4 @@ public class ServiceGroupEntity {
     this.clusterEntity = clusterEntity;
   }
 
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
index 8fd878e..5ba61b7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
@@ -90,6 +90,8 @@ public interface Cluster {
    */
   ServiceGroup addServiceGroup(String serviceGroupName) throws AmbariException;
 
+  ServiceGroup addServiceGroupDependency(String serviceGroupName, String dependencyServiceGroupName) throws AmbariException;
+
   /**
    * Get a service
    *
@@ -510,6 +512,8 @@ public interface Cluster {
    */
   void deleteServiceGroup(String serviceGroupName) throws AmbariException;
 
+  void deleteServiceGroupDependency(String serviceGroupName, String dependencyServiceGroupName) throws AmbariException;
+
   /**
    * Gets if the cluster can be deleted
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroup.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroup.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroup.java
index 9850462..3d59c96 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroup.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroup.java
@@ -18,8 +18,13 @@
 
 package org.apache.ambari.server.state;
 
+import java.util.Set;
+
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.api.services.ServiceGroupKey;
+import org.apache.ambari.server.controller.ServiceGroupDependencyResponse;
 import org.apache.ambari.server.controller.ServiceGroupResponse;
+import org.apache.ambari.server.orm.entities.ServiceGroupEntity;
 
 public interface ServiceGroup {
 
@@ -33,8 +38,14 @@ public interface ServiceGroup {
 
   Cluster getCluster();
 
+  Set<ServiceGroupKey> getServiceGroupDependencies();
+
+  void setServiceGroupDependencies(Set<ServiceGroupKey> serviceGroupDependencies);
+
   ServiceGroupResponse convertToResponse();
 
+  Set<ServiceGroupDependencyResponse> getServiceGroupDependencyResponses();
+
   void debugDump(StringBuilder sb);
 
   void refresh();
@@ -47,4 +58,6 @@ public interface ServiceGroup {
   boolean canBeRemoved();
 
   void delete() throws AmbariException;
-}
\ No newline at end of file
+
+  ServiceGroupEntity deleteDependency(String dependencyServiceGroupName) throws AmbariException;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupFactory.java
index 7146bdf..3c5e956 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupFactory.java
@@ -18,6 +18,9 @@
 
 package org.apache.ambari.server.state;
 
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.ServiceGroupKey;
 import org.apache.ambari.server.orm.entities.ServiceGroupEntity;
 
 import com.google.inject.assistedinject.Assisted;
@@ -25,7 +28,8 @@ import com.google.inject.assistedinject.Assisted;
 public interface ServiceGroupFactory {
 
   ServiceGroup createNew(Cluster cluster,
-                         @Assisted("serviceGroupName") String serviceGroupName);
+                         @Assisted("serviceGroupName") String serviceGroupName,
+                         @Assisted("serviceGroupDependencies") Set<ServiceGroupKey> serviceGroupDependencies);
 
   ServiceGroup createExisting(Cluster cluster, ServiceGroupEntity serviceGroupEntity);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
index 735a946..7737c0d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceGroupImpl.java
@@ -18,7 +18,15 @@
 
 package org.apache.ambari.server.state;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.api.services.ServiceGroupKey;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ServiceGroupDependencyResponse;
 import org.apache.ambari.server.controller.ServiceGroupResponse;
 import org.apache.ambari.server.events.ServiceGroupInstalledEvent;
 import org.apache.ambari.server.events.ServiceGroupRemovedEvent;
@@ -50,13 +58,16 @@ public class ServiceGroupImpl implements ServiceGroup {
 
   private Long serviceGroupId;
   private String serviceGroupName;
+  private Set<ServiceGroupKey> serviceGroupDependencies = new HashSet<>();
 
   @AssistedInject
   public ServiceGroupImpl(@Assisted Cluster cluster,
                           @Assisted("serviceGroupName") String serviceGroupName,
+                          @Assisted("serviceGroupDependencies") Set<ServiceGroupKey> serviceGroupDependencies,
                           ClusterDAO clusterDAO,
                           ServiceGroupDAO serviceGroupDAO,
-                          AmbariEventPublisher eventPublisher) throws AmbariException {
+                          AmbariEventPublisher eventPublisher,
+                          AmbariManagementController controller) throws AmbariException {
 
     this.cluster = cluster;
     this.clusterDAO = clusterDAO;
@@ -70,6 +81,27 @@ public class ServiceGroupImpl implements ServiceGroup {
     serviceGroupEntity.setServiceGroupId(serviceGroupId);
     serviceGroupEntity.setServiceGroupName(serviceGroupName);
 
+    List<ServiceGroupEntity> serviceGroupEntities = new ArrayList<>();
+    if (serviceGroupDependencies != null) {
+      this.serviceGroupDependencies = serviceGroupDependencies;
+      for (ServiceGroupKey serviceGroupKey : serviceGroupDependencies) {
+        Clusters clusters = controller.getClusters();
+        Cluster dependencyCluster = serviceGroupKey.getClusterName() == null ? cluster :
+                clusters.getCluster(serviceGroupKey.getClusterName());
+        serviceGroupKey.setClusterName(dependencyCluster.getClusterName());
+        ServiceGroup dependencyServiceGroup = dependencyCluster.getServiceGroup(serviceGroupKey.getServiceGroupName());
+
+        ServiceGroupEntityPK serviceGroupEntityPK = new ServiceGroupEntityPK();
+        serviceGroupEntityPK.setServiceGroupId(dependencyServiceGroup.getServiceGroupId());
+        serviceGroupEntityPK.setClusterId(dependencyServiceGroup.getClusterId());
+        ServiceGroupEntity dependentServiceGroupEntity = serviceGroupDAO.findByPK(serviceGroupEntityPK);
+        serviceGroupEntities.add(dependentServiceGroupEntity);
+      }
+    } else {
+      this.serviceGroupDependencies = new HashSet<>();
+    }
+    serviceGroupEntity.setServiceGroupDependencies(serviceGroupEntities);
+
     this.serviceGroupEntityPK = getServiceGroupEntityPK(serviceGroupEntity);
     persist(serviceGroupEntity);
   }
@@ -87,6 +119,7 @@ public class ServiceGroupImpl implements ServiceGroup {
 
     this.serviceGroupId = serviceGroupEntity.getServiceGroupId();
     this.serviceGroupName = serviceGroupEntity.getServiceGroupName();
+    this.serviceGroupDependencies = getServiceGroupDependencies(serviceGroupEntity.getServiceGroupDependencies());
 
     this.serviceGroupEntityPK = getServiceGroupEntityPK(serviceGroupEntity);
   }
@@ -115,6 +148,16 @@ public class ServiceGroupImpl implements ServiceGroup {
   }
 
   @Override
+  public Set<ServiceGroupKey> getServiceGroupDependencies() {
+    return serviceGroupDependencies;
+  }
+
+  @Override
+  public void setServiceGroupDependencies(Set<ServiceGroupKey> serviceGroupDependencies) {
+    this.serviceGroupDependencies = serviceGroupDependencies;
+  }
+
+  @Override
   public ServiceGroupResponse convertToResponse() {
     ServiceGroupResponse r = new ServiceGroupResponse(cluster.getClusterId(),
       cluster.getClusterName(), getServiceGroupId(), getServiceGroupName());
@@ -122,6 +165,61 @@ public class ServiceGroupImpl implements ServiceGroup {
   }
 
   @Override
+  public Set<ServiceGroupDependencyResponse> getServiceGroupDependencyResponses() {
+    Set<ServiceGroupDependencyResponse> responses = new HashSet<>();
+    if (getServiceGroupDependencies() != null) {
+      for (ServiceGroupKey sgk : getServiceGroupDependencies()) {
+        responses.add(new ServiceGroupDependencyResponse(cluster.getClusterId(), cluster.getClusterName(),
+                serviceGroupId, serviceGroupName, sgk.getClusterId(), sgk.getClusterName(), sgk.getServiceGroupId(), sgk.getServiceGroupName()));
+      }
+    }
+    return responses;
+  }
+
+  public Set<ServiceGroupKey> getServiceGroupDependencies(List<ServiceGroupEntity> serviceGroupDependencies) {
+    Set<ServiceGroupKey> serviceGroupDependenciesList = new HashSet<>();
+    if (serviceGroupDependencies != null) {
+      for (ServiceGroupEntity sge : serviceGroupDependencies) {
+        ServiceGroupKey serviceGroupKey = new ServiceGroupKey();
+        String clusterName = "";
+        Long clusterId = null;
+        if (sge.getClusterId() == cluster.getClusterId()) {
+          clusterName = cluster.getClusterName();
+          clusterId = cluster.getClusterId();
+        } else {
+          ClusterEntity clusterEntity = clusterDAO.findById(sge.getClusterId());
+          if (clusterEntity != null) {
+            clusterName = clusterEntity.getClusterName();
+            clusterId = clusterEntity.getClusterId();
+          } else {
+            LOG.error("Unable to get cluster id for service group " + sge.getServiceGroupName());
+          }
+        }
+
+        ServiceGroupEntityPK serviceGroupEntityPK = new ServiceGroupEntityPK();
+        serviceGroupEntityPK.setClusterId(sge.getClusterId());
+        serviceGroupEntityPK.setServiceGroupId(sge.getServiceGroupId());
+        ServiceGroupEntity serviceGroupEntity = serviceGroupDAO.findByPK(serviceGroupEntityPK);
+        String serviceGroupDependencyName = "";
+        Long serviceGroupDependencId = null;
+        if (serviceGroupEntity != null) {
+          serviceGroupDependencyName = serviceGroupEntity.getServiceGroupName();
+          serviceGroupDependencId = serviceGroupEntity.getServiceGroupId();
+        } else {
+          LOG.error("Unable to get service group entity for service group " + sge.getServiceGroupName());
+        }
+
+        serviceGroupKey.setServiceGroupName(serviceGroupDependencyName);
+        serviceGroupKey.setServiceGroupId(serviceGroupDependencId);
+        serviceGroupKey.setClusterName(clusterName);
+        serviceGroupKey.setClusterId(clusterId);
+        serviceGroupDependenciesList.add(serviceGroupKey);
+      }
+    }
+    return serviceGroupDependenciesList;
+  }
+
+  @Override
   public Cluster getCluster() {
     return cluster;
   }
@@ -190,6 +288,25 @@ public class ServiceGroupImpl implements ServiceGroup {
     eventPublisher.publish(event);
   }
 
+  @Override
+  @Transactional
+  public ServiceGroupEntity deleteDependency(String dependencyServiceGroupName) throws AmbariException {
+    ServiceGroupEntityPK pk = new ServiceGroupEntityPK();
+    pk.setClusterId(getClusterId());
+    pk.setServiceGroupId(getServiceGroupId());
+    ServiceGroupEntity serviceGroupEntity = serviceGroupDAO.findByPK(pk);
+    ServiceGroupEntity dependencyToRemove = null;
+    for (ServiceGroupEntity dependency : serviceGroupEntity.getServiceGroupDependencies()) {
+      if (dependency.getServiceGroupName().equals(dependencyServiceGroupName)) {
+        dependencyToRemove = dependency;
+        break;
+      }
+    }
+    serviceGroupEntity.getServiceGroupDependencies().remove(dependencyToRemove);
+    serviceGroupEntity = serviceGroupDAO.merge(serviceGroupEntity);
+    return serviceGroupEntity;
+  }
+
   @Transactional
   protected void removeEntities() throws AmbariException {
 
@@ -210,4 +327,4 @@ public class ServiceGroupImpl implements ServiceGroup {
     pk.setServiceGroupId(serviceGroupEntity.getServiceGroupId());
     return pk;
   }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index 1e4d81f..e896d0e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -54,6 +54,7 @@ import org.apache.ambari.server.ServiceGroupNotFoundException;
 import org.apache.ambari.server.ServiceNotFoundException;
 import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.api.services.ServiceGroupKey;
 import org.apache.ambari.server.controller.AmbariSessionManager;
 import org.apache.ambari.server.controller.ClusterResponse;
 import org.apache.ambari.server.controller.ConfigurationResponse;
@@ -81,6 +82,7 @@ import org.apache.ambari.server.orm.dao.HostConfigMappingDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.dao.HostVersionDAO;
 import org.apache.ambari.server.orm.dao.ServiceConfigDAO;
+import org.apache.ambari.server.orm.dao.ServiceGroupDAO;
 import org.apache.ambari.server.orm.dao.StackDAO;
 import org.apache.ambari.server.orm.dao.TopologyRequestDAO;
 import org.apache.ambari.server.orm.dao.UpgradeDAO;
@@ -99,6 +101,7 @@ import org.apache.ambari.server.orm.entities.ResourceEntity;
 import org.apache.ambari.server.orm.entities.ServiceConfigEntity;
 import org.apache.ambari.server.orm.entities.ServiceDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.ServiceGroupEntity;
+import org.apache.ambari.server.orm.entities.ServiceGroupEntityPK;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.orm.entities.TopologyRequestEntity;
 import org.apache.ambari.server.orm.entities.UpgradeEntity;
@@ -273,6 +276,9 @@ public class ClusterImpl implements Cluster {
   @Inject
   private TopologyRequestDAO topologyRequestDAO;
 
+  @Inject
+  private ServiceGroupDAO serviceGroupDAO;
+
   /**
    * Data access object used for looking up stacks from the database.
    */
@@ -905,7 +911,43 @@ public class ClusterImpl implements Cluster {
         + ", clusterId=" + getClusterId() + ", serviceGroupName=" + serviceGroupName);
     }
 
-    ServiceGroup serviceGroup = serviceGroupFactory.createNew(this, serviceGroupName);
+    ServiceGroup serviceGroup = serviceGroupFactory.createNew(this, serviceGroupName, new HashSet<ServiceGroupKey>());
+    addServiceGroup(serviceGroup);
+    return serviceGroup;
+  }
+
+  @Override
+  public ServiceGroup addServiceGroupDependency(String serviceGroupName, String dependencyServiceGroupName) throws AmbariException {
+    if (!serviceGroups.containsKey(serviceGroupName)) {
+      throw new AmbariException("Service group doesn't exist" + ", clusterName=" + getClusterName()
+              + ", clusterId=" + getClusterId() + ", serviceGroupName=" + serviceGroupName);
+    }
+
+    if (!serviceGroups.containsKey(dependencyServiceGroupName)) {
+      throw new AmbariException("Dependent service group doesn't exist" + ", clusterName=" + getClusterName()
+              + ", clusterId=" + getClusterId() + ", serviceGroupName=" + serviceGroupName);
+    }
+
+    ServiceGroupEntity serviceGroupEntity = null;
+    clusterGlobalLock.writeLock().lock();
+    try {
+      ServiceGroupEntityPK serviceGroupEntityPK = new ServiceGroupEntityPK();
+      serviceGroupEntityPK.setClusterId(getClusterId());
+      serviceGroupEntityPK.setServiceGroupId(serviceGroups.get(serviceGroupName).getServiceGroupId());
+      serviceGroupEntity = serviceGroupDAO.findByPK(serviceGroupEntityPK);
+
+      ServiceGroupEntityPK dependencyServiceGroupEntityPK = new ServiceGroupEntityPK();
+      dependencyServiceGroupEntityPK.setClusterId(getClusterId());
+      dependencyServiceGroupEntityPK.setServiceGroupId(serviceGroups.get(dependencyServiceGroupName).getServiceGroupId());
+      ServiceGroupEntity dependencyServiceGroupEntity = serviceGroupDAO.findByPK(dependencyServiceGroupEntityPK);
+
+      serviceGroupEntity.getServiceGroupDependencies().add(dependencyServiceGroupEntity);
+      serviceGroupEntity = serviceGroupDAO.merge(serviceGroupEntity);
+    } finally {
+      clusterGlobalLock.writeLock().unlock();
+    }
+
+    ServiceGroup serviceGroup = serviceGroupFactory.createExisting(this, serviceGroupEntity);
     addServiceGroup(serviceGroup);
     return serviceGroup;
   }
@@ -1409,6 +1451,24 @@ public class ClusterImpl implements Cluster {
     }
   }
 
+  @Override
+  public void deleteServiceGroupDependency(String serviceGroupName, String dependencyServiceGroupName) throws AmbariException {
+    clusterGlobalLock.writeLock().lock();
+    try {
+      ServiceGroup serviceGroup = getServiceGroup(serviceGroupName);
+      LOG.info("Deleting service group dependency, dependencyServiceGroupName=" + dependencyServiceGroupName + " in cluster" + ", clusterName="
+              + getClusterName() + ", serviceGroupName=" + serviceGroup.getServiceGroupName());
+
+      Long serviceGroupId = serviceGroup.getServiceGroupId();
+      ServiceGroupEntity serviceGroupEntity = serviceGroup.deleteDependency(dependencyServiceGroupName);
+      ServiceGroup updatedServiceGroup = serviceGroupFactory.createExisting(this, serviceGroupEntity);
+      serviceGroups.put(updatedServiceGroup.getServiceGroupName(), updatedServiceGroup);
+      serviceGroupsById.put(updatedServiceGroup.getServiceGroupId(), updatedServiceGroup);
+    } finally {
+      clusterGlobalLock.writeLock().unlock();
+    }
+  }
+
   /**
    * Deletes the specified service also removes references to it from {@link this.serviceComponentHosts}
    * and references to ServiceComponentHost objects that belong to the service from {@link this.serviceComponentHostsByHost}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
index 9270e7d..fda0566 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java
@@ -61,6 +61,7 @@ import org.apache.ambari.server.controller.internal.HostComponentResourceProvide
 import org.apache.ambari.server.controller.internal.HostResourceProvider;
 import org.apache.ambari.server.controller.internal.ProvisionClusterRequest;
 import org.apache.ambari.server.controller.internal.RequestImpl;
+import org.apache.ambari.server.controller.internal.ServiceGroupDependencyResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceGroupResourceProvider;
 import org.apache.ambari.server.controller.internal.ServiceResourceProvider;
 import org.apache.ambari.server.controller.internal.VersionDefinitionResourceProvider;
@@ -128,6 +129,7 @@ public class AmbariContext {
   private static HostRoleCommandFactory hostRoleCommandFactory;
   private static HostResourceProvider hostResourceProvider;
   private static ServiceGroupResourceProvider serviceGroupResourceProvider;
+  private static ServiceGroupDependencyResourceProvider serviceGroupDependencyResourceProvider;
   private static ServiceResourceProvider serviceResourceProvider;
   private static ComponentResourceProvider componentResourceProvider;
   private static HostComponentResourceProvider hostComponentResourceProvider;
@@ -771,6 +773,14 @@ public class AmbariContext {
     return serviceGroupResourceProvider;
   }
 
+  private synchronized ServiceGroupDependencyResourceProvider getServiceGroupDependencyResourceProvider() {
+    if (serviceGroupDependencyResourceProvider == null) {
+      serviceGroupResourceProvider = (ServiceGroupResourceProvider) ClusterControllerHelper.
+              getClusterController().ensureResourceProvider(Resource.Type.ServiceGroupDependency);
+    }
+    return serviceGroupDependencyResourceProvider;
+  }
+
   private synchronized ServiceResourceProvider getServiceResourceProvider() {
     if (serviceResourceProvider == null) {
       serviceResourceProvider = (ServiceResourceProvider) ClusterControllerHelper.
@@ -796,4 +806,4 @@ public class AmbariContext {
 
   }
 
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
index ce201e4..19e23c5 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -177,6 +177,15 @@ CREATE TABLE servicegroups (
   CONSTRAINT PK_servicegroups PRIMARY KEY (id, cluster_id),
   CONSTRAINT FK_servicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
 
+CREATE TABLE servicegroupdependencies (
+  service_group_id BIGINT NOT NULL,
+  service_group_cluster_id BIGINT NOT NULL,
+  dependent_service_group_id BIGINT NOT NULL,
+  dependent_service_group_cluster_id BIGINT NOT NULL,
+  CONSTRAINT PK_servicegroupdependencies PRIMARY KEY (service_group_id, service_group_cluster_id, dependent_service_group_id, dependent_service_group_cluster_id),
+  CONSTRAINT FK_servicegroupdependencies_service_group_cluster_id FOREIGN KEY (service_group_id, service_group_cluster_id) REFERENCES servicegroups (id, cluster_id));
+  CONSTRAINT FK_servicegroupdependencies_dependent_service_group_cluster_id FOREIGN KEY (dependent_service_group_id, dependent_service_group_cluster_id) REFERENCES servicegroups (id, cluster_id));
+
 CREATE TABLE clusterservices (
   id BIGINT NOT NULL,
   service_name VARCHAR(255) NOT NULL,

http://git-wip-us.apache.org/repos/asf/ambari/blob/16913b20/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index f4d9554..b1990df 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -196,6 +196,15 @@ CREATE TABLE servicegroups (
   CONSTRAINT PK_servicegroups PRIMARY KEY (id, cluster_id),
   CONSTRAINT FK_servicegroups_cluster_id FOREIGN KEY (cluster_id) REFERENCES clusters (cluster_id));
 
+CREATE TABLE servicegroupdependencies (
+  service_group_id BIGINT NOT NULL,
+  service_group_cluster_id BIGINT NOT NULL,
+  dependent_service_group_id BIGINT NOT NULL,
+  dependent_service_group_cluster_id BIGINT NOT NULL,
+  CONSTRAINT PK_servicegroupdependencies PRIMARY KEY (service_group_id, service_group_cluster_id, dependent_service_group_id, dependent_service_group_cluster_id),
+  CONSTRAINT FK_servicegroupdependencies_service_group_cluster_id FOREIGN KEY (service_group_id, service_group_cluster_id) REFERENCES servicegroups (id, cluster_id));
+  CONSTRAINT FK_servicegroupdependencies_dependent_service_group_cluster_id FOREIGN KEY (dependent_service_group_id, dependent_service_group_cluster_id) REFERENCES servicegroups (id, cluster_id));
+
 CREATE TABLE clusterservices (
   id BIGINT NOT NULL,
   service_name VARCHAR(255) NOT NULL,