LENS-1195 : Add state machine for scheduler service

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

Branch: refs/heads/current-release-line
Commit: 9e61e51064ad0f15e511fea08a0eba63771715d8
Parents: a736f46
Author: Ajay Yadava <[email protected]>
Authored: Thu Jul 7 16:29:32 2016 +0530
Committer: Amareshwari Sriramadasu <[email protected]>
Committed: Thu Jul 7 16:29:32 2016 +0530

----------------------------------------------------------------------
 .../lens/api/scheduler/SchedulerJobInfo.java    |   2 +-
 .../api/scheduler/SchedulerJobInstanceInfo.java |   2 +-
 .../scheduler/SchedulerJobInstanceState.java    |  23 ---
 .../scheduler/SchedulerJobInstanceStatus.java   |  23 +++
 .../lens/api/scheduler/SchedulerJobState.java   |  23 ---
 .../lens/api/scheduler/SchedulerJobStatus.java  |  23 +++
 .../error/InvalidStateTransitionException.java  |  46 +++++
 .../lens/server/api/scheduler/StateMachine.java |  35 ++++
 .../lens/server/scheduler/SchedulerDAO.java     |  12 +-
 .../state/SchedulerJobInstanceState.java        | 193 +++++++++++++++++++
 .../scheduler/state/SchedulerJobState.java      | 150 ++++++++++++++
 .../lens/server/scheduler/SchedulerDAOTest.java |  20 +-
 12 files changed, 488 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInfo.java
