ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From swa...@apache.org
Subject [3/3] git commit: AMBARI-4034. Create the RequestSchedule resource provider. Patch 1. (swagle)
Date Mon, 23 Dec 2013 22:13:18 GMT
AMBARI-4034. Create the RequestSchedule resource provider. Patch 1. (swagle)


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

Branch: refs/heads/trunk
Commit: 5dcea3726e53eea4243510da156a9c8f145f51ef
Parents: ef81b39
Author: Siddharth Wagle <swagle@hortonworks.com>
Authored: Mon Dec 23 12:46:02 2013 -0800
Committer: Siddharth Wagle <swagle@hortonworks.com>
Committed: Mon Dec 23 14:12:55 2013 -0800

----------------------------------------------------------------------
 ambari-server/conf/unix/ambari.properties       |   7 +
 ambari-server/pom.xml                           |  10 +
 .../RequestScheduleResourceDefinition.java      |  78 +++
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 .../server/api/services/ClusterService.java     |   9 +
 .../api/services/RequestScheduleService.java    | 162 +++++
 .../services/parsers/JsonRequestBodyParser.java |   7 +-
 .../api/services/parsers/RequestBodyParser.java |   6 +
 .../server/configuration/Configuration.java     |  44 +-
 .../controller/AmbariManagementController.java  |   9 +-
 .../AmbariManagementControllerImpl.java         |   8 +
 .../ambari/server/controller/AmbariServer.java  |  14 +-
 .../server/controller/ControllerModule.java     |   8 +
 .../controller/RequestScheduleRequest.java      |  89 +++
 .../controller/RequestScheduleResponse.java     | 132 +++++
 .../AbstractControllerResourceProvider.java     |   2 +
 .../internal/ConfigGroupResourceProvider.java   |   5 +-
 .../RequestScheduleResourceProvider.java        | 584 +++++++++++++++++++
 .../ambari/server/controller/spi/Resource.java  |   1 +
 .../orm/dao/RequestScheduleBatchHostDAO.java    |  88 ---
 .../orm/dao/RequestScheduleBatchRequestDAO.java |  99 ++++
 .../server/orm/dao/RequestScheduleDAO.java      |   2 +-
 .../RequestScheduleBatchHostEntity.java         | 133 -----
 .../RequestScheduleBatchHostEntityPK.java       |  81 ---
 .../RequestScheduleBatchRequestEntity.java      | 172 ++++++
 .../RequestScheduleBatchRequestEntityPK.java    |  67 +++
 .../orm/entities/RequestScheduleEntity.java     | 102 +---
 .../scheduler/AbstractLinearExecutionJob.java   | 103 ++++
 .../ambari/server/scheduler/ExecutionJob.java   |  34 ++
 .../scheduler/ExecutionScheduleManager.java     | 103 ++++
 .../server/scheduler/ExecutionScheduler.java    |  52 ++
 .../scheduler/ExecutionSchedulerImpl.java       | 170 ++++++
 .../org/apache/ambari/server/state/Cluster.java |  21 +
 .../server/state/cluster/ClusterImpl.java       | 339 +++++++----
 .../state/configgroup/ConfigGroupImpl.java      |   5 -
 .../ambari/server/state/scheduler/Batch.java    |  46 ++
 .../server/state/scheduler/BatchRequest.java    | 109 ++++
 .../server/state/scheduler/BatchRequestJob.java |  34 ++
 .../server/state/scheduler/BatchSettings.java   |  47 ++
 .../state/scheduler/RequestExecution.java       | 145 +++++
 .../scheduler/RequestExecutionFactory.java      |  31 +
 .../state/scheduler/RequestExecutionImpl.java   | 373 ++++++++++++
 .../ambari/server/state/scheduler/Schedule.java | 177 ++++++
 .../apache/ambari/server/utils/DateUtils.java   |  63 ++
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   7 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   9 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   9 +-
 .../Ambari-DDL-Postgres-REMOTE-CREATE.sql       |   7 +-
 .../src/main/resources/META-INF/persistence.xml |   2 +-
 .../src/main/resources/key_properties.json      |   4 +
 .../src/main/resources/properties.json          |   9 +
 .../ambari/server/agent/AgentResourceTest.java  |   5 +
 .../RequestScheduleResourceProviderTest.java    | 404 +++++++++++++
 .../server/orm/InMemoryDefaultTestModule.java   |   2 -
 .../server/orm/dao/RequestScheduleDAOTest.java  |  49 +-
 .../scheduler/ExecutionSchedulerTest.java       | 110 ++++
 .../server/state/RequestExecutionTest.java      | 275 +++++++++
 ambari-server/src/test/resources/password.dat   |   1 +
 58 files changed, 4103 insertions(+), 565 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/conf/unix/ambari.properties
----------------------------------------------------------------------
diff --git a/ambari-server/conf/unix/ambari.properties b/ambari-server/conf/unix/ambari.properties
index 01a4b3c..d70612f 100644
--- a/ambari-server/conf/unix/ambari.properties
+++ b/ambari-server/conf/unix/ambari.properties
@@ -29,3 +29,10 @@ bootstrap.setup_agent.script=/usr/lib/python2.6/site-packages/ambari_server/setu
 api.authenticate=true
 server.connection.max.idle.millis=900000
 server.fqdn.service.url=http://169.254.169.254/latest/meta-data/public-hostname
+
+# Scheduler settings
+server.execution.scheduler.isClustered=false
+server.execution.scheduler.maxThreads=5
+server.execution.scheduler.maxDbConnections=5
+server.execution.scheduler.misfire.toleration.minutes=480
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 095df3a..722a123 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -832,6 +832,16 @@
       <artifactId>jsr305</artifactId>
       <version>1.3.9</version>
     </dependency>
+    <dependency>
+      <groupId>org.quartz-scheduler</groupId>
+      <artifactId>quartz</artifactId>
+      <version>2.2.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.quartz-scheduler</groupId>
+      <artifactId>quartz-jobs</artifactId>
+      <version>2.2.1</version>
+    </dependency>
   </dependencies>
   <!--<reporting>
         <plugins>

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RequestScheduleResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RequestScheduleResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RequestScheduleResourceDefinition.java
new file mode 100644
index 0000000..5b1af91
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RequestScheduleResourceDefinition.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.util.TreeNode;
+import org.apache.ambari.server.controller.spi.Resource;
+import java.util.Collections;
+import java.util.List;
+
+public class RequestScheduleResourceDefinition extends BaseResourceDefinition {
+  /**
+   * Constructor.
+   *
+   * @param resourceType resource type
+   */
+  public RequestScheduleResourceDefinition() {
+    super(Resource.Type.RequestSchedule);
+  }
+
+  @Override
+  public String getPluralName() {
+    return "request_schedules";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "request_schedule";
+  }
+
+  @Override
+  public List<PostProcessor> getPostProcessors() {
+    return Collections.<PostProcessor>singletonList(new
+      RequestScheduleHrefPostProcessor());
+  }
+
+  private class RequestScheduleHrefPostProcessor implements PostProcessor {
+
+    @Override
+    public void process(Request request, TreeNode<Resource> resultNode, String href) {
+      StringBuilder sb = new StringBuilder();
+      String[] tokens = href.split("/");
+
+      for (int i = 0; i < tokens.length; ++i) {
+        String s = tokens[i];
+        sb.append(s).append('/');
+        if ("clusters".equals(s)) {
+          sb.append(tokens[i + 1]).append('/');
+          break;
+        }
+      }
+
+      Object scheduleId = resultNode.getObject()
+        .getPropertyValue(getClusterController()
+          .getSchema(Resource.Type.RequestSchedule)
+            .getKeyPropertyId(Resource.Type.RequestSchedule));
+
+      sb.append("request_schedules/").append(scheduleId);
+
+      resultNode.setProperty("href", sb.toString());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/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 02d081e..1ab6682 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
@@ -163,6 +163,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new ConfigGroupResourceDefinition();
         break;
 
+      case RequestSchedule:
+        resourceDefinition = new RequestScheduleResourceDefinition();
+        break;
+
       default:
         throw new IllegalArgumentException("Unsupported resource type: " + type);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
index 4da4385..a6630b8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
@@ -200,6 +200,15 @@ public class ClusterService extends BaseService {
   }
 
   /**
+   * Gets the request schedule service
+   */
+  @Path("{clusterName}/request_schedules")
+  public RequestScheduleService getRequestScheduleService
+                             (@PathParam ("clusterName") String clusterName) {
+    return new RequestScheduleService(clusterName);
+  }
+
+  /**
    * Create a cluster resource instance.
    *
    * @param clusterName cluster name

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestScheduleService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestScheduleService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestScheduleService.java
new file mode 100644
index 0000000..c59a8e3
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestScheduleService.java
@@ -0,0 +1,162 @@
+/**
+ * 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 management of a batch of requests with attached
+ * schedule
+ */
+public class RequestScheduleService extends BaseService {
+  /**
+   * Parent cluster name.
+   */
+  private String m_clusterName;
+
+  /**
+   * Constructor
+   * @param m_clusterName
+   */
+  public RequestScheduleService(String m_clusterName) {
+    this.m_clusterName = m_clusterName;
+  }
+
+  /**
+   * Handles URL: /clusters/{clusterId}/request_schedules
+   * Get all the scheduled requests for a cluster.
+   *
+   * @param headers
+   * @param ui
+   * @return
+   */
+  @GET
+  @Produces("text/plain")
+  public Response getRequestSchedules(@Context HttpHeaders headers,
+                                  @Context UriInfo ui) {
+    return handleRequest(headers, null, ui, Request.Type.GET,
+      createRequestSchedule(m_clusterName, null));
+  }
+
+  /**
+   * Handles URL: /clusters/{clusterId}/request_schedules/{requestScheduleId}
+   * Get details on a specific request schedule
+   *
+   * @return
+   */
+  @GET
+  @Path("{requestScheduleId}")
+  @Produces("text/plain")
+  public Response getRequestSchedule(@Context HttpHeaders headers,
+                                     @Context UriInfo ui,
+                                     @PathParam("requestScheduleId") String requestScheduleId) {
+    return handleRequest(headers, null, ui, Request.Type.GET,
+      createRequestSchedule(m_clusterName, requestScheduleId));
+  }
+
+  /**
+   * Handles POST /clusters/{clusterId}/request_schedules
+   * Create a new request schedule
+   *
+   * @param body
+   * @param headers
+   * @param ui
+   * @return
+   */
+  @POST
+  @Produces("text/plain")
+  public Response createRequestSchedule(String body, @Context HttpHeaders
+    headers,
+                                    @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.POST,
+      createRequestSchedule(m_clusterName, null));
+  }
+
+  /**
+   * Handles PUT /clusters/{clusterId}/request_schedules/{requestScheduleId}
+   * Update a request schedule
+   *
+   * @param body
+   * @param headers
+   * @param ui
+   * @param requestScheduleId
+   * @return
+   */
+  @PUT
+  @Path("{requestScheduleId}")
+  @Produces("text/plain")
+  public Response updateRequestSchedule(String body,
+                                        @Context HttpHeaders headers,
+                                        @Context UriInfo ui,
+                                        @PathParam("requestScheduleId") String requestScheduleId) {
+    return handleRequest(headers, body, ui, Request.Type.PUT,
+      createRequestSchedule(m_clusterName, requestScheduleId));
+  }
+
+  /**
+   * Handles DELETE /clusters/{clusterId}/request_schedules/{requestScheduleId}
+   * Delete a request schedule
+   *
+   * @param headers
+   * @param ui
+   * @param requestScheduleId
+   * @return
+   */
+  @DELETE
+  @Path("{requestScheduleId}")
+  @Produces("text/plain")
+  public Response deleteRequestSchedule(@Context HttpHeaders headers,
+                                    @Context UriInfo ui,
+                                    @PathParam("requestScheduleId") String requestScheduleId) {
+    return handleRequest(headers, null, ui, Request.Type.DELETE,
+      createRequestSchedule(m_clusterName, requestScheduleId));
+  }
+
+
+
+  /**
+   * Create a request schedule resource instance
+   * @param clusterName
+   * @param requestScheduleId
+   * @return
+   */
+  private ResourceInstance createRequestSchedule(String clusterName,
+                                                 String requestScheduleId) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, clusterName);
+    mapIds.put(Resource.Type.RequestSchedule, requestScheduleId);
+
+    return createResource(Resource.Type.RequestSchedule, mapIds);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/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 8f940ec..3443b72 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
@@ -125,7 +125,12 @@ public class JsonRequestBodyParser implements RequestBodyParser {
         if (name.equals(BODY_TITLE)) {
           name = "";
         }
-        processNode(child, path.isEmpty() ? name : path + '/' + name, propertySet, requestInfoProps);
+        if (name.equals(REQUEST_BLOB_TITLE)) {
+          propertySet.getProperties().put(PropertyHelper.getPropertyId(path,
+            name), child.toString());
+        } else {
+          processNode(child, path.isEmpty() ? name : path + '/' + name, propertySet, requestInfoProps);
+        }
       } else {
         // field
         if (path.startsWith(REQUEST_INFO_PATH)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/RequestBodyParser.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/RequestBodyParser.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/RequestBodyParser.java
index e625bf3..aefcb52 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/RequestBodyParser.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/parsers/RequestBodyParser.java
@@ -31,6 +31,12 @@ public interface RequestBodyParser {
    * RequestInfo category path.
    */
   public static final String REQUEST_INFO_PATH = "RequestInfo";
+
+  /**
+   * Category path to ignore parsing of the child node
+   */
+  public static final String REQUEST_BLOB_TITLE = "RequestBodyInfo";
+
   /**
    * Name of the query property which may exist under REQUEST_INFO_PATH.
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index dd6b66d..53a77a8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -262,6 +262,18 @@ public class Configuration {
    */
   private static final String REPO_SUFFIX_DEFAULT = "/repodata/repomd.xml";
 
+  public static final String EXECUTION_SCHEDULER_CLUSTERED =
+    "server.execution.scheduler.isClustered";
+  public static final String EXECUTION_SCHEDULER_THREADS =
+    "server.execution.scheduler.maxThreads";
+  public static final String EXECUTION_SCHEDULER_CONNECTIONS =
+    "server.execution.scheduler.maxDbConnections";
+  public static final String EXECUTION_SCHEDULER_MISFIRE_TOLERATION =
+    "server.execution.scheduler.misfire.toleration.minutes";
+  public static final String DEFAULT_SCHEDULER_THREAD_COUNT = "5";
+  public static final String DEFAULT_SCHEDULER_MAX_CONNECTIONS = "5";
+  public static final String DEFAULT_EXECUTION_SCHEDULER_MISFIRE_TOLERATION = "480";
+
   private static final Logger LOG = LoggerFactory.getLogger(
       Configuration.class);
 
@@ -590,11 +602,11 @@ public class Configuration {
   }
 
   public String getDatabaseDriver() {
-    return properties.getProperty(SERVER_JDBC_DRIVER_KEY);
+    return properties.getProperty(SERVER_JDBC_DRIVER_KEY, JDBC_LOCAL_DRIVER);
   }
 
   public String getDatabaseUrl() {
-    return properties.getProperty(SERVER_JDBC_URL_KEY);
+    return properties.getProperty(SERVER_JDBC_URL_KEY, getLocalDatabaseUrl());
   }
 
   public String getLocalDatabaseUrl() {
@@ -602,7 +614,7 @@ public class Configuration {
     if(dbName == null || dbName.isEmpty())
       throw new RuntimeException("Server DB Name is not configured!");
 
-    return JDBC_LOCAL_URL + properties.getProperty(SERVER_DB_NAME_KEY);
+    return JDBC_LOCAL_URL + dbName;
   }
 
   public String getDatabaseUser() {
@@ -611,7 +623,10 @@ public class Configuration {
 
   public String getDatabasePassword() {
     String passwdProp = properties.getProperty(SERVER_JDBC_USER_PASSWD_KEY);
-    String dbpasswd = readPasswordFromStore(passwdProp);
+    String dbpasswd = null;
+    if (CredentialProvider.isAliasString(passwdProp)) {
+      dbpasswd = readPasswordFromStore(passwdProp);
+    }
 
     if (dbpasswd != null)
       return dbpasswd;
@@ -850,4 +865,25 @@ public class Configuration {
     
     return value.split(",");
   }
+
+  public String isExecutionSchedulerClusterd() {
+    return properties.getProperty(EXECUTION_SCHEDULER_CLUSTERED, "false");
+  }
+
+  public String getExecutionSchedulerThreads() {
+    return properties.getProperty(EXECUTION_SCHEDULER_THREADS,
+      DEFAULT_SCHEDULER_THREAD_COUNT);
+  }
+
+  public String getExecutionSchedulerConnections() {
+    return properties.getProperty(EXECUTION_SCHEDULER_CONNECTIONS,
+      DEFAULT_SCHEDULER_MAX_CONNECTIONS);
+  }
+
+  public Long getExecutionSchedulerMisfireToleration() {
+    String limit = properties.getProperty
+      (EXECUTION_SCHEDULER_MISFIRE_TOLERATION,
+        DEFAULT_EXECUTION_SCHEDULER_MISFIRE_TOLERATION);
+    return Long.parseLong(limit);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
index b21b5b4..18bd98b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
@@ -30,6 +30,7 @@ import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
+import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
 
 import java.util.Collection;
 import java.util.List;
@@ -482,7 +483,7 @@ public interface AmbariManagementController {
    */
   public Map<String, Map<String,String>> findConfigurationTagsWithOverrides(
           Cluster cluster, String hostName) throws AmbariException;
-  
+
   /**
    * Returns parameters for RCA database
    *
@@ -490,5 +491,11 @@ public interface AmbariManagementController {
    *
    */
   public Map<String, String> getRcaParameters();
+
+  /**
+   * Get the Factory to create Request schedules
+   * @return
+   */
+  public RequestExecutionFactory getRequestExecutionFactory();
 }
   

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index b4bc3c0..46c6a9f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -61,6 +61,7 @@ import org.apache.ambari.server.stageplanner.RoleGraph;
 import org.apache.ambari.server.state.*;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
+import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostMaintenanceEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostRestoreEvent;
@@ -130,6 +131,8 @@ public class AmbariManagementControllerImpl implements
   private ConfigGroupFactory configGroupFactory;
   @Inject
   private ConfigHelper configHelper;
+  @Inject
+  private RequestExecutionFactory requestExecutionFactory;
 
   final private String masterHostname;
   final private Integer masterPort;
@@ -1006,6 +1009,11 @@ public class AmbariManagementControllerImpl implements
     return configHelper.getEffectiveDesiredTags(cluster, hostName);
   }
 
+  @Override
+  public RequestExecutionFactory getRequestExecutionFactory() {
+    return requestExecutionFactory;
+  }
+
   private List<Stage> doStageCreation(Cluster cluster,
       Map<State, List<Service>> changedServices,
       Map<State, List<ServiceComponent>> changedComps,

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index ea5a017..63e4c56 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -47,6 +47,8 @@ import org.apache.ambari.server.orm.PersistenceType;
 import org.apache.ambari.server.orm.dao.MetainfoDAO;
 import org.apache.ambari.server.resources.ResourceManager;
 import org.apache.ambari.server.resources.api.rest.GetResource;
+import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
+import org.apache.ambari.server.scheduler.ExecutionScheduler;
 import org.apache.ambari.server.security.CertificateManager;
 import org.apache.ambari.server.security.SecurityFilter;
 import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider;
@@ -111,7 +113,6 @@ public class AmbariServer {
     return configs.getServerOsType();
   }
 
-
   private static AmbariManagementController clusterController = null;
 
   public static AmbariManagementController getController() {
@@ -349,6 +350,11 @@ public class AmbariServer {
       AmbariManagementController controller = injector.getInstance(
           AmbariManagementController.class);
 
+      LOG.info("********* Initializing Scheduled Request Manager **********");
+      ExecutionScheduleManager executionScheduleManager = injector
+        .getInstance(ExecutionScheduleManager.class);
+
+
       clusterController = controller;
 
       // FIXME need to figure out correct order of starting things to
@@ -365,10 +371,8 @@ public class AmbariServer {
       manager.start();
       LOG.info("********* Started ActionManager **********");
 
-      //TODO: Remove this code when APIs are ready for testing.
-      //      RequestInjectorForTest testInjector = new RequestInjectorForTest(controller, clusters);
-      //      Thread testInjectorThread = new Thread(testInjector);
-      //      testInjectorThread.start();
+      executionScheduleManager.start();
+      LOG.info("********* Started Scheduled Request Manager **********");
 
       server.join();
       LOG.info("Joined the Server");

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/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 7d60bab..974b481 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
@@ -32,6 +32,8 @@ import org.apache.ambari.server.actionmanager.HostRoleCommandFactoryImpl;
 import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.PersistenceType;
+import org.apache.ambari.server.scheduler.ExecutionScheduler;
+import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
 import org.apache.ambari.server.serveraction.ServerActionManager;
 import org.apache.ambari.server.serveraction.ServerActionManagerImpl;
 import org.apache.ambari.server.state.Cluster;
@@ -56,6 +58,9 @@ import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.configgroup.ConfigGroupImpl;
 import org.apache.ambari.server.state.host.HostFactory;
 import org.apache.ambari.server.state.host.HostImpl;
+import org.apache.ambari.server.state.scheduler.RequestExecution;
+import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
+import org.apache.ambari.server.state.scheduler.RequestExecutionImpl;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostImpl;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.StandardPasswordEncoder;
@@ -112,6 +117,7 @@ public class ControllerModule extends AbstractModule {
         .to(AmbariManagementControllerImpl.class);
     bind(AbstractRootServiceResponseFactory.class).to(RootServiceResponseFactory.class);
     bind(ServerActionManager.class).to(ServerActionManagerImpl.class);
+    bind(ExecutionScheduler.class).to(ExecutionSchedulerImpl.class);
 
     requestStaticInjection(ExecutionCommandWrapper.class);
   }
@@ -189,6 +195,8 @@ public class ControllerModule extends AbstractModule {
         Config.class, ConfigImpl.class).build(ConfigFactory.class));
     install(new FactoryModuleBuilder().implement(
       ConfigGroup.class, ConfigGroupImpl.class).build(ConfigGroupFactory.class));
+    install(new FactoryModuleBuilder().implement(RequestExecution.class,
+      RequestExecutionImpl.class).build(RequestExecutionFactory.class));
     install(new FactoryModuleBuilder().build(StageFactory.class));
     bind(HostRoleCommandFactory.class).to(HostRoleCommandFactoryImpl.class);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleRequest.java
new file mode 100644
index 0000000..8f01bf9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleRequest.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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller;
+
+import org.apache.ambari.server.state.scheduler.Batch;
+import org.apache.ambari.server.state.scheduler.Schedule;
+
+public class RequestScheduleRequest {
+  private Long id;
+  private String clusterName;
+  private String description;
+  private String status;
+  private Batch batch;
+  private Schedule schedule;
+
+  public RequestScheduleRequest(Long id, String clusterName,
+                                String description, String status,
+                                Batch batch, Schedule schedule) {
+    this.id = id;
+    this.clusterName = clusterName;
+    this.description = description;
+    this.status = status;
+    this.batch = batch;
+    this.schedule = schedule;
+  }
+
+  public Long getId() {
+    return id;
+  }
+
+  public void setId(Long id) {
+    this.id = id;
+  }
+
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public Batch getBatch() {
+    return batch;
+  }
+
+  public void setBatch(Batch batch) {
+    this.batch = batch;
+  }
+
+  public Schedule getSchedule() {
+    return schedule;
+  }
+
+  public void setSchedule(Schedule schedule) {
+    this.schedule = schedule;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleResponse.java
new file mode 100644
index 0000000..a94e972
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleResponse.java
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+import org.apache.ambari.server.state.scheduler.Batch;
+import org.apache.ambari.server.state.scheduler.Schedule;
+
+public class RequestScheduleResponse {
+  private Long id;
+  private String clusterName;
+  private String description;
+  private String status;
+  private Batch batch;
+  private Schedule schedule;
+  private String createUser;
+  private String createTime;
+  private String updateUser;
+  private String updateTime;
+
+  public RequestScheduleResponse(Long id, String clusterName,
+                                 String description, String status,
+                                 Batch batch, Schedule schedule,
+                                 String createUser, String createTime,
+                                 String updateUser, String updateTime) {
+    this.id = id;
+    this.clusterName = clusterName;
+    this.description = description;
+    this.status = status;
+    this.batch = batch;
+    this.schedule = schedule;
+    this.createUser = createUser;
+    this.createTime = createTime;
+    this.updateUser = updateUser;
+    this.updateTime = updateTime;
+  }
+
+  public Long getId() {
+    return id;
+  }
+
+  public void setId(Long id) {
+    this.id = id;
+  }
+
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public Batch getBatch() {
+    return batch;
+  }
+
+  public void setBatch(Batch batch) {
+    this.batch = batch;
+  }
+
+  public Schedule getSchedule() {
+    return schedule;
+  }
+
+  public void setSchedule(Schedule schedule) {
+    this.schedule = schedule;
+  }
+
+  public String getCreateUser() {
+    return createUser;
+  }
+
+  public void setCreateUser(String createUser) {
+    this.createUser = createUser;
+  }
+
+  public String getCreateTime() {
+    return createTime;
+  }
+
+  public void setCreateTime(String createTime) {
+    this.createTime = createTime;
+  }
+
+  public String getUpdateUser() {
+    return updateUser;
+  }
+
+  public void setUpdateUser(String updateUser) {
+    this.updateUser = updateUser;
+  }
+
+  public String getUpdateTime() {
+    return updateTime;
+  }
+
+  public void setUpdateTime(String updateTime) {
+    this.updateTime = updateTime;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/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 dc2575e..3ebabca 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
@@ -126,6 +126,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc
         return new RootServiceHostComponentResourceProvider(propertyIds, keyPropertyIds, managementController);
       case ConfigGroup:
         return new ConfigGroupResourceProvider(propertyIds, keyPropertyIds, managementController);
+      case RequestSchedule:
+        return new RequestScheduleResourceProvider(propertyIds, keyPropertyIds, managementController);
       default:
         throw new IllegalArgumentException("Unknown type " + type);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java
index 3afc4bf..af368cf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigGroupResourceProvider.java
@@ -343,7 +343,8 @@ public class ConfigGroupResourceProvider extends
       cluster = clusters.getCluster(request.getClusterName());
     } catch (ClusterNotFoundException e) {
       throw new ParentObjectNotFoundException(
-        "Attempted to add a service to a cluster which doesn't exist", e);
+        "Attempted to delete a config group from a cluster which doesn't " +
+          "exist", e);
     }
 
     configLogger.info("Deleting Config group, "
@@ -469,7 +470,7 @@ public class ConfigGroupResourceProvider extends
         cluster = clusters.getCluster(request.getClusterName());
       } catch (ClusterNotFoundException e) {
         throw new ParentObjectNotFoundException(
-          "Attempted to add a service to a cluster which doesn't exist", e);
+          "Attempted to add a config group to a cluster which doesn't exist", e);
       }
 
       if (request.getId() == null) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProvider.java
new file mode 100644
index 0000000..5119d25
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProvider.java
@@ -0,0 +1,584 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller.internal;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ClusterNotFoundException;
+import org.apache.ambari.server.ParentObjectNotFoundException;
+import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.RequestScheduleRequest;
+import org.apache.ambari.server.controller.RequestScheduleResponse;
+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.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.scheduler.Batch;
+import org.apache.ambari.server.state.scheduler.BatchRequest;
+import org.apache.ambari.server.state.scheduler.BatchSettings;
+import org.apache.ambari.server.state.scheduler.RequestExecution;
+import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
+import org.apache.ambari.server.state.scheduler.Schedule;
+import org.apache.ambari.server.utils.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class RequestScheduleResourceProvider extends AbstractControllerResourceProvider {
+  private static final Logger LOG = LoggerFactory.getLogger
+    (RequestScheduleResourceProvider.class);
+
+  protected static final String REQUEST_SCHEDULE_ID_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "id");
+  protected static final String REQUEST_SCHEDULE_CLUSTER_NAME_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "cluster_name");
+  protected static final String REQUEST_SCHEDULE_DESC_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "description");
+  protected static final String REQUEST_SCHEDULE_STATUS_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "status");
+  protected static final String REQUEST_SCHEDULE_BATCH_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "batch");
+  protected static final String REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "schedule");
+  protected static final String REQUEST_SCHEDULE_CREATE_USER_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "create_user");
+  protected static final String REQUEST_SCHEDULE_UPDATE_USER_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "update_user");
+  protected static final String REQUEST_SCHEDULE_CREATE_TIME_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "create_time");
+  protected static final String REQUEST_SCHEDULE_UPDATE_TIME_PROPERTY_ID =
+    PropertyHelper.getPropertyId("RequestSchedule", "update_time");
+
+  protected static final String REQUEST_SCHEDULE_BATCH_SEPARATION_PROPERTY_ID =
+    PropertyHelper.getPropertyId("batch_settings", "batch_separation_in_minutes");
+  protected static final String REQUEST_SCHEDULE_BATCH_TOLERATION_PROPERTY_ID =
+    PropertyHelper.getPropertyId("batch_settings", "task_failure_tolerance");
+  protected static final String REQUEST_SCHEDULE_BATCH_REQUESTS_PROPERTY_ID =
+    PropertyHelper.getPropertyId(null, "requests");
+
+  protected static final String BATCH_REQUEST_TYPE_PROPERTY_ID =
+    PropertyHelper.getPropertyId(null, "type");
+  protected static final String BATCH_REQUEST_URI_PROPERTY_ID =
+    PropertyHelper.getPropertyId(null, "uri");
+  protected static final String BATCH_REQUEST_ORDER_ID_PROPERTY_ID =
+    PropertyHelper.getPropertyId(null, "order_id");
+  protected static final String BATCH_REQUEST_BODY_PROPERTY_ID =
+    PropertyHelper.getPropertyId(null, RequestBodyParser.REQUEST_BLOB_TITLE);
+
+  protected static final String SCHEDULE_DAYS_OF_MONTH_PROPERTY_ID =
+    PropertyHelper.getPropertyId(REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID, "days_of_month");
+  protected static final String SCHEDULE_MINUTES_PROPERTY_ID =
+    PropertyHelper.getPropertyId(REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID, "minutes");
+  protected static final String SCHEDULE_HOURS_PROPERTY_ID =
+    PropertyHelper.getPropertyId(REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID, "hours");
+  protected static final String SCHEDULE_YEAR_PROPERTY_ID =
+    PropertyHelper.getPropertyId(REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID, "year");
+  protected static final String SCHEDULE_DAY_OF_WEEK_PROPERTY_ID =
+    PropertyHelper.getPropertyId(REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID, "day_of_week");
+  protected static final String SCHEDULE_MONTH_PROPERTY_ID =
+    PropertyHelper.getPropertyId(REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID, "month");
+  protected static final String SCHEDULE_START_TIME_PROPERTY_ID =
+    PropertyHelper.getPropertyId(REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID, "startTime");
+  protected static final String SCHEDULE_END_TIME_PROPERTY_ID =
+    PropertyHelper.getPropertyId(REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID, "endTime");
+
+  private static Set<String> pkPropertyIds = new HashSet<String>(Arrays
+    .asList(new String[]{ REQUEST_SCHEDULE_ID_PROPERTY_ID }));
+
+  /**
+   * Create a  new resource provider for the given management controller.
+   *
+   * @param propertyIds          the property ids
+   * @param keyPropertyIds       the key property ids
+   * @param managementController the management controller
+   */
+
+  protected RequestScheduleResourceProvider(Set<String> propertyIds,
+      Map<Resource.Type, String> keyPropertyIds,
+        AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  @Override
+  public RequestStatus createResources(Request request) throws SystemException,
+      UnsupportedPropertyException, ResourceAlreadyExistsException,
+      NoSuchParentResourceException {
+
+    final Set<RequestScheduleRequest> requests = new HashSet<RequestScheduleRequest>();
+
+    for (Map<String, Object> propertyMap : request.getProperties()) {
+      requests.add(getRequestScheduleRequest(propertyMap));
+    }
+
+    Set<RequestScheduleResponse> responses =
+      createResources(new Command<Set<RequestScheduleResponse>>() {
+      @Override
+      public Set<RequestScheduleResponse> invoke() throws AmbariException {
+        return createRequestSchedules(requests);
+      }
+    });
+
+    notifyCreate(Resource.Type.RequestSchedule, request);
+
+    Set<Resource> associatedResources = new HashSet<Resource>();
+    for (RequestScheduleResponse response : responses) {
+      Resource resource = new ResourceImpl(Resource.Type.RequestSchedule);
+      resource.setProperty(REQUEST_SCHEDULE_ID_PROPERTY_ID, response.getId());
+      associatedResources.add(resource);
+    }
+
+    return getRequestStatus(null, associatedResources);
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate) throws
+      SystemException, UnsupportedPropertyException, NoSuchResourceException,
+      NoSuchParentResourceException {
+
+    final Set<RequestScheduleRequest> requests = new HashSet<RequestScheduleRequest>();
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      requests.add(getRequestScheduleRequest(propertyMap));
+    }
+
+    Set<RequestScheduleResponse> responses =
+      getResources(new Command<Set<RequestScheduleResponse>>() {
+        @Override
+        public Set<RequestScheduleResponse> invoke() throws AmbariException {
+          return getRequestSchedules(requests);
+        }
+      });
+
+    Set<String>   requestedIds = getRequestPropertyIds(request, predicate);
+    Set<Resource> resources    = new HashSet<Resource>();
+
+    for (RequestScheduleResponse response : responses) {
+      Resource resource = new ResourceImpl(Resource.Type.RequestSchedule);
+
+      setResourceProperty(resource, REQUEST_SCHEDULE_ID_PROPERTY_ID,
+        response.getId(), requestedIds);
+      setResourceProperty(resource, REQUEST_SCHEDULE_CLUSTER_NAME_PROPERTY_ID,
+        response.getClusterName(), requestedIds);
+      setResourceProperty(resource, REQUEST_SCHEDULE_DESC_PROPERTY_ID,
+        response.getDescription(), requestedIds);
+      setResourceProperty(resource, REQUEST_SCHEDULE_STATUS_PROPERTY_ID,
+        response.getStatus(), requestedIds);
+      setResourceProperty(resource, REQUEST_SCHEDULE_BATCH_PROPERTY_ID,
+        response.getBatch(), requestedIds);
+      setResourceProperty(resource, REQUEST_SCHEDULE_SCHEDULE_PROPERTY_ID,
+        response.getSchedule(), requestedIds);
+      setResourceProperty(resource, REQUEST_SCHEDULE_CREATE_USER_PROPERTY_ID,
+        response.getCreateUser(), requestedIds);
+      setResourceProperty(resource, REQUEST_SCHEDULE_CREATE_TIME_PROPERTY_ID,
+        response.getCreateTime(), requestedIds);
+      setResourceProperty(resource, REQUEST_SCHEDULE_UPDATE_USER_PROPERTY_ID,
+        response.getUpdateUser(), requestedIds);
+      setResourceProperty(resource, REQUEST_SCHEDULE_UPDATE_TIME_PROPERTY_ID,
+        response.getUpdateTime(), requestedIds);
+
+      resources.add(resource);
+    }
+
+    return resources;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<RequestScheduleRequest> requests = new
+      HashSet<RequestScheduleRequest>();
+
+    Iterator<Map<String,Object>> iterator = request.getProperties().iterator();
+    if (iterator.hasNext()) {
+      for (Map<String, Object> propertyMap : getPropertyMaps(iterator.next(), predicate)) {
+        requests.add(getRequestScheduleRequest(propertyMap));
+      }
+
+      modifyResources(new Command<Void>() {
+        @Override
+        public Void invoke() throws AmbariException {
+          updateRequestSchedule(requests);
+          return null;
+        }
+      });
+    }
+
+    notifyUpdate(Resource.Type.RequestSchedule, request, predicate);
+
+    return getRequestStatus(null);
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate) throws
+      SystemException, UnsupportedPropertyException, NoSuchResourceException,
+      NoSuchParentResourceException {
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      final RequestScheduleRequest requestScheduleRequest =
+        getRequestScheduleRequest(propertyMap);
+
+      modifyResources(new Command<Void>() {
+        @Override
+        public Void invoke() throws AmbariException {
+          deleteRequestSchedule(requestScheduleRequest);
+          return null;
+        }
+      });
+    }
+
+    notifyDelete(Resource.Type.RequestSchedule, predicate);
+
+    return getRequestStatus(null);
+  }
+
+  private synchronized void deleteRequestSchedule(RequestScheduleRequest request)
+    throws AmbariException {
+
+    if (request.getId() == null) {
+      throw new AmbariException("Id is a required field.");
+    }
+
+    Clusters clusters = getManagementController().getClusters();
+
+    Cluster cluster;
+    try {
+      cluster = clusters.getCluster(request.getClusterName());
+    } catch (ClusterNotFoundException e) {
+      throw new ParentObjectNotFoundException(
+        "Attempted to delete a request schedule from a cluster which doesn't "
+          + "exist", e);
+    }
+
+    LOG.info("Deleting Request Schedule "
+      + ", clusterName = " + request.getClusterName()
+      + ", id = " + request.getId());
+
+    cluster.deleteRequestExecution(request.getId());
+  }
+
+  private synchronized void updateRequestSchedule
+    (Set<RequestScheduleRequest> requests) throws AmbariException {
+
+    if (requests.isEmpty()) {
+      LOG.warn("Received an empty requests set");
+      return;
+    }
+
+    Clusters clusters = getManagementController().getClusters();
+
+    for (RequestScheduleRequest request : requests) {
+
+      validateRequest(request);
+
+      Cluster cluster;
+      try {
+        cluster = clusters.getCluster(request.getClusterName());
+      } catch (ClusterNotFoundException e) {
+        throw new ParentObjectNotFoundException(
+          "Attempted to add a request schedule to a cluster which doesn't " +
+            "exist", e);
+      }
+
+      if (request.getId() == null) {
+        throw new AmbariException("Id is a required parameter.");
+      }
+
+      RequestExecution requestExecution =
+        cluster.getAllRequestExecutions().get(request.getId());
+
+      if (requestExecution == null) {
+        throw new AmbariException("Request Schedule not found "
+          + ", clusterName = " + request.getClusterName()
+          + ", description = " + request.getDescription()
+          + ", id = " + request.getId());
+      }
+
+      String username = getManagementController().getAuthName();
+
+      requestExecution.setBatch(request.getBatch());
+      requestExecution.setDescription(request.getDescription());
+      requestExecution.setSchedule(request.getSchedule());
+      if (request.getStatus() != null && isValidRequestScheduleStatus
+          (request.getStatus())) {
+        requestExecution.setStatus(RequestExecution.Status.valueOf(request.getStatus()));
+      }
+      requestExecution.setUpdateUser(username);
+
+      LOG.info("Persisting updated Request Schedule "
+        + ", clusterName = " + request.getClusterName()
+        + ", description = " + request.getDescription()
+        + ", user = " + username);
+
+      requestExecution.persist();
+    }
+  }
+
+  private synchronized Set<RequestScheduleResponse> createRequestSchedules
+    (Set<RequestScheduleRequest> requests) throws AmbariException {
+
+    if (requests.isEmpty()) {
+      LOG.warn("Received an empty requests set");
+      return null;
+    }
+
+    Set<RequestScheduleResponse> responses = new
+      HashSet<RequestScheduleResponse>();
+
+    Clusters clusters = getManagementController().getClusters();
+    RequestExecutionFactory requestExecutionFactory =
+      getManagementController().getRequestExecutionFactory();
+
+    for (RequestScheduleRequest request : requests) {
+
+      validateRequest(request);
+
+      Cluster cluster;
+      try {
+        cluster = clusters.getCluster(request.getClusterName());
+      } catch (ClusterNotFoundException e) {
+        throw new ParentObjectNotFoundException(
+          "Attempted to add a request schedule to a cluster which doesn't " +
+            "exist", e);
+      }
+
+      String username = getManagementController().getAuthName();
+
+      RequestExecution requestExecution = requestExecutionFactory.createNew
+        (cluster, request.getBatch(), request.getSchedule());
+
+      requestExecution.setCreateUser(username);
+      requestExecution.setUpdateUser(username);
+
+      LOG.info("Persisting new Request Schedule "
+        + ", clusterName = " + request.getClusterName()
+        + ", description = " + request.getDescription()
+        + ", user = " + username);
+
+      requestExecution.persist();
+      cluster.addRequestExecution(requestExecution);
+
+      RequestScheduleResponse response = new RequestScheduleResponse
+        (requestExecution.getId(), requestExecution.getClusterName(),
+          requestExecution.getDescription(), requestExecution.getStatus(),
+          requestExecution.getBatch(), request.getSchedule(),
+          requestExecution.getCreateUser(), requestExecution.getCreateTime(),
+          requestExecution.getUpdateUser(), requestExecution.getUpdateTime());
+
+      responses.add(response);
+    }
+
+    return responses;
+  }
+
+  private void validateRequest(RequestScheduleRequest request) {
+    if (request.getClusterName() == null) {
+      throw new IllegalArgumentException("Cluster name is required.");
+    }
+  }
+
+  private synchronized Set<RequestScheduleResponse> getRequestSchedules
+    (Set<RequestScheduleRequest> requests) throws AmbariException {
+
+    Set<RequestScheduleResponse> responses = new
+      HashSet<RequestScheduleResponse>();
+
+    if (requests != null) {
+      for (RequestScheduleRequest request : requests) {
+        if (request.getClusterName() == null) {
+          LOG.warn("Cluster name is a required field.");
+          continue;
+        }
+
+        Cluster cluster = getManagementController().getClusters().getCluster
+          (request.getClusterName());
+
+        Map<Long, RequestExecution> allRequestExecutions =
+          cluster.getAllRequestExecutions();
+
+        // Find by id
+        if (request.getId() != null) {
+          RequestExecution requestExecution = allRequestExecutions.get
+            (request.getId());
+          if (requestExecution != null) {
+            responses.add(requestExecution.convertToResponse());
+          }
+          continue;
+        }
+        // Find by status
+        if (request.getStatus() != null) {
+          for (RequestExecution requestExecution : allRequestExecutions.values()) {
+            if (requestExecution.getStatus().equals(request.getStatus())) {
+              responses.add(requestExecution.convertToResponse());
+            }
+          }
+          continue;
+        }
+        // TODO: Find by status of Batch Request(s) and start time greater than requested time
+
+        // Select all
+        for (RequestExecution requestExecution : allRequestExecutions.values()) {
+          responses.add(requestExecution.convertToResponse());
+        }
+      }
+    }
+
+    return responses;
+  }
+
+  private boolean isValidRequestScheduleStatus(String giveStatus) {
+    for (RequestExecution.Status status : RequestExecution.Status.values()) {
+      if (status.name().equalsIgnoreCase(giveStatus)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private RequestScheduleRequest getRequestScheduleRequest(Map<String, Object> properties) {
+    Object idObj = properties.get(REQUEST_SCHEDULE_ID_PROPERTY_ID);
+    Long id = null;
+    if (idObj != null)  {
+      id = idObj instanceof Long ? (Long) idObj :
+        Long.parseLong((String) idObj);
+    }
+
+    RequestScheduleRequest requestScheduleRequest = new RequestScheduleRequest(
+      id,
+      (String) properties.get(REQUEST_SCHEDULE_CLUSTER_NAME_PROPERTY_ID),
+      (String) properties.get(REQUEST_SCHEDULE_DESC_PROPERTY_ID),
+      (String) properties.get(REQUEST_SCHEDULE_STATUS_PROPERTY_ID),
+      null,
+      null);
+
+    Batch batch = new Batch();
+    BatchSettings batchSettings = new BatchSettings();
+    List<BatchRequest> batchRequests = new ArrayList<BatchRequest>();
+
+    Object batchObject = properties.get(REQUEST_SCHEDULE_BATCH_PROPERTY_ID);
+    if (batchObject != null && batchObject instanceof HashSet<?>) {
+      try {
+        HashSet<Map<String, Object>> batchMap = (HashSet<Map<String, Object>>) batchObject;
+
+        for (Map<String, Object> batchEntry : batchMap) {
+          if (batchEntry != null) {
+            for (Map.Entry<String, Object> batchMapEntry : batchEntry.entrySet()) {
+              if (batchMapEntry.getKey().equals
+                  (REQUEST_SCHEDULE_BATCH_TOLERATION_PROPERTY_ID)) {
+                batchSettings.setTaskFailureToleranceLimit(Integer.valueOf
+                  ((String) batchMapEntry.getValue()));
+              } else if (batchMapEntry.getKey().equals
+                  (REQUEST_SCHEDULE_BATCH_SEPARATION_PROPERTY_ID)) {
+                batchSettings.setBatchSeparationInMinutes(Integer.valueOf
+                  ((String) batchMapEntry.getValue()));
+              } else if (batchMapEntry.getKey().equals
+                  (REQUEST_SCHEDULE_BATCH_REQUESTS_PROPERTY_ID)) {
+                HashSet<Map<String, Object>> requestSet =
+                  (HashSet<Map<String, Object>>) batchMapEntry.getValue();
+
+                for (Map<String, Object> requestEntry : requestSet) {
+                  if (requestEntry != null) {
+                    BatchRequest batchRequest = new BatchRequest();
+                    for (Map.Entry<String, Object> requestMapEntry :
+                        requestEntry.entrySet()) {
+                      if (requestMapEntry.getKey()
+                                 .equals(BATCH_REQUEST_TYPE_PROPERTY_ID)) {
+                        batchRequest.setType(BatchRequest.Type.valueOf
+                          ((String) requestMapEntry.getValue()));
+                      } else if (requestMapEntry.getKey()
+                                 .equals(BATCH_REQUEST_URI_PROPERTY_ID)) {
+                        batchRequest.setUri(
+                          (String) requestMapEntry.getValue());
+                      } else if (requestMapEntry.getKey()
+                                .equals(BATCH_REQUEST_ORDER_ID_PROPERTY_ID)) {
+                        batchRequest.setOrderId(Long.parseLong(
+                          (String) requestMapEntry.getValue()));
+                      } else if (requestMapEntry.getKey()
+                                .equals(BATCH_REQUEST_BODY_PROPERTY_ID)) {
+                        batchRequest.setBody(
+                          (String) requestMapEntry.getValue());
+                      }
+                    }
+                    batchRequests.add(batchRequest);
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        batch.getBatchRequests().addAll(batchRequests);
+        batch.setBatchSettings(batchSettings);
+
+      } catch (Exception e) {
+        LOG.warn("Request Schedule batch json is unparseable. " +
+          batchObject, e);
+      }
+    }
+
+    requestScheduleRequest.setBatch(batch);
+
+    Schedule schedule = new Schedule();
+    for (Map.Entry<String, Object> propertyEntry : properties.entrySet()) {
+      if (propertyEntry.getKey().equals(SCHEDULE_DAY_OF_WEEK_PROPERTY_ID)) {
+        schedule.setDayOfWeek((String) propertyEntry.getValue());
+      } else if (propertyEntry.getKey().equals(SCHEDULE_DAYS_OF_MONTH_PROPERTY_ID)) {
+        schedule.setDaysOfMonth((String) propertyEntry.getValue());
+      } else if (propertyEntry.getKey().equals(SCHEDULE_END_TIME_PROPERTY_ID)) {
+        schedule.setEndTime((String) propertyEntry.getValue());
+      } else if (propertyEntry.getKey().equals(SCHEDULE_HOURS_PROPERTY_ID)) {
+        schedule.setHours((String) propertyEntry.getValue());
+      } else if (propertyEntry.getKey().equals(SCHEDULE_MINUTES_PROPERTY_ID)) {
+        schedule.setMinutes((String) propertyEntry.getValue());
+      } else if (propertyEntry.getKey().equals(SCHEDULE_MONTH_PROPERTY_ID)) {
+        schedule.setMonth((String) propertyEntry.getValue());
+      } else if (propertyEntry.getKey().equals(SCHEDULE_START_TIME_PROPERTY_ID)) {
+        schedule.setStartTime((String) propertyEntry.getValue());
+      } else if (propertyEntry.getKey().equals(SCHEDULE_YEAR_PROPERTY_ID)) {
+        schedule.setYear((String) propertyEntry.getValue());
+      }
+    }
+
+    if (!schedule.isEmpty()) {
+      requestScheduleRequest.setSchedule(schedule);
+    }
+
+    return requestScheduleRequest;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/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 d4af369..2081766 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
@@ -79,6 +79,7 @@ public interface Resource {
     ConfigGroup,
     Action,
     Request,
+    RequestSchedule,
     Task,
     User,
     Stack,

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleBatchHostDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleBatchHostDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleBatchHostDAO.java
deleted file mode 100644
index feabf9d..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleBatchHostDAO.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.orm.dao;
-
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.google.inject.persist.Transactional;
-import org.apache.ambari.server.orm.entities.RequestScheduleBatchHostEntity;
-import org.apache.ambari.server.orm.entities.RequestScheduleBatchHostEntityPK;
-import javax.persistence.EntityManager;
-import javax.persistence.NoResultException;
-import javax.persistence.TypedQuery;
-import java.util.List;
-
-@Singleton
-public class RequestScheduleBatchHostDAO {
-  @Inject
-  Provider<EntityManager> entityManagerProvider;
-  @Inject
-  DaoUtils daoUtils;
-
-  @Transactional
-  public RequestScheduleBatchHostEntity findByPK
-    (RequestScheduleBatchHostEntityPK requestScheduleBatchHostEntityPK) {
-    return entityManagerProvider.get().find(RequestScheduleBatchHostEntity
-      .class, requestScheduleBatchHostEntityPK);
-  }
-
-  @Transactional
-  public List<RequestScheduleBatchHostEntity> findBySchedule(Long scheduleId) {
-    TypedQuery<RequestScheduleBatchHostEntity> query = entityManagerProvider
-      .get().createNamedQuery("batchHostsBySchedule",
-        RequestScheduleBatchHostEntity.class);
-
-    query.setParameter("id", scheduleId);
-    try {
-      return query.getResultList();
-    } catch (NoResultException ignored) {
-    }
-    return null;
-  }
-
-  @Transactional
-  public void create(RequestScheduleBatchHostEntity batchHostEntity) {
-    entityManagerProvider.get().persist(batchHostEntity);
-  }
-
-  @Transactional
-  public RequestScheduleBatchHostEntity merge(RequestScheduleBatchHostEntity batchHostEntity) {
-    return entityManagerProvider.get().merge(batchHostEntity);
-  }
-
-  @Transactional
-  public void refresh(RequestScheduleBatchHostEntity batchHostEntity) {
-    entityManagerProvider.get().refresh(batchHostEntity);
-  }
-
-  @Transactional
-  public void remove(RequestScheduleBatchHostEntity batchHostEntity) {
-    entityManagerProvider.get().remove(batchHostEntity);
-  }
-
-  @Transactional
-  public void removeBySchedule(Long scheduleId) {
-    TypedQuery<Long> query = entityManagerProvider.get().createQuery(
-      "DELETE FROM RequestScheduleBatchHostEntity batchHosts WHERE " +
-        "batchHosts.scheduleId = ?1", Long.class);
-
-    daoUtils.executeUpdate(query, scheduleId);
-    entityManagerProvider.get().flush();
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleBatchRequestDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleBatchRequestDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleBatchRequestDAO.java
new file mode 100644
index 0000000..6a25b65
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleBatchRequestDAO.java
@@ -0,0 +1,99 @@
+/**
+ * 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.orm.dao;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.orm.entities.RequestScheduleBatchRequestEntity;
+import org.apache.ambari.server.orm.entities.RequestScheduleBatchRequestEntityPK;
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+import java.util.List;
+
+@Singleton
+public class RequestScheduleBatchRequestDAO {
+  @Inject
+  Provider<EntityManager> entityManagerProvider;
+  @Inject
+  DaoUtils daoUtils;
+
+  @Transactional
+  public RequestScheduleBatchRequestEntity findByPk
+    (RequestScheduleBatchRequestEntityPK batchRequestEntity) {
+
+    return entityManagerProvider.get()
+      .find(RequestScheduleBatchRequestEntity.class, batchRequestEntity);
+  }
+
+  @Transactional
+  public List<RequestScheduleBatchRequestEntity> findByScheduleId(Long scheduleId) {
+    TypedQuery<RequestScheduleBatchRequestEntity> query = entityManagerProvider
+      .get().createNamedQuery("findByScheduleId",
+        RequestScheduleBatchRequestEntity.class);
+
+    query.setParameter("id", scheduleId);
+    try {
+      return query.getResultList();
+    } catch (NoResultException ignored) {
+    }
+    return null;
+  }
+
+  @Transactional
+  public void create(RequestScheduleBatchRequestEntity batchRequestEntity) {
+    entityManagerProvider.get().persist(batchRequestEntity);
+  }
+
+  @Transactional
+  public RequestScheduleBatchRequestEntity merge
+    (RequestScheduleBatchRequestEntity batchRequestEntity) {
+
+    return entityManagerProvider.get().merge(batchRequestEntity);
+  }
+
+  @Transactional
+  public void refresh(RequestScheduleBatchRequestEntity batchRequestEntity) {
+    entityManagerProvider.get().refresh(batchRequestEntity);
+  }
+
+  @Transactional
+  public void remove(RequestScheduleBatchRequestEntity batchRequestEntity) {
+    entityManagerProvider.get().remove(merge(batchRequestEntity));
+  }
+
+  @Transactional
+  public void removeByPk(RequestScheduleBatchRequestEntityPK
+                             batchRequestEntityPK) {
+    entityManagerProvider.get().remove(findByPk(batchRequestEntityPK));
+  }
+
+  @Transactional
+  public void removeByScheduleId(Long scheduleId) {
+    TypedQuery<Long> query = entityManagerProvider.get().createQuery
+      ("DELETE FROM RequestScheduleBatchRequestEntity batchreq WHERE " +
+        "batchreq.scheduleId = ?1", Long.class);
+
+    daoUtils.executeUpdate(query, scheduleId);
+    // Flush to current transaction required in order to avoid Eclipse link
+    // from re-ordering delete
+    entityManagerProvider.get().flush();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleDAO.java
index 0c9b75e..e0b1377 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestScheduleDAO.java
@@ -73,7 +73,7 @@ public class RequestScheduleDAO {
 
   @Transactional
   public void remove(RequestScheduleEntity requestScheduleEntity) {
-    entityManagerProvider.get().remove(requestScheduleEntity);
+    entityManagerProvider.get().remove(merge(requestScheduleEntity));
   }
 
   @Transactional

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleBatchHostEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleBatchHostEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleBatchHostEntity.java
deleted file mode 100644
index 5942cf5..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleBatchHostEntity.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.orm.entities;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.JoinColumns;
-import javax.persistence.ManyToOne;
-import javax.persistence.NamedQueries;
-import javax.persistence.NamedQuery;
-import javax.persistence.Table;
-
-@Table(name = "requestschedulebatchhost")
-@Entity
-@NamedQueries({
-  @NamedQuery(name = "batchHostsBySchedule", query =
-    "SELECT batchHost FROM RequestScheduleBatchHostEntity batchHost " +
-      "WHERE batchHost.scheduleId=:id")
-})
-public class RequestScheduleBatchHostEntity {
-
-  @Id
-  @Column(name = "schedule_id", nullable = false, insertable = true, updatable = true)
-  private Long scheduleId;
-
-  @Id
-  @Column(name = "batch_id", nullable = false, insertable = true, updatable = true)
-  private Long batchId;
-
-  @Id
-  @Column(name = "host_name", nullable = false, insertable = true, updatable = true)
-  private String hostName;
-
-  @Column(name = "batch_name")
-  private String batchName;
-
-  @ManyToOne
-  @JoinColumns({
-    @JoinColumn(name = "host_name", referencedColumnName = "host_name", nullable = false, insertable = false, updatable = false) })
-  private HostEntity hostEntity;
-
-  @ManyToOne
-  @JoinColumns({
-    @JoinColumn(name = "schedule_id", referencedColumnName = "schedule_id", nullable = false, insertable = false, updatable = false) })
-  private RequestScheduleEntity requestScheduleEntity;
-
-  public Long getScheduleId() {
-    return scheduleId;
-  }
-
-  public void setScheduleId(Long scheduleId) {
-    this.scheduleId = scheduleId;
-  }
-
-  public Long getBatchId() {
-    return batchId;
-  }
-
-  public void setBatchId(Long batchId) {
-    this.batchId = batchId;
-  }
-
-  public String getHostName() {
-    return hostName;
-  }
-
-  public void setHostName(String hostName) {
-    this.hostName = hostName;
-  }
-
-  public String getBatchName() {
-    return batchName;
-  }
-
-  public void setBatchName(String batchName) {
-    this.batchName = batchName;
-  }
-
-  public HostEntity getHostEntity() {
-    return hostEntity;
-  }
-
-  public void setHostEntity(HostEntity hostEntity) {
-    this.hostEntity = hostEntity;
-  }
-
-  public RequestScheduleEntity getRequestScheduleEntity() {
-    return requestScheduleEntity;
-  }
-
-  public void setRequestScheduleEntity(RequestScheduleEntity requestScheduleEntity) {
-    this.requestScheduleEntity = requestScheduleEntity;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    RequestScheduleBatchHostEntity that = (RequestScheduleBatchHostEntity) o;
-
-    if (!batchId.equals(that.batchId)) return false;
-    if (!hostName.equals(that.hostName)) return false;
-    if (!scheduleId.equals(that.scheduleId)) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = scheduleId.hashCode();
-    result = 31 * result + batchId.hashCode();
-    result = 31 * result + hostName.hashCode();
-    return result;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dcea372/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleBatchHostEntityPK.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleBatchHostEntityPK.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleBatchHostEntityPK.java
deleted file mode 100644
index 01d576d..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleBatchHostEntityPK.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.orm.entities;
-
-
-import javax.persistence.Column;
-import javax.persistence.Id;
-import java.io.Serializable;
-
-public class RequestScheduleBatchHostEntityPK implements Serializable {
-  private Long scheduleId;
-  private Long  batchId;
-  private String hostName;
-
-  @Id
-  @Column(name = "schedule_id", nullable = false, insertable = true, updatable = true)
-  public Long getScheduleId() {
-    return scheduleId;
-  }
-
-  public void setScheduleId(Long scheduleId) {
-    this.scheduleId = scheduleId;
-  }
-
-  @Id
-  @Column(name = "batch_id", nullable = false, insertable = true, updatable = true)
-  public Long getBatchId() {
-    return batchId;
-  }
-
-  public void setBatchId(Long batchId) {
-    this.batchId = batchId;
-  }
-
-  @Id
-  @Column(name = "host_name", nullable = false, insertable = true, updatable = true)
-  public String getHostName() {
-    return hostName;
-  }
-
-  public void setHostName(String hostName) {
-    this.hostName = hostName;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    RequestScheduleBatchHostEntityPK that = (RequestScheduleBatchHostEntityPK) o;
-
-    if (!batchId.equals(that.batchId)) return false;
-    if (!hostName.equals(that.hostName)) return false;
-    if (!scheduleId.equals(that.scheduleId)) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = scheduleId.hashCode();
-    result = 31 * result + batchId.hashCode();
-    result = 31 * result + hostName.hashCode();
-    return result;
-  }
-}


Mime
View raw message