----------------------------------------------------------------------
diff --git 
a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInfo.java 
b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInfo.java
index 0561834..7d06689 100644
--- a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInfo.java
+++ b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInfo.java
@@ -52,7 +52,7 @@ public class SchedulerJobInfo {
    * @param state state of this job.
    * @return current state of this job
    */
-  private SchedulerJobState state;
+  private SchedulerJobStatus state;
 
   /**
    * @param createdOn time to be set as createdOn.

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceInfo.java
----------------------------------------------------------------------
diff --git 
a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceInfo.java
 
b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceInfo.java
index cb0d938..8158576 100644
--- 
a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceInfo.java
+++ 
b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceInfo.java
@@ -76,7 +76,7 @@ public class SchedulerJobInstanceInfo {
    * @param state state to be set.
    * @return state of this instance.
    */
-  private SchedulerJobInstanceState state;
+  private SchedulerJobInstanceStatus state;
 
   /**
    * @param createdOn time to be set as created_on time for the instance.

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceState.java
----------------------------------------------------------------------
diff --git 
a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceState.java
 
b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceState.java
deleted file mode 100644
index c66add6..0000000
--- 
a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceState.java
+++ /dev/null
@@ -1,23 +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
- * <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.lens.api.scheduler;
-
-public enum SchedulerJobInstanceState {
-  WAITING, LAUNCHED, FAILED, SUCCEEDED, KILLED, TIMEOUT
-}

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceStatus.java
----------------------------------------------------------------------
diff --git 
a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceStatus.java
 
b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceStatus.java
new file mode 100644
index 0000000..85e7e85
--- /dev/null
+++ 
b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobInstanceStatus.java
@@ -0,0 +1,23 @@
+/**
+ * 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.lens.api.scheduler;
+
+public enum SchedulerJobInstanceStatus {
+  WAITING, TIMED_OUT, LAUNCHED, RUNNING, FAILED, SUCCEEDED, KILLED,
+}

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobState.java
----------------------------------------------------------------------
diff --git 
a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobState.java 
b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobState.java
deleted file mode 100644
index 82c55c8..0000000
--- 
a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobState.java
+++ /dev/null
@@ -1,23 +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
- * <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.lens.api.scheduler;
-
-public enum SchedulerJobState {
-  NEW, SCHEDULED, EXPIRED, PAUSED
-}

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobStatus.java
----------------------------------------------------------------------
diff --git 
a/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobStatus.java 
b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobStatus.java
new file mode 100644
index 0000000..aaf403c
--- /dev/null
+++ 
b/lens-api/src/main/java/org/apache/lens/api/scheduler/SchedulerJobStatus.java
@@ -0,0 +1,23 @@
+/**
+ * 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.lens.api.scheduler;
+
+public enum SchedulerJobStatus {
+  NEW, SCHEDULED, SUSPENDED, EXPIRED, DELETED
+}

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-server-api/src/main/java/org/apache/lens/server/api/error/InvalidStateTransitionException.java
----------------------------------------------------------------------
diff --git 
a/lens-server-api/src/main/java/org/apache/lens/server/api/error/InvalidStateTransitionException.java
 
b/lens-server-api/src/main/java/org/apache/lens/server/api/error/InvalidStateTransitionException.java
new file mode 100644
index 0000000..5882151
--- /dev/null
+++ 
b/lens-server-api/src/main/java/org/apache/lens/server/api/error/InvalidStateTransitionException.java
@@ -0,0 +1,46 @@
+/**
+ * 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.lens.server.api.error;
+
+/**
+ * Exception thrown during state transition of jobs and job instances.
+ */
+public class InvalidStateTransitionException extends LensException {
+  /**
+   * @param e Exception
+   */
+  public InvalidStateTransitionException(Throwable e) {
+    super(e);
+  }
+
+  /**
+   * @param message - custom exception message
+   * @param e
+   */
+  public InvalidStateTransitionException(String message, Throwable e) {
+    super(message, e);
+  }
+
+  /**
+   * @param message - custom exception message
+   */
+  public InvalidStateTransitionException(String message) {
+    super(message);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-server-api/src/main/java/org/apache/lens/server/api/scheduler/StateMachine.java
----------------------------------------------------------------------
diff --git 
a/lens-server-api/src/main/java/org/apache/lens/server/api/scheduler/StateMachine.java
 
b/lens-server-api/src/main/java/org/apache/lens/server/api/scheduler/StateMachine.java
new file mode 100644
index 0000000..ba6a0a2
--- /dev/null
+++ 
b/lens-server-api/src/main/java/org/apache/lens/server/api/scheduler/StateMachine.java
@@ -0,0 +1,35 @@
+/**
+ * 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.lens.server.api.scheduler;
+
+
+import org.apache.lens.server.api.error.InvalidStateTransitionException;
+
+/**
+ * Interface to be implemented by a class that handles state transitions.
+ */
+public interface StateMachine<STATE extends Enum<STATE>, EVENT extends 
Enum<EVENT>> {
+
+  /**
+   * @param event
+   * @return The state that the machine enters into as a result of the event.
+   * @throws InvalidStateTransitionException
+   */
+  STATE nextTransition(EVENT event) throws InvalidStateTransitionException;
+
+}

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-server/src/main/java/org/apache/lens/server/scheduler/SchedulerDAO.java
----------------------------------------------------------------------
diff --git 
a/lens-server/src/main/java/org/apache/lens/server/scheduler/SchedulerDAO.java 
b/lens-server/src/main/java/org/apache/lens/server/scheduler/SchedulerDAO.java
index 8179fef..bf99fde 100644
--- 
a/lens-server/src/main/java/org/apache/lens/server/scheduler/SchedulerDAO.java
+++ 
b/lens-server/src/main/java/org/apache/lens/server/scheduler/SchedulerDAO.java
@@ -120,7 +120,7 @@ public class SchedulerDAO {
    * @param id : Job handle id.
    * @return SchedulerJobState of the job.
    */
-  public SchedulerJobState getJobState(SchedulerJobHandle id) {
+  public SchedulerJobStatus getJobState(SchedulerJobHandle id) {
     try {
       return store.getJobState(id.getHandleIdString());
     } catch (SQLException e) {
@@ -223,7 +223,7 @@ public class SchedulerDAO {
    * @param endTime   : Created on should be less than the end time.
    * @return List of Job handles
    */
-  public List<SchedulerJobHandle> getJobs(String username, SchedulerJobState 
state, Long startTime,
+  public List<SchedulerJobHandle> getJobs(String username, SchedulerJobStatus 
state, Long startTime,
       Long endTime) {
     try {
       return store.getJobs(username, state == null ? null : state.name(), 
startTime, endTime);
@@ -341,7 +341,7 @@ public class SchedulerDAO {
         String state = (String) jobInfo[3];
         long createdOn = (Long) jobInfo[4];
         long modifiedOn = (Long) jobInfo[5];
-        return new SchedulerJobInfo(id, xJob, userName, 
SchedulerJobState.valueOf(state), createdOn, modifiedOn);
+        return new SchedulerJobInfo(id, xJob, userName, 
SchedulerJobStatus.valueOf(state), createdOn, modifiedOn);
       }
     }
 
@@ -369,13 +369,13 @@ public class SchedulerDAO {
      * @return SchedulerJobState
      * @throws SQLException
      */
-    public SchedulerJobState getJobState(String id) throws SQLException {
+    public SchedulerJobStatus getJobState(String id) throws SQLException {
       String fetchSQL = "SELECT " + COLUMN_STATE + " FROM " + JOB_TABLE + " 
WHERE " + COLUMN_ID + "=?";
       List<Object[]> result = runner.query(fetchSQL, multipleRowsHandler, id);
       if (result.size() == 0) {
         return null;
       } else {
-        return SchedulerJobState.valueOf((String) result.get(0)[0]);
+        return SchedulerJobStatus.valueOf((String) result.get(0)[0]);
       }
     }
 
@@ -468,7 +468,7 @@ public class SchedulerDAO {
         long endtime = (Long) instanceInfo[4];
         String resultPath = (String) instanceInfo[5];
         String query = (String) instanceInfo[6];
-        SchedulerJobInstanceState state = 
SchedulerJobInstanceState.valueOf((String) instanceInfo[7]);
+        SchedulerJobInstanceStatus state = 
SchedulerJobInstanceStatus.valueOf((String) instanceInfo[7]);
         long createdOn = (Long) instanceInfo[8];
         return new SchedulerJobInstanceInfo(id, jobId, sessionHandle, 
starttime, endtime, resultPath, query, state,
             createdOn);

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-server/src/main/java/org/apache/lens/server/scheduler/state/SchedulerJobInstanceState.java
----------------------------------------------------------------------
diff --git 
a/lens-server/src/main/java/org/apache/lens/server/scheduler/state/SchedulerJobInstanceState.java
 
b/lens-server/src/main/java/org/apache/lens/server/scheduler/state/SchedulerJobInstanceState.java
new file mode 100644
index 0000000..95057e4
--- /dev/null
+++ 
b/lens-server/src/main/java/org/apache/lens/server/scheduler/state/SchedulerJobInstanceState.java
@@ -0,0 +1,193 @@
+/**
+ * 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.lens.server.scheduler.state;
+
+import org.apache.lens.api.scheduler.SchedulerJobInstanceStatus;
+import org.apache.lens.server.api.error.InvalidStateTransitionException;
+import org.apache.lens.server.api.scheduler.StateMachine;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * State machine for transitions on Scheduler Jobs.
+ */
+public class SchedulerJobInstanceState {
+
+  public SchedulerJobInstanceState(SchedulerJobInstanceStatus status) {
+    this.currentStatus = status;
+  }
+
+  public SchedulerJobInstanceState() {
+    this.currentStatus = INITIAL_STATUS;
+  }
+
+  @Getter @Setter
+  private SchedulerJobInstanceStatus currentStatus;
+
+  private static final SchedulerJobInstanceStatus INITIAL_STATUS = 
SchedulerJobInstanceStatus.WAITING;
+
+  public SchedulerJobInstanceStatus nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+    STATE currentState = STATE.valueOf(currentStatus.name());
+    return 
SchedulerJobInstanceStatus.valueOf(currentState.nextTransition(event).name());
+  }
+
+  public enum STATE implements StateMachine<STATE, EVENT> {
+    // repeating same operation will return the same state to ensure 
idempotent behavior.
+    WAITING {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_CREATION:
+          return this;
+        case ON_CONDITIONS_MET:
+          return STATE.LAUNCHED;
+        case ON_TIME_OUT:
+          return STATE.TIMED_OUT;
+        case ON_RUN:
+          return STATE.RUNNING;
+        case ON_SUCCESS:
+          return STATE.SUCCEEDED;
+        case ON_FAILURE:
+          return STATE.FAILED;
+        case ON_KILL:
+          return STATE.KILLED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+    LAUNCHED {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_CONDITIONS_MET:
+          return this;
+        case ON_RUN:
+          return STATE.RUNNING;
+        case ON_SUCCESS:
+          return STATE.SUCCEEDED;
+        case ON_FAILURE:
+          return STATE.FAILED;
+        case ON_KILL:
+          return STATE.KILLED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+    RUNNING {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_RUN:
+          return this;
+        case ON_SUCCESS:
+          return STATE.SUCCEEDED;
+        case ON_FAILURE:
+          return STATE.FAILED;
+        case ON_KILL:
+          return STATE.KILLED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+    FAILED {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_FAILURE:
+          return this;
+        case ON_RERUN:
+          return STATE.LAUNCHED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+    SUCCEEDED {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_SUCCESS:
+          return this;
+        case ON_RERUN:
+          return STATE.LAUNCHED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+
+    TIMED_OUT {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_TIME_OUT:
+          return this;
+        case ON_RERUN:
+          return STATE.WAITING;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+    KILLED {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_KILL:
+          return this;
+        case ON_RERUN:
+          return STATE.LAUNCHED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    }
+  }
+
+  /**
+   * All events(actions) which can happen on an instance of 
<code>SchedulerJob</code>.
+   */
+  public enum EVENT {
+    ON_CREATION, // an instance is first considered by the scheduler.
+    ON_TIME_OUT,
+    ON_CONDITIONS_MET,
+    ON_RUN,
+    ON_SUCCESS,
+    ON_FAILURE,
+    ON_RERUN,
+    ON_KILL
+  }
+}

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-server/src/main/java/org/apache/lens/server/scheduler/state/SchedulerJobState.java
----------------------------------------------------------------------
diff --git 
a/lens-server/src/main/java/org/apache/lens/server/scheduler/state/SchedulerJobState.java
 
b/lens-server/src/main/java/org/apache/lens/server/scheduler/state/SchedulerJobState.java
new file mode 100644
index 0000000..d21cd05
--- /dev/null
+++ 
b/lens-server/src/main/java/org/apache/lens/server/scheduler/state/SchedulerJobState.java
@@ -0,0 +1,150 @@
+/**
+ * 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.lens.server.scheduler.state;
+
+import org.apache.lens.api.scheduler.SchedulerJobStatus;
+import org.apache.lens.server.api.error.InvalidStateTransitionException;
+import org.apache.lens.server.api.scheduler.StateMachine;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * This class represents current state of a SchedulerJob and provides helper 
methods
+ * for handling different events and lifecycle transition for a SchedulerJob.
+ */
+public class SchedulerJobState {
+
+  public SchedulerJobState(SchedulerJobStatus status) {
+    this.currentStatus = status;
+  }
+  public SchedulerJobState() {
+    this.currentStatus = INITIAL_STATUS;
+  }
+
+  @Getter @Setter
+  private SchedulerJobStatus currentStatus;
+
+  private static final SchedulerJobStatus INITIAL_STATUS = 
SchedulerJobStatus.NEW;
+
+  public SchedulerJobStatus nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+    STATE currentState = STATE.valueOf(currentStatus.name());
+    return 
SchedulerJobStatus.valueOf(currentState.nextTransition(event).name());
+  }
+
+  private enum STATE implements StateMachine<STATE, EVENT> {
+    // repeating same operation will return the same state to ensure 
idempotent behavior.
+    NEW {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_SUBMIT:
+          return this;
+        case ON_SCHEDULE:
+          return STATE.SCHEDULED;
+        case ON_EXPIRE:
+          return STATE.EXPIRED;
+        case ON_DELETE:
+          return STATE.DELETED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+    SCHEDULED {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_SCHEDULE:
+          return this;
+        case ON_SUSPEND:
+          return STATE.SUSPENDED;
+        case ON_EXPIRE:
+          return STATE.EXPIRED;
+        case ON_DELETE:
+          return STATE.DELETED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+    SUSPENDED {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_SUSPEND:
+          return this;
+        case ON_RESUME:
+          return STATE.SCHEDULED;
+        case ON_EXPIRE:
+          return STATE.EXPIRED;
+        case ON_DELETE:
+          return STATE.DELETED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+    EXPIRED {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_EXPIRE:
+          return this;
+        case ON_DELETE:
+          return STATE.DELETED;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    },
+
+    DELETED {
+      @Override
+      public STATE nextTransition(EVENT event) throws 
InvalidStateTransitionException {
+        switch (event) {
+        case ON_DELETE:
+          return this;
+        default:
+          throw new InvalidStateTransitionException("Event: " + event.name() + 
" is not a valid event for state: "
+            + this.name());
+        }
+      }
+    }
+  }
+
+  /**
+   * All events(actions) which can happen on a Scheduler Job.
+   */
+  public enum EVENT {
+    ON_SUBMIT,
+    ON_SCHEDULE,
+    ON_SUSPEND,
+    ON_RESUME,
+    ON_EXPIRE,
+    ON_DELETE
+  }
+}

http://git-wip-us.apache.org/repos/asf/lens/blob/9e61e510/lens-server/src/test/java/org/apache/lens/server/scheduler/SchedulerDAOTest.java
----------------------------------------------------------------------
diff --git 
a/lens-server/src/test/java/org/apache/lens/server/scheduler/SchedulerDAOTest.java
 
b/lens-server/src/test/java/org/apache/lens/server/scheduler/SchedulerDAOTest.java
index 41cfc99..d76a586 100644
--- 
a/lens-server/src/test/java/org/apache/lens/server/scheduler/SchedulerDAOTest.java
+++ 
b/lens-server/src/test/java/org/apache/lens/server/scheduler/SchedulerDAOTest.java
@@ -100,7 +100,7 @@ public class SchedulerDAOTest {
     XJob job = getTestJob();
     long currentTime = System.currentTimeMillis();
     SchedulerJobInfo info = new 
SchedulerJobInfo(SchedulerJobHandle.fromString(UUID.randomUUID().toString()), 
job,
-        "lens", SchedulerJobState.NEW, currentTime, currentTime);
+        "lens", SchedulerJobStatus.NEW, currentTime, currentTime);
     // Store the job
     schedulerDAO.storeJob(info);
     // Retrive the stored job
@@ -115,7 +115,7 @@ public class SchedulerDAOTest {
     SchedulerJobInstanceInfo firstInstance = new SchedulerJobInstanceInfo(
         SchedulerJobInstanceHandle.fromString(UUID.randomUUID().toString()), 
jobHandle,
         new LensSessionHandle(UUID.randomUUID(), UUID.randomUUID()), 
currentTime, currentTime, "/tmp/",
-        "select * form yoda_cube", SchedulerJobInstanceState.WAITING, 
currentTime);
+        "select * form yoda_cube", SchedulerJobInstanceStatus.WAITING, 
currentTime);
     instances.put(firstInstance.getId(), firstInstance);
     schedulerDAO.storeJobInstance(firstInstance);
 
@@ -123,7 +123,7 @@ public class SchedulerDAOTest {
     SchedulerJobInstanceInfo secondInstance = new SchedulerJobInstanceInfo(
         SchedulerJobInstanceHandle.fromString(UUID.randomUUID().toString()), 
jobHandle,
         new LensSessionHandle(UUID.randomUUID(), UUID.randomUUID()), 
currentTime, currentTime, "/tmp/",
-        "select * form yoda_cube", SchedulerJobInstanceState.WAITING, 
currentTime);
+        "select * form yoda_cube", SchedulerJobInstanceStatus.WAITING, 
currentTime);
     instances.put(secondInstance.getId(), secondInstance);
     schedulerDAO.storeJobInstance(secondInstance);
     List<SchedulerJobInstanceHandle> handleList = 
schedulerDAO.getJobInstances(jobHandle);
@@ -153,16 +153,16 @@ public class SchedulerDAOTest {
     Assert.assertEquals(storedJob, newJob);
 
     // Change State
-    jobInfo.setState(SchedulerJobState.SCHEDULED);
+    jobInfo.setState(SchedulerJobStatus.SCHEDULED);
     schedulerDAO.updateJobState(jobInfo);
-    Assert.assertEquals(schedulerDAO.getJobState(jobInfo.getId()), 
SchedulerJobState.SCHEDULED);
+    Assert.assertEquals(schedulerDAO.getJobState(jobInfo.getId()), 
SchedulerJobStatus.SCHEDULED);
   }
 
   @Test(dependsOnMethods = { "testStoreInstance" })
   public void testUpdateJobInstance() {
     SchedulerJobInstanceHandle handle = instances.keySet().iterator().next();
     SchedulerJobInstanceInfo info = instances.get(handle);
-    info.setState(SchedulerJobInstanceState.LAUNCHED);
+    info.setState(SchedulerJobInstanceStatus.LAUNCHED);
     schedulerDAO.updateJobInstanceState(info);
     // Get the instance
     Assert.assertEquals(schedulerDAO.getSchedulerJobInstanceInfo(handle), 
info);
@@ -174,15 +174,15 @@ public class SchedulerDAOTest {
     XJob job = getTestJob();
     long currentTime = System.currentTimeMillis();
     SchedulerJobInfo info = new 
SchedulerJobInfo(SchedulerJobHandle.fromString(UUID.randomUUID().toString()), 
job,
-        "lens", SchedulerJobState.NEW, currentTime, currentTime);
+        "lens", SchedulerJobStatus.NEW, currentTime, currentTime);
     // Store the job
     schedulerDAO.storeJob(info);
     info = new 
SchedulerJobInfo(SchedulerJobHandle.fromString(UUID.randomUUID().toString()), 
job, "lens",
-        SchedulerJobState.NEW, currentTime, currentTime);
+        SchedulerJobStatus.NEW, currentTime, currentTime);
     schedulerDAO.storeJob(info);
     // There should be 3 jobs till now.
     Assert.assertEquals(schedulerDAO.getJobs("lens", null, null, null).size(), 
3);
-    Assert.assertEquals(schedulerDAO.getJobs("lens", SchedulerJobState.NEW, 
1L, System.currentTimeMillis()).size(), 2);
-    Assert.assertEquals(schedulerDAO.getJobs("Alice", SchedulerJobState.NEW, 
null, null).size(), 0);
+    Assert.assertEquals(schedulerDAO.getJobs("lens", SchedulerJobStatus.NEW, 
1L, System.currentTimeMillis()).size(), 2);
+    Assert.assertEquals(schedulerDAO.getJobs("Alice", SchedulerJobStatus.NEW, 
null, null).size(), 0);
   }
 }

Reply via email to