You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by sc...@apache.org on 2015/06/23 23:41:34 UTC

[12/14] airavata git commit: Adding job data model to the registry

Adding job data model to the registry


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

Branch: refs/heads/master
Commit: ec1ba5a2bb9e2ef68d17034756bd5a0131b36402
Parents: ed63a40
Author: Supun Nakandala <sc...@apache.org>
Authored: Wed Jun 24 02:30:50 2015 +0530
Committer: Supun Nakandala <sc...@apache.org>
Committed: Wed Jun 24 02:30:50 2015 +0530

----------------------------------------------------------------------
 .../core/experiment/catalog/ResourceType.java   |  20 +-
 .../catalog/impl/ExperimentCatalogImpl.java     |  29 ++
 .../catalog/impl/ExperimentRegistry.java        | 150 +++++++++-
 .../core/experiment/catalog/model/Job.java      | 163 +++++++++++
 .../experiment/catalog/model/JobStatus.java     | 127 ++++++++
 .../experiment/catalog/model/JobStatusPK.java   |  74 +++++
 .../resources/AbstractExpCatResource.java       |  17 ++
 .../catalog/resources/JobResource.java          | 293 +++++++++++++++++++
 .../catalog/resources/JobStatusResource.java    | 143 +++++++++
 .../catalog/resources/TaskResource.java         |  26 +-
 .../experiment/catalog/resources/Utils.java     |  40 +++
 .../utils/ThriftDataModelConversion.java        |  29 ++
 .../src/main/resources/META-INF/persistence.xml |   2 +
 .../src/main/resources/expcatalog-derby.sql     |  22 ++
 .../src/main/resources/expcatalog-mysql.sql     |  23 ++
 .../experiment/catalog/JobResourceTest.java     | 106 +++++++
 .../src/test/resources/expcatalog-derby.sql     |  22 ++
 .../registry/cpi/ExpCatChildDataType.java       |   4 +-
 .../cpi/ExperimentCatalogModelType.java         |   4 +-
 19 files changed, 1279 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/ResourceType.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/ResourceType.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/ResourceType.java
index 0aeaa95..3c5bd5a 100644
--- a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/ResourceType.java
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/ResourceType.java
@@ -26,19 +26,21 @@ public enum ResourceType {
     PROJECT_USER,
     GATEWAY_WORKER,
     EXPERIMENT,
+    USER_CONFIGURATION_DATA,
     EXPERIMENT_SUMMARY,
-    TASK,
-    TASK_ERROR,
-    PROCESS_ERROR,
+    EXPERIMENT_INPUT,
+    EXPERIMENT_OUTPUT,
+    EXPERIMENT_STATUS,
     EXPERIMENT_ERROR,
     PROCESS,
+    PROCESS_RESOURCE_SCHEDULE,
     PROCESS_INPUT,
     PROCESS_OUTPUT,
-    EXPERIMENT_INPUT,
-    EXPERIMENT_OUTPUT,
-    PROCESS_RESOURCE_SCHEDULE,
-    TASK_STATUS,
+    PROCESS_ERROR,
     PROCESS_STATUS,
-    EXPERIMENT_STATUS,
-    USER_CONFIGURATION_DATA;
+    TASK,
+    TASK_ERROR,
+    TASK_STATUS,
+    JOB,
+    JOB_STATUS
 }

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentCatalogImpl.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentCatalogImpl.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentCatalogImpl.java
index 95707f3..014140e 100644
--- a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentCatalogImpl.java
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentCatalogImpl.java
@@ -29,9 +29,11 @@ import org.apache.airavata.model.commons.ErrorModel;
 import org.apache.airavata.model.experiment.ExperimentModel;
 import org.apache.airavata.model.experiment.ExperimentSummaryModel;
 import org.apache.airavata.model.experiment.UserConfigurationDataModel;
+import org.apache.airavata.model.job.JobModel;
 import org.apache.airavata.model.process.ProcessModel;
 import org.apache.airavata.model.scheduling.ComputationalResourceSchedulingModel;
 import org.apache.airavata.model.status.ExperimentStatus;
+import org.apache.airavata.model.status.JobStatus;
 import org.apache.airavata.model.status.ProcessStatus;
 import org.apache.airavata.model.status.TaskStatus;
 import org.apache.airavata.model.task.TaskModel;
@@ -173,6 +175,10 @@ public class ExperimentCatalogImpl implements ExperimentCatalog {
                     return experimentRegistry.addTaskStatus((TaskStatus) newObjectToAdd, (String) dependentIdentifier);
                 case TASK_ERROR:
                     return experimentRegistry.addTaskError((ErrorModel) newObjectToAdd, (String) dependentIdentifier);
+                case JOB:
+                    return experimentRegistry.addJob((JobModel) newObjectToAdd, (String) dependentIdentifier);
+                case JOB_STATUS:
+                    return experimentRegistry.addJobStatus((JobStatus) newObjectToAdd, (String) dependentIdentifier);
                 default:
                     logger.error("Unsupported dependent data type...", new UnsupportedOperationException());
                     throw new UnsupportedOperationException();
@@ -244,6 +250,12 @@ public class ExperimentCatalogImpl implements ExperimentCatalog {
                 case TASK_ERROR:
                     experimentRegistry.updateTaskError((ErrorModel) newObjectToUpdate, (String) identifier);
                     break;
+                case JOB:
+                    experimentRegistry.updateJob((JobModel) newObjectToUpdate, (String) identifier);
+                    break;
+                case JOB_STATUS:
+                    experimentRegistry.updateJobStatus((JobStatus) newObjectToUpdate, (String) identifier);
+                    break;
                 default:
                     logger.error("Unsupported data type...", new UnsupportedOperationException());
                     throw new UnsupportedOperationException();
@@ -336,6 +348,10 @@ public class ExperimentCatalogImpl implements ExperimentCatalog {
                     return experimentRegistry.getTaskStatus((String) identifier);
                 case TASK_ERROR:
                     return experimentRegistry.getTaskError((String) identifier);
+                case JOB:
+                    return experimentRegistry.getJob((String) identifier, null);
+                case JOB_STATUS:
+                    return experimentRegistry.getJobStatus((String) identifier);
                 default:
                     logger.error("Unsupported data type...", new UnsupportedOperationException());
                     throw new UnsupportedOperationException();
@@ -391,6 +407,12 @@ public class ExperimentCatalogImpl implements ExperimentCatalog {
                         result.add(task);
                     }
                     return result;
+                case JOB:
+                    List<JobModel> jobList = experimentRegistry.getJobList(fieldName, value);
+                    for (JobModel task : jobList) {
+                        result.add(task);
+                    }
+                    return result;
                 default:
                     logger.error("Unsupported data type...", new UnsupportedOperationException());
                     throw new UnsupportedOperationException();
@@ -561,6 +583,8 @@ public class ExperimentCatalogImpl implements ExperimentCatalog {
                     return experimentRegistry.getProcessIds(fieldName, value);
                 case TASK:
                     return experimentRegistry.getTaskIds(fieldName, value);
+                case JOB:
+                    return experimentRegistry.getJobIds(fieldName, value);
                 default:
                     logger.error("Unsupported data type...", new UnsupportedOperationException());
                     throw new UnsupportedOperationException();
@@ -605,6 +629,9 @@ public class ExperimentCatalogImpl implements ExperimentCatalog {
                 case TASK:
                     experimentRegistry.removeTask((String) identifier);
                     break;
+                case JOB:
+                    experimentRegistry.removeJob((String) identifier);
+                    break;
                 default:
                     logger.error("Unsupported data type...", new UnsupportedOperationException());
                     throw new UnsupportedOperationException();
@@ -643,6 +670,8 @@ public class ExperimentCatalogImpl implements ExperimentCatalog {
                     return experimentRegistry.isProcessResourceScheduleExist((String) identifier);
                 case TASK:
                     return experimentRegistry.isTaskExist((String) identifier);
+                case JOB:
+                    return experimentRegistry.isJobExist((String) identifier);
                 default:
                     logger.error("Unsupported data type...", new UnsupportedOperationException());
                     throw new UnsupportedOperationException();

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentRegistry.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentRegistry.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentRegistry.java
index 76dfc31..75218b7 100644
--- a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentRegistry.java
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/impl/ExperimentRegistry.java
@@ -29,6 +29,7 @@ import org.apache.airavata.model.experiment.ExperimentModel;
 import org.apache.airavata.model.experiment.ExperimentStatistics;
 import org.apache.airavata.model.experiment.ExperimentSummaryModel;
 import org.apache.airavata.model.experiment.UserConfigurationDataModel;
+import org.apache.airavata.model.job.JobModel;
 import org.apache.airavata.model.process.ProcessModel;
 import org.apache.airavata.model.scheduling.ComputationalResourceSchedulingModel;
 import org.apache.airavata.model.status.*;
@@ -459,6 +460,51 @@ public class ExperimentRegistry {
         return taskId;
     }
 
+    public String addJob(JobModel job, String taskId) throws RegistryException {
+        try {
+            JobResource jobResource = new JobResource();
+            jobResource.setJobId(getJobID(taskId));
+            jobResource.setTaskId(taskId);
+            jobResource.setJobDescription(job.getJobDescription());
+            jobResource.setCreationTime(AiravataUtils.getTime(job.getCreationTime()));
+            jobResource.setComputeResourceConsumed(job.getComputeResourceConsumed());
+            jobResource.setJobName(job.getJobName());
+            jobResource.setWorkingDir(job.getWorkingDir());
+
+            TaskStatus taskStatus = new TaskStatus();
+            taskStatus.setState(TaskState.CREATED);
+            addTaskStatus(taskStatus, job.getJobId());
+        } catch (Exception e) {
+            logger.error(taskId, "Error while adding task...", e);
+            throw new RegistryException(e);
+        }
+        return taskId;
+    }
+
+    public String addJobStatus(JobStatus jobStatus, String jobID) throws RegistryException {
+        try {
+            JobResource jobResource = new JobResource();
+            jobResource.setJobId(jobID);
+            JobStatusResource status = jobResource.getJobStatus();
+            if (status == null) {
+                status = new JobStatusResource();
+            }
+            if (isValidStatusTransition(ProcessState.valueOf(status.getState()), jobStatus.getJobState())) {
+                status.setStatusId(getStatusID(jobID));
+                status.setJobId(jobID);
+                status.setTimeOfStateChange(AiravataUtils.getTime(jobStatus.getTimeOfStateChange()));
+                status.setState(jobStatus.getJobState().toString());
+                status.setReason(jobStatus.getReason());
+                status.save();
+                logger.debug(jobID, "Added job {} status to {}.", jobID, jobStatus.toString());
+            }
+        } catch (Exception e) {
+            logger.error(jobID, "Error while adding job status...", e);
+            throw new RegistryException(e);
+        }
+        return jobID;
+    }
+
 
     //CPI Update Methods
     public void updateExperiment(ExperimentModel experiment, String expId) throws RegistryException {
@@ -761,6 +807,33 @@ public class ExperimentRegistry {
         return addTaskError(taskError, taskID);
     }
 
+    public String updateJob(JobModel job, String jobId) throws RegistryException {
+        try {
+            TaskResource taskResource = new TaskResource();
+            JobResource jobResource = taskResource.getJob(jobId);
+            jobResource.setJobId(jobId);
+            jobResource.setTaskId(job.getTaskId());
+            jobResource.setJobDescription(job.getJobDescription());
+            jobResource.setCreationTime(AiravataUtils.getTime(job.getCreationTime()));
+            jobResource.setComputeResourceConsumed(job.getComputeResourceConsumed());
+            jobResource.setJobName(job.getJobName());
+            jobResource.setWorkingDir(job.getWorkingDir());
+
+            TaskStatus taskStatus = new TaskStatus();
+            taskStatus.setState(TaskState.CREATED);
+            addTaskStatus(taskStatus, job.getJobId());
+        } catch (Exception e) {
+            logger.error(jobId, "Error while adding job...", e);
+            throw new RegistryException(e);
+        }
+        return jobId;
+    }
+
+    public String updateJobStatus(JobStatus jobStatus, String jobID) throws RegistryException {
+        return addJobStatus(jobStatus, jobID);
+    }
+
+
     //TODO
     public void updateExperimentField(String expID, String fieldName, Object value) throws RegistryException {
         try {
@@ -912,7 +985,7 @@ public class ExperimentRegistry {
             if (fieldName == null) {
                 return ThriftDataModelConversion.getProcesModel(resource);
             } else {
-                logger.error("Unsupported field name for experiment basic data..");
+                logger.error("Unsupported field name for process basic data..");
             }
         }catch (Exception e) {
             logger.error("Error while getting process data..", e);
@@ -948,10 +1021,10 @@ public class ExperimentRegistry {
             if (fieldName == null) {
                 return ThriftDataModelConversion.getTaskModel(resource);
             } else {
-                logger.error("Unsupported field name for experiment basic data..");
+                logger.error("Unsupported field name for task basic data..");
             }
         }catch (Exception e) {
-            logger.error("Error while getting process data..", e);
+            logger.error("Error while getting task data..", e);
             throw new RegistryException(e);
         }
         return null;
@@ -965,6 +1038,27 @@ public class ExperimentRegistry {
         return null;
     }
 
+    public Object getJob(String jobId, String fieldName) throws RegistryException {
+        try {
+            TaskResource taskResource = new TaskResource();
+            JobResource resource = taskResource.getJob(jobId);
+            if (fieldName == null) {
+                return ThriftDataModelConversion.getJobModel(resource);
+            } else {
+                logger.error("Unsupported field name for job basic data..");
+            }
+        }catch (Exception e) {
+            logger.error("Error while getting job data..", e);
+            throw new RegistryException(e);
+        }
+        return null;
+    }
+
+    public Object getJobStatus(String identifier) {
+        return null;
+    }
+
+
     public List<ExperimentModel> getExperimentList(String fieldName, Object value) throws RegistryException {
         List<ExperimentModel> experiments = new ArrayList<ExperimentModel>();
         try {
@@ -1011,6 +1105,10 @@ public class ExperimentRegistry {
         return null;
     }
 
+    public List<JobModel> getJobList(String fieldName, Object value) {
+        return null;
+    }
+
     public List<ExperimentModel> getExperimentList(String fieldName, Object value, int limit, int offset,
                                                    Object orderByIdentifier, ResultOrderType resultOrderType) throws RegistryException {
         List<ExperimentModel> experiments = new ArrayList<ExperimentModel>();
@@ -1193,6 +1291,15 @@ public class ExperimentRegistry {
         return taskIds;
     }
 
+    public List<String> getJobIds(String fieldName, Object value) throws RegistryException {
+        List<String> jobIds = new ArrayList<String>();
+        List<JobModel> jobs = getJobList(fieldName, value);
+        for (JobModel job : jobs) {
+            jobIds.add(job.getJobId());
+        }
+        return jobIds;
+    }
+
 
     //Remove CPI methods
     public void removeExperiment(String experimentId) throws RegistryException {
@@ -1246,6 +1353,16 @@ public class ExperimentRegistry {
         }
     }
 
+    public void removeJob(String jobId) throws RegistryException {
+        try {
+            TaskResource taskResource = new TaskResource();
+            taskResource.remove(ResourceType.JOB, jobId);
+        } catch (Exception e) {
+            logger.error("Error while removing task details..", e);
+            throw new RegistryException(e);
+        }
+    }
+
 
     //isExists CPI methods
     public boolean isExperimentExist(String expID) throws RegistryException {
@@ -1298,6 +1415,17 @@ public class ExperimentRegistry {
         }
     }
 
+
+    public boolean isJobExist(String jobId) throws RegistryException {
+        try {
+            TaskResource taskResource = new TaskResource();
+            return taskResource.isExists(ResourceType.JOB, jobId);
+        } catch (Exception e) {
+            logger.error("Error while retrieving job.....", e);
+            throw new RegistryException(e);
+        }
+    }
+
     public String getExperimentID(String experimentName) {
         String exp = experimentName.replaceAll("\\s", "");
         return exp + "_" + UUID.randomUUID();
@@ -1313,6 +1441,11 @@ public class ExperimentRegistry {
         return taskId + "_" + UUID.randomUUID();
     }
 
+    public String getJobID(String taskId) {
+        String jobId = taskId.replaceAll("\\s", "");
+        return jobId + "_" + UUID.randomUUID();
+    }
+
     public String getStatusID(String parentId) {
         String status = parentId.replaceAll("\\s", "");
         return status + "_" + UUID.randomUUID();
@@ -1389,6 +1522,17 @@ public class ExperimentRegistry {
                 default:
                     return false;
             }
+        }else if (object1 instanceof JobState && object2 instanceof JobState) {
+            JobState oldState = (JobState) object1;
+            JobState nextState = (JobState) object2;
+            if (nextState == null) {
+                return false;
+            }
+            //TODO
+            switch (oldState) {
+                default:
+                    return false;
+            }
         }
         return false;
     }

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/Job.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/Job.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/Job.java
new file mode 100644
index 0000000..95e1f1d
--- /dev/null
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/Job.java
@@ -0,0 +1,163 @@
+/*
+ *
+ * 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.airavata.registry.core.experiment.catalog.model;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+import java.util.Collection;
+
+@Entity
+public class Job {
+    private final static Logger logger = LoggerFactory.getLogger(Job.class);
+    private String jobId;
+    private String taskId;
+    private String jobDescription;
+    private Timestamp creationTime;
+    private String computeResourceConsumed;
+    private String jobName;
+    private String workingDir;
+    private Task task;
+    private Collection<JobStatus> jobStatuses;
+
+    @Id
+    @Column(name = "JOB_ID")
+    public String getJobId() {
+        return jobId;
+    }
+
+    public void setJobId(String jobId) {
+        this.jobId = jobId;
+    }
+
+    @Basic
+    @Column(name = "TASK_ID")
+    public String getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(String taskId) {
+        this.taskId = taskId;
+    }
+
+    @Basic
+    @Column(name = "JOB_DESCRIPTION")
+    public String getJobDescription() {
+        return jobDescription;
+    }
+
+    public void setJobDescription(String jobDescription) {
+        this.jobDescription = jobDescription;
+    }
+
+    @Basic
+    @Column(name = "CREATION_TIME")
+    public Timestamp getCreationTime() {
+        return creationTime;
+    }
+
+    public void setCreationTime(Timestamp creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    @Basic
+    @Column(name = "COMPUTE_RESOURCE_CONSUMED")
+    public String getComputeResourceConsumed() {
+        return computeResourceConsumed;
+    }
+
+    public void setComputeResourceConsumed(String computeResourceConsumed) {
+        this.computeResourceConsumed = computeResourceConsumed;
+    }
+
+    @Basic
+    @Column(name = "JOB_NAME")
+    public String getJobName() {
+        return jobName;
+    }
+
+    public void setJobName(String jobName) {
+        this.jobName = jobName;
+    }
+
+    @Basic
+    @Column(name = "WORKING_DIR")
+    public String getWorkingDir() {
+        return workingDir;
+    }
+
+    public void setWorkingDir(String workingDir) {
+        this.workingDir = workingDir;
+    }
+
+//    @Override
+//    public boolean equals(Object o) {
+//        if (this == o) return true;
+//        if (o == null || getClass() != o.getClass()) return false;
+//
+//        Job job = (Job) o;
+//
+//        if (computeResourceConsumed != null ? !computeResourceConsumed.equals(job.computeResourceConsumed) : job.computeResourceConsumed != null)
+//            return false;
+//        if (creationTime != null ? !creationTime.equals(job.creationTime) : job.creationTime != null) return false;
+//        if (jobDescription != null ? !jobDescription.equals(job.jobDescription) : job.jobDescription != null)
+//            return false;
+//        if (jobId != null ? !jobId.equals(job.jobId) : job.jobId != null) return false;
+//        if (jobName != null ? !jobName.equals(job.jobName) : job.jobName != null) return false;
+//        if (taskId != null ? !taskId.equals(job.taskId) : job.taskId != null) return false;
+//        if (workingDir != null ? !workingDir.equals(job.workingDir) : job.workingDir != null) return false;
+//
+//        return true;
+//    }
+//
+//    @Override
+//    public int hashCode() {
+//        int result = jobId != null ? jobId.hashCode() : 0;
+//        result = 31 * result + (taskId != null ? taskId.hashCode() : 0);
+//        result = 31 * result + (jobDescription != null ? jobDescription.hashCode() : 0);
+//        result = 31 * result + (creationTime != null ? creationTime.hashCode() : 0);
+//        result = 31 * result + (computeResourceConsumed != null ? computeResourceConsumed.hashCode() : 0);
+//        result = 31 * result + (jobName != null ? jobName.hashCode() : 0);
+//        result = 31 * result + (workingDir != null ? workingDir.hashCode() : 0);
+//        return result;
+//    }
+
+    @ManyToOne
+    @JoinColumn(name = "TASK_ID", referencedColumnName = "TASK_ID")
+    public Task getTask() {
+        return task;
+    }
+
+    public void setTask(Task taskByTaskId) {
+        this.task = taskByTaskId;
+    }
+
+    @OneToMany(mappedBy = "job")
+    public Collection<JobStatus> getJobStatuses() {
+        return jobStatuses;
+    }
+
+    public void setJobStatuses(Collection<JobStatus> jobStatusesByJobId) {
+        this.jobStatuses = jobStatusesByJobId;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/JobStatus.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/JobStatus.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/JobStatus.java
new file mode 100644
index 0000000..49735ff
--- /dev/null
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/JobStatus.java
@@ -0,0 +1,127 @@
+/*
+ *
+ * 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.airavata.registry.core.experiment.catalog.model;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+
+@Entity
+@Table(name = "JOB_STATUS")
+@IdClass(JobStatusPK.class)
+public class JobStatus {
+    private final static Logger logger = LoggerFactory.getLogger(JobStatus.class);
+    private String statusId;
+    private String jobId;
+    private String state;
+    private Timestamp timeOfStateChange;
+    private String reason;
+    private Job job;
+
+    @Id
+    @Column(name = "STATUS_ID")
+    public String getStatusId() {
+        return statusId;
+    }
+
+    public void setStatusId(String statusId) {
+        this.statusId = statusId;
+    }
+
+    @Id
+    @Column(name = "JOB_ID")
+    public String getJobId() {
+        return jobId;
+    }
+
+    public void setJobId(String jobId) {
+        this.jobId = jobId;
+    }
+
+    @Basic
+    @Column(name = "STATE")
+    public String getState() {
+        return state;
+    }
+
+    public void setState(String state) {
+        this.state = state;
+    }
+
+    @Basic
+    @Column(name = "TIME_OF_STATE_CHANGE")
+    public Timestamp getTimeOfStateChange() {
+        return timeOfStateChange;
+    }
+
+    public void setTimeOfStateChange(Timestamp timeOfStateChange) {
+        this.timeOfStateChange = timeOfStateChange;
+    }
+
+    @Basic
+    @Lob
+    @Column(name = "REASON")
+    public String getReason() {
+        return reason;
+    }
+
+    public void setReason(String reason) {
+        this.reason = reason;
+    }
+
+//    @Override
+//    public boolean equals(Object o) {
+//        if (this == o) return true;
+//        if (o == null || getClass() != o.getClass()) return false;
+//
+//        TaskStatus that = (TaskStatus) o;
+//        if (statusId != null ? !statusId.equals(that.statusId) : that.statusId != null) return false;
+//        if (reason != null ? !reason.equals(that.reason) : that.reason != null) return false;
+//        if (state != null ? !state.equals(that.state) : that.state != null) return false;
+//        if (jobId != null ? !jobId.equals(that.jobId) : that.jobId != null) return false;
+//        if (timeOfStateChange != null ? !timeOfStateChange.equals(that.timeOfStateChange) : that.timeOfStateChange != null)
+//            return false;
+//
+//        return true;
+//    }
+//
+//    @Override
+//    public int hashCode() {
+//        int result = statusId != null ? statusId.hashCode() : 0;
+//        result = 31 * result + (jobId != null ? jobId.hashCode() : 0);
+//        result = 31 * result + (state != null ? state.hashCode() : 0);
+//        result = 31 * result + (timeOfStateChange != null ? timeOfStateChange.hashCode() : 0);
+//        result = 31 * result + (reason != null ? reason.hashCode() : 0);
+//        return result;
+//    }
+
+    @ManyToOne
+    @JoinColumn(name = "JOB_ID", referencedColumnName = "JOB_ID", nullable = false)
+    public Job getJob() {
+        return job;
+    }
+
+    public void setJob(Job jobById) {
+        this.job = jobById;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/JobStatusPK.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/JobStatusPK.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/JobStatusPK.java
new file mode 100644
index 0000000..672319b
--- /dev/null
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/model/JobStatusPK.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+package org.apache.airavata.registry.core.experiment.catalog.model;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import java.io.Serializable;
+
+public class JobStatusPK implements Serializable {
+    private final static Logger logger = LoggerFactory.getLogger(JobStatusPK.class);
+    private String statusId;
+    private String jobId;
+
+    @Id
+    @Column(name = "STATUS_ID")
+    public String getStatusId() {
+        return statusId;
+    }
+
+    public void setStatusId(String statusId) {
+        this.statusId = statusId;
+    }
+
+    @Id
+    @Column(name = "JOB_ID")
+    public String getJobId() {
+        return jobId;
+    }
+
+    public void setJobId(String jobId) {
+        this.jobId = jobId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        JobStatusPK that = (JobStatusPK) o;
+
+        if (getStatusId() != null ? !getStatusId().equals(that.getStatusId()) : that.getStatusId() != null) return false;
+        if (getJobId() != null ? !getJobId().equals(that.getJobId()) : that.getJobId() != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = getStatusId() != null ? getStatusId().hashCode() : 0;
+        result = 31 * result + (getJobId() != null ? getJobId().hashCode() : 0);
+        return result;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/AbstractExpCatResource.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/AbstractExpCatResource.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/AbstractExpCatResource.java
index f4b4d37..8608d65 100644
--- a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/AbstractExpCatResource.java
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/AbstractExpCatResource.java
@@ -49,6 +49,8 @@ public abstract class AbstractExpCatResource implements ExperimentCatResource {
     public static final String TASK = "Task";
     public static final String TASK_ERROR = "TaskError";
     public static final String TASK_STATUS = "TaskStatus";
+    public static final String JOB = "Job";
+    public static final String JOB_STATUS = "JobStatus";
 
 
 	// Gateway Table
@@ -215,6 +217,21 @@ public abstract class AbstractExpCatResource implements ExperimentCatResource {
         public static final String PROCESS_ID = "processId";
     }
 
+    //Job Table
+    public final class JobConstants {
+        public static final String JOB_ID = "jobId";
+        public static final String TASK_ID = "taskId";
+    }
+
+    // Job Status table
+    public final class JobStatusConstants {
+        public static final String STATUS_ID = "statusId";
+        public static final String JOB_ID = "jobId";
+        public static final String STATE = "state";
+        public static final String TIME_OF_STATE_CHANGE = "timeOfStateChange";
+        public static final String REASON = "reason";
+    }
+
     // Task Status table
     public final class TaskStatusConstants {
         public static final String STATUS_ID = "statusId";

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/JobResource.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/JobResource.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/JobResource.java
new file mode 100644
index 0000000..55bdd98
--- /dev/null
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/JobResource.java
@@ -0,0 +1,293 @@
+/*
+ *
+ * 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.airavata.registry.core.experiment.catalog.resources;
+
+import org.apache.airavata.registry.core.experiment.catalog.ExpCatResourceUtils;
+import org.apache.airavata.registry.core.experiment.catalog.ExperimentCatResource;
+import org.apache.airavata.registry.core.experiment.catalog.ResourceType;
+import org.apache.airavata.registry.core.experiment.catalog.model.Job;
+import org.apache.airavata.registry.core.experiment.catalog.model.JobStatus;
+import org.apache.airavata.registry.core.experiment.catalog.utils.QueryGenerator;
+import org.apache.airavata.registry.cpi.RegistryException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JobResource extends AbstractExpCatResource {
+    private static final Logger logger = LoggerFactory.getLogger(JobResource.class);
+    private String jobId;
+    private String taskId;
+    private String jobDescription;
+    private Timestamp creationTime;
+    private String computeResourceConsumed;
+    private String jobName;
+    private String workingDir;
+
+    public String getJobId() {
+        return jobId;
+    }
+
+    public void setJobId(String jobId) {
+        this.jobId = jobId;
+    }
+
+    public String getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(String taskId) {
+        this.taskId = taskId;
+    }
+
+    public String getJobDescription() {
+        return jobDescription;
+    }
+
+    public void setJobDescription(String jobDescription) {
+        this.jobDescription = jobDescription;
+    }
+
+    public Timestamp getCreationTime() {
+        return creationTime;
+    }
+
+    public void setCreationTime(Timestamp creationTime) {
+        this.creationTime = creationTime;
+    }
+
+    public String getComputeResourceConsumed() {
+        return computeResourceConsumed;
+    }
+
+    public void setComputeResourceConsumed(String computeResourceConsumed) {
+        this.computeResourceConsumed = computeResourceConsumed;
+    }
+
+    public String getJobName() {
+        return jobName;
+    }
+
+    public void setJobName(String jobName) {
+        this.jobName = jobName;
+    }
+
+    public String getWorkingDir() {
+        return workingDir;
+    }
+
+    public void setWorkingDir(String workingDir) {
+        this.workingDir = workingDir;
+    }
+
+    public ExperimentCatResource create(ResourceType type) throws RegistryException {
+        switch (type){
+            case JOB_STATUS:
+                JobStatusResource jobStatusResource = new JobStatusResource();
+                jobStatusResource.setJobId(jobId);
+                return jobStatusResource;
+            default:
+                logger.error("Unsupported resource type for job details data resource.", new UnsupportedOperationException());
+                throw new UnsupportedOperationException();
+        }
+    }
+
+    
+    public void remove(ResourceType type, Object name) throws RegistryException{
+        EntityManager em = null;
+        try {
+            em = ExpCatResourceUtils.getEntityManager();
+            em.getTransaction().begin();
+            Query q;
+            QueryGenerator generator;
+            switch (type) {
+                case JOB_STATUS:
+                    generator = new QueryGenerator(JOB_STATUS);
+                    generator.setParameter(JobStatusConstants.STATUS_ID, name);
+                    q = generator.deleteQuery(em);
+                    q.executeUpdate();
+                    break;
+                default:
+                    logger.error("Unsupported resource type for job details resource.", new IllegalArgumentException());
+                    break;
+            }
+            em.getTransaction().commit();
+            em.close();
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            throw new RegistryException(e);
+        } finally {
+            if (em != null && em.isOpen()) {
+                if (em.getTransaction().isActive()){
+                    em.getTransaction().rollback();
+                }
+                em.close();
+            }
+        }
+    }
+
+
+    public ExperimentCatResource get(ResourceType type, Object name) throws RegistryException {
+        EntityManager em = null;
+        try {
+            em = ExpCatResourceUtils.getEntityManager();
+            em.getTransaction().begin();
+            QueryGenerator generator;
+            Query q;
+            switch (type) {
+                case JOB_STATUS:
+                    generator = new QueryGenerator(JOB_STATUS);
+                    generator.setParameter(JobStatusConstants.STATUS_ID, name);
+                    q = generator.selectQuery(em);
+                    JobStatus status = (JobStatus) q.getSingleResult();
+                    JobStatusResource statusResource = (JobStatusResource) Utils.getResource(ResourceType.JOB_STATUS, status);
+                    em.getTransaction().commit();
+                    em.close();
+                    return statusResource;
+                default:
+                    em.getTransaction().commit();
+                    em.close();
+                    logger.error("Unsupported resource type for Job resource.", new IllegalArgumentException());
+                    throw new IllegalArgumentException("Unsupported resource type for Job resource.");
+            }
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            throw new RegistryException(e);
+        } finally {
+            if (em != null && em.isOpen()) {
+                if (em.getTransaction().isActive()){
+                    em.getTransaction().rollback();
+                }
+                em.close();
+            }
+        }
+    }
+
+    
+    public List<ExperimentCatResource> get(ResourceType type) throws RegistryException{
+        List<ExperimentCatResource> resourceList = new ArrayList<ExperimentCatResource>();
+        EntityManager em = null;
+        try {
+            em = ExpCatResourceUtils.getEntityManager();
+            em.getTransaction().begin();
+            Query q;
+            QueryGenerator generator;
+            List results;
+            switch (type) {
+                case JOB_STATUS:
+                    generator = new QueryGenerator(JOB_STATUS);
+                    generator.setParameter(JobStatusConstants.JOB_ID, jobId);
+                    q = generator.selectQuery(em);
+                    results = q.getResultList();
+                    if (results.size() != 0) {
+                        for (Object result : results) {
+                            JobStatus jobStatus = (JobStatus) result;
+                            JobStatusResource jobStatusResource =
+                                    (JobStatusResource) Utils.getResource(ResourceType.JOB_STATUS, jobStatus);
+                            resourceList.add(jobStatusResource);
+                        }
+                    }
+                    break;
+                default:
+                    em.getTransaction().commit();
+                    em.close();
+                    logger.error("Unsupported resource type for job resource.", new UnsupportedOperationException());
+                    throw new UnsupportedOperationException();
+            }
+            em.getTransaction().commit();
+            em.close();
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            throw new RegistryException(e);
+        } finally {
+            if (em != null && em.isOpen()) {
+                if (em.getTransaction().isActive()){
+                    em.getTransaction().rollback();
+                }
+                em.close();
+            }
+        }
+        return resourceList;
+    }
+
+    
+    public void save()  throws RegistryException{
+        EntityManager em = null;
+        try {
+            em = ExpCatResourceUtils.getEntityManager();
+            em.getTransaction().begin();
+            Job job = em.find(Job.class, jobId);
+            if(job == null){
+                job = new Job();
+            }
+            job.setJobId(jobId);
+            job.setTaskId(taskId);
+            job.setJobDescription(jobDescription);
+            job.setCreationTime(creationTime);
+            job.setComputeResourceConsumed(computeResourceConsumed);
+            job.setJobName(jobName);
+            job.setWorkingDir(workingDir);
+            em.persist(job);
+            em.getTransaction().commit();
+            em.close();
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            throw new RegistryException(e);
+        } finally {
+            if (em != null && em.isOpen()) {
+                if (em.getTransaction().isActive()){
+                    em.getTransaction().rollback();
+                }
+                em.close();
+            }
+        }
+    }
+
+    public List<JobStatusResource> getJobStatuses() throws RegistryException{
+        List<JobStatusResource> jobStatusResources = new ArrayList();
+        List<ExperimentCatResource> resources = get(ResourceType.JOB_STATUS);
+        for (ExperimentCatResource resource : resources) {
+            JobStatusResource statusResource = (JobStatusResource) resource;
+            jobStatusResources.add(statusResource);
+        }
+        return jobStatusResources;
+    }
+
+    public JobStatusResource getJobStatus() throws RegistryException{
+        List<JobStatusResource> jobStatusResources = getJobStatuses();
+        if(jobStatusResources.size() == 0){
+            return null;
+        }else{
+            JobStatusResource max = jobStatusResources.get(0);
+            for(int i=1; i<jobStatusResources.size();i++){
+                if(jobStatusResources.get(i).getTimeOfStateChange().after(max.getTimeOfStateChange())){
+                    max = jobStatusResources.get(i);
+                }
+            }
+            return max;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/JobStatusResource.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/JobStatusResource.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/JobStatusResource.java
new file mode 100644
index 0000000..5c0e3b2
--- /dev/null
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/JobStatusResource.java
@@ -0,0 +1,143 @@
+/*
+ *
+ * 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.airavata.registry.core.experiment.catalog.resources;
+
+import org.apache.airavata.registry.core.experiment.catalog.ExpCatResourceUtils;
+import org.apache.airavata.registry.core.experiment.catalog.ExperimentCatResource;
+import org.apache.airavata.registry.core.experiment.catalog.ResourceType;
+import org.apache.airavata.registry.core.experiment.catalog.model.JobStatus;
+import org.apache.airavata.registry.core.experiment.catalog.model.JobStatusPK;
+import org.apache.airavata.registry.cpi.RegistryException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.EntityManager;
+import java.sql.Timestamp;
+import java.util.List;
+
+public class JobStatusResource extends AbstractExpCatResource {
+    private static final Logger logger = LoggerFactory.getLogger(JobStatusResource.class);
+    private String statusId;
+    private String jobId;
+    private String state;
+    private Timestamp timeOfStateChange;
+    private String reason;
+
+    public String getStatusId() {
+        return statusId;
+    }
+
+    public void setStatusId(String statusId) {
+        this.statusId = statusId;
+    }
+
+    public String getJobId() {
+        return jobId;
+    }
+
+    public void setJobId(String jobId) {
+        this.jobId = jobId;
+    }
+
+    public String getState() {
+        return state;
+    }
+
+    public void setState(String state) {
+        this.state = state;
+    }
+
+    public Timestamp getTimeOfStateChange() {
+        return timeOfStateChange;
+    }
+
+    public void setTimeOfStateChange(Timestamp timeOfStateChange) {
+        this.timeOfStateChange = timeOfStateChange;
+    }
+
+    public String getReason() {
+        return reason;
+    }
+
+    public void setReason(String reason) {
+        this.reason = reason;
+    }
+
+    public ExperimentCatResource create(ResourceType type) throws RegistryException {
+        logger.error("Unsupported resource type for task status data resource.", new UnsupportedOperationException());
+        throw new UnsupportedOperationException();
+    }
+
+    
+    public void remove(ResourceType type, Object name) throws RegistryException {
+        logger.error("Unsupported resource type for task status data resource.", new UnsupportedOperationException());
+        throw new UnsupportedOperationException();
+    }
+
+    
+    public ExperimentCatResource get(ResourceType type, Object name) throws RegistryException{
+        logger.error("Unsupported resource type for task status data resource.", new UnsupportedOperationException());
+        throw new UnsupportedOperationException();
+    }
+
+    
+    public List<ExperimentCatResource> get(ResourceType type) throws RegistryException{
+        logger.error("Unsupported resource type for task status data resource.", new UnsupportedOperationException());
+        throw new UnsupportedOperationException();
+    }
+
+    
+    public void save() throws RegistryException{
+        EntityManager em = null;
+        try {
+            em = ExpCatResourceUtils.getEntityManager();
+            em.getTransaction().begin();
+            JobStatus jobStatus;
+            if(jobId == null || statusId == null){
+                throw new RegistryException("Does not have the job id or status id");
+            }
+            JobStatusPK jobStatusPK = new JobStatusPK();
+            jobStatusPK.setJobId(jobId);
+            jobStatusPK.setStatusId(statusId);
+            jobStatus = em.find(JobStatus.class, jobStatusPK);
+            if(jobStatus == null){
+                jobStatus = new JobStatus();
+            }
+            jobStatus.setJobId(jobId);
+            jobStatus.setState(state);
+            jobStatus.setReason(reason);
+            em.persist(jobStatus);
+            em.getTransaction().commit();
+            em.close();
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            throw new RegistryException(e);
+        } finally {
+            if (em != null && em.isOpen()) {
+                if (em.getTransaction().isActive()){
+                    em.getTransaction().rollback();
+                }
+                em.close();
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/TaskResource.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/TaskResource.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/TaskResource.java
index e620278..5d90e4f 100644
--- a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/TaskResource.java
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/TaskResource.java
@@ -24,6 +24,7 @@ package org.apache.airavata.registry.core.experiment.catalog.resources;
 import org.apache.airavata.registry.core.experiment.catalog.ExpCatResourceUtils;
 import org.apache.airavata.registry.core.experiment.catalog.ExperimentCatResource;
 import org.apache.airavata.registry.core.experiment.catalog.ResourceType;
+import org.apache.airavata.registry.core.experiment.catalog.model.Job;
 import org.apache.airavata.registry.core.experiment.catalog.model.Task;
 import org.apache.airavata.registry.core.experiment.catalog.model.TaskError;
 import org.apache.airavata.registry.core.experiment.catalog.model.TaskStatus;
@@ -114,8 +115,12 @@ public class TaskResource extends AbstractExpCatResource {
                 TaskErrorResource taskErrorResource = new TaskErrorResource();
                 taskErrorResource.setTaskId(taskId);
                 return taskErrorResource;
+            case JOB:
+                JobResource jobResource = new JobResource();
+                jobResource.setTaskId(taskId);
+                return jobResource;
             default:
-                logger.error("Unsupported resource type for job details data resource.", new UnsupportedOperationException());
+                logger.error("Unsupported resource type for task data resource.", new UnsupportedOperationException());
                 throw new UnsupportedOperationException();
         }
     }
@@ -141,6 +146,12 @@ public class TaskResource extends AbstractExpCatResource {
                     q = generator.deleteQuery(em);
                     q.executeUpdate();
                     break;
+                case JOB:
+                    generator = new QueryGenerator(JOB);
+                    generator.setParameter(JobConstants.JOB_ID, name);
+                    q = generator.deleteQuery(em);
+                    q.executeUpdate();
+                    break;
                 default:
                     logger.error("Unsupported resource type for job details resource.", new IllegalArgumentException());
                     break;
@@ -189,6 +200,15 @@ public class TaskResource extends AbstractExpCatResource {
                     em.getTransaction().commit();
                     em.close();
                     return errorResource;
+                case JOB:
+                    generator = new QueryGenerator(JOB);
+                    generator.setParameter(JobConstants.JOB_ID, name);
+                    q = generator.selectQuery(em);
+                    Job job = (Job) q.getSingleResult();
+                    JobResource jobResource = (JobResource) Utils.getResource(ResourceType.JOB, job);
+                    em.getTransaction().commit();
+                    em.close();
+                    return jobResource;
                 default:
                     em.getTransaction().commit();
                     em.close();
@@ -351,4 +371,8 @@ public class TaskResource extends AbstractExpCatResource {
             return max;
         }
     }
+
+    public JobResource getJob(String jobId) throws RegistryException {
+        return (JobResource) get(ResourceType.JOB, jobId);
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/Utils.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/Utils.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/Utils.java
index 64f80a3..90fb348 100644
--- a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/Utils.java
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/resources/Utils.java
@@ -313,6 +313,20 @@ public class Utils {
                     logger.error("Object should be a task error data.", new IllegalArgumentException());
                     throw new IllegalArgumentException("Object should be task error data.");
                 }
+            case JOB:
+                if (o instanceof  Job){
+                    return createJobResource((Job) o);
+                }else {
+                    logger.error("Object should be a Job data.", new IllegalArgumentException());
+                    throw new IllegalArgumentException("Object should be a Job data.");
+                }
+            case JOB_STATUS:
+                if (o instanceof  JobStatus){
+                    return createJobStatusResource((JobStatus) o);
+                }else {
+                    logger.error("Object should be a JobStatus data.", new IllegalArgumentException());
+                    throw new IllegalArgumentException("Object should be a JobStatus data.");
+                }
             default:
                 logger.error("Illegal data type..", new IllegalArgumentException());
                 throw new IllegalArgumentException("Illegal data type..");
@@ -622,4 +636,30 @@ public class Utils {
         }
         return resourceScheduleResource;
     }
+
+    private static ExperimentCatResource createJobResource (Job o){
+        JobResource jobResource = new JobResource();
+        if (o != null){
+            jobResource.setJobId(o.getJobId());
+            jobResource.setTaskId(o.getTaskId());
+            jobResource.setCreationTime(o.getCreationTime());
+            jobResource.setJobDescription(o.getJobDescription());
+            jobResource.setComputeResourceConsumed(o.getComputeResourceConsumed());
+            jobResource.setJobName(o.getJobName());
+            jobResource.setWorkingDir(o.getWorkingDir());
+        }
+        return jobResource;
+    }
+
+    private static ExperimentCatResource createJobStatusResource (JobStatus o){
+        JobStatusResource jobStatusResource = new JobStatusResource();
+        if (o != null){
+            jobStatusResource.setJobId(o.getJobId());
+            jobStatusResource.setState(o.getState());
+            jobStatusResource.setTimeOfStateChange(o.getTimeOfStateChange());
+            jobStatusResource.setReason(o.getReason());
+        }
+
+        return jobStatusResource;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/utils/ThriftDataModelConversion.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/utils/ThriftDataModelConversion.java b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/utils/ThriftDataModelConversion.java
index 25a2ce6..ba64adf 100644
--- a/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/utils/ThriftDataModelConversion.java
+++ b/modules/registry/registry-core/src/main/java/org/apache/airavata/registry/core/experiment/catalog/utils/ThriftDataModelConversion.java
@@ -28,6 +28,7 @@ import org.apache.airavata.model.commons.ErrorModel;
 import org.apache.airavata.model.experiment.ExperimentModel;
 import org.apache.airavata.model.experiment.ExperimentSummaryModel;
 import org.apache.airavata.model.experiment.UserConfigurationDataModel;
+import org.apache.airavata.model.job.JobModel;
 import org.apache.airavata.model.process.ProcessModel;
 import org.apache.airavata.model.scheduling.ComputationalResourceSchedulingModel;
 import org.apache.airavata.model.status.*;
@@ -311,6 +312,20 @@ public class ThriftDataModelConversion {
         return null;
     }
 
+    public static JobStatus getJobStatus (JobStatusResource status){
+        if (status != null){
+            JobStatus jobStatus = new JobStatus();
+            if (status.getState() == null || status.getState().equals("")){
+                status.setState("UNKNOWN");
+            }
+            jobStatus.setJobState(JobState.valueOf(status.getState()));
+            jobStatus.setTimeOfStateChange(status.getTimeOfStateChange().getTime());
+            jobStatus.setReason(status.getReason());
+            return jobStatus;
+        }
+        return null;
+    }
+
     public static ProcessModel getProcesModel (ProcessResource processResource) throws RegistryException {
         if (processResource != null){
             ProcessModel processModel = new ProcessModel();
@@ -363,6 +378,20 @@ public class ThriftDataModelConversion {
         return model;
     }
 
+    public static JobModel getJobModel (JobResource jobResource) throws RegistryException {
+        JobModel model = new JobModel();
+        model.setJobId(jobResource.getJobId());
+        model.setTaskId(jobResource.getTaskId());
+        model.setJobDescription(jobResource.getJobDescription());
+        model.setCreationTime(jobResource.getCreationTime().getTime());
+        model.setComputeResourceConsumed(jobResource.getComputeResourceConsumed());
+        model.setJobName(jobResource.getJobName());
+        model.setWorkingDir(jobResource.getWorkingDir());
+        model.setJobStatus(getJobStatus(jobResource.getJobStatus()));
+
+        return model;
+    }
+
 
     public static ErrorModel getErrorModel (Object object){
         if (object != null) {

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/resources/META-INF/persistence.xml b/modules/registry/registry-core/src/main/resources/META-INF/persistence.xml
index 9e2ddfe..e9cc636 100644
--- a/modules/registry/registry-core/src/main/resources/META-INF/persistence.xml
+++ b/modules/registry/registry-core/src/main/resources/META-INF/persistence.xml
@@ -87,6 +87,8 @@
         <class>org.apache.airavata.registry.core.experiment.catalog.model.TaskStatus</class>
         <class>org.apache.airavata.registry.core.experiment.catalog.model.Users</class>
         <class>org.apache.airavata.registry.core.experiment.catalog.model.UserConfigurationData</class>
+        <class>org.apache.airavata.registry.core.experiment.catalog.model.Job</class>
+        <class>org.apache.airavata.registry.core.experiment.catalog.model.JobStatus</class>
         <exclude-unlisted-classes>true</exclude-unlisted-classes>
     </persistence-unit>
 </persistence>

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/resources/expcatalog-derby.sql
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/resources/expcatalog-derby.sql b/modules/registry/registry-core/src/main/resources/expcatalog-derby.sql
index aeab3e5..63f40ef 100644
--- a/modules/registry/registry-core/src/main/resources/expcatalog-derby.sql
+++ b/modules/registry/registry-core/src/main/resources/expcatalog-derby.sql
@@ -292,6 +292,28 @@ CREATE TABLE TASK_ERROR (
   FOREIGN KEY (TASK_ID) REFERENCES TASK(TASK_ID) ON DELETE CASCADE
 );
 
+CREATE TABLE JOB (
+  JOB_ID varchar(255),
+  TASK_ID varchar(255),
+  JOB_DESCRIPTION varchar(255),
+  CREATION_TIME  timestamp DEFAULT '0000-00-00 00:00:00',
+  COMPUTE_RESOURCE_CONSUMED varchar(255),
+  JOB_NAME varchar(255),
+  WORKING_DIR varchar(255),
+  PRIMARY KEY (JOB_ID),
+  FOREIGN KEY (TASK_ID) REFERENCES TASK(TASK_ID) ON DELETE CASCADE
+);
+
+CREATE TABLE JOB_STATUS (
+  STATUS_ID varchar(255),
+  JOB_ID varchar(255),
+  STATE varchar(255),
+  TIME_OF_STATE_CHANGE  timestamp DEFAULT '0000-00-00 00:00:00',
+  REASON CLOB,
+  PRIMARY KEY (STATUS_ID, JOB_ID),
+  FOREIGN KEY (JOB_ID) REFERENCES JOB(JOB_ID) ON DELETE CASCADE
+);
+
 CREATE TABLE CONFIGURATION
 (
         CONFIG_KEY VARCHAR(255),

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/main/resources/expcatalog-mysql.sql
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/main/resources/expcatalog-mysql.sql b/modules/registry/registry-core/src/main/resources/expcatalog-mysql.sql
index 8a9ebe0..56a3d3a 100644
--- a/modules/registry/registry-core/src/main/resources/expcatalog-mysql.sql
+++ b/modules/registry/registry-core/src/main/resources/expcatalog-mysql.sql
@@ -294,6 +294,29 @@ CREATE TABLE TASK_ERROR (
   FOREIGN KEY (TASK_ID) REFERENCES TASK(TASK_ID) ON DELETE CASCADE
 );
 
+CREATE TABLE JOB (
+  JOB_ID varchar(255),
+  TASK_ID varchar(255),
+  JOB_DESCRIPTION varchar(255),
+  CREATION_TIME timestamp DEFAULT CURRENT_TIMESTAMP,
+  COMPUTE_RESOURCE_CONSUMED varchar(255),
+  JOB_NAME varchar(255),
+  WORKING_DIR varchar(255),
+  PRIMARY KEY (JOB_ID),
+  FOREIGN KEY (TASK_ID) REFERENCES TASK(TASK_ID) ON DELETE CASCADE
+);
+
+CREATE TABLE JOB_STATUS (
+  STATUS_ID varchar(255),
+  JOB_ID varchar(255),
+  STATE varchar(255),
+  TIME_OF_STATE_CHANGE timestamp DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
+  REASON LONGTEXT,
+  PRIMARY KEY (STATUS_ID, JOB_ID),
+  FOREIGN KEY (JOB_ID) REFERENCES JOB(JOB_ID) ON DELETE CASCADE
+);
+
+
 CREATE TABLE CONFIGURATION
 (
         CONFIG_KEY VARCHAR(255),

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/test/java/org/apache/airavata/experiment/catalog/JobResourceTest.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/test/java/org/apache/airavata/experiment/catalog/JobResourceTest.java b/modules/registry/registry-core/src/test/java/org/apache/airavata/experiment/catalog/JobResourceTest.java
new file mode 100644
index 0000000..7ee72cb
--- /dev/null
+++ b/modules/registry/registry-core/src/test/java/org/apache/airavata/experiment/catalog/JobResourceTest.java
@@ -0,0 +1,106 @@
+/**
+ * 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.airavata.experiment.catalog;
+
+import org.apache.airavata.model.task.TaskTypes;
+import org.apache.airavata.registry.core.experiment.catalog.ResourceType;
+import org.apache.airavata.registry.core.experiment.catalog.resources.ExperimentResource;
+import org.apache.airavata.registry.core.experiment.catalog.resources.JobResource;
+import org.apache.airavata.registry.core.experiment.catalog.resources.ProcessResource;
+import org.apache.airavata.registry.core.experiment.catalog.resources.TaskResource;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.sql.Timestamp;
+import java.util.Date;
+
+import static org.junit.Assert.*;
+
+public class JobResourceTest extends AbstractResourceTest{
+	
+	   private ExperimentResource experimentResource;
+	   private ProcessResource processResource;
+	   private TaskResource taskResource;
+       private JobResource jobResource;
+       private String experimentID = "testExpID";
+	   private String processId = "processID";
+       private String taskId = "taskID";
+       private String jobId = "jobID";
+
+	
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+	    Timestamp creationTime = new Timestamp(new Date().getTime());
+	    
+	    experimentResource = (ExperimentResource) getGatewayResource().create(ResourceType.EXPERIMENT);
+        experimentResource.setExperimentId(experimentID);
+        experimentResource.setExperimentName(experimentID);
+        experimentResource.setUserName(getWorkerResource().getUser());
+        experimentResource.setProjectId(getProjectResource().getId());
+        experimentResource.setCreationTime(creationTime);
+        experimentResource.save();
+
+        processResource = (ProcessResource)experimentResource.create(ResourceType.PROCESS);
+        processResource.setProcessId(processId);
+        processResource.setExperimentId(experimentID);
+        processResource.setCreationTime(creationTime);
+        processResource.save();
+
+        taskResource = (TaskResource)processResource.create(ResourceType.TASK);
+        taskResource.setTaskId(taskId);
+        taskResource.setParentProcessId(processId);
+        taskResource.setTaskType(TaskTypes.DATA_STAGING.toString());
+        taskResource.setTaskDetail("task detail");
+        taskResource.setTaskInternalStore((byte)2);
+        taskResource.save();
+
+        jobResource = (JobResource)taskResource.create(ResourceType.JOB);
+        jobResource.setJobId(jobId);
+        taskResource.setTaskId(taskId);
+        jobResource.setJobDescription("Job Description");
+        jobResource.setComputeResourceConsumed("computer-resource-host");
+        jobResource.setJobName("JobName");
+        jobResource.setWorkingDir("WorkingDir");
+        jobResource.save();
+    }
+	
+
+	@Test
+    public void testCreate() throws Exception {
+    	assertNotNull("job data resource has being created ", jobResource);
+    }
+    
+    @Test
+    public void testSave() throws Exception {
+        assertTrue("job save successfully", taskResource.isExists(ResourceType.JOB, jobId));
+    }
+    
+    @Test
+    public void testGet() throws Exception {
+        assertNotNull("job data retrieved successfully", taskResource.get(ResourceType.JOB, jobId));
+    }
+
+    @Test
+    public void testRemove() throws Exception {
+    	taskResource.remove(ResourceType.JOB, jobId);
+    	assertFalse("job data removed successfully", taskResource.isExists(ResourceType.JOB, jobId));
+    }
+}

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-core/src/test/resources/expcatalog-derby.sql
----------------------------------------------------------------------
diff --git a/modules/registry/registry-core/src/test/resources/expcatalog-derby.sql b/modules/registry/registry-core/src/test/resources/expcatalog-derby.sql
index aeab3e5..63f40ef 100644
--- a/modules/registry/registry-core/src/test/resources/expcatalog-derby.sql
+++ b/modules/registry/registry-core/src/test/resources/expcatalog-derby.sql
@@ -292,6 +292,28 @@ CREATE TABLE TASK_ERROR (
   FOREIGN KEY (TASK_ID) REFERENCES TASK(TASK_ID) ON DELETE CASCADE
 );
 
+CREATE TABLE JOB (
+  JOB_ID varchar(255),
+  TASK_ID varchar(255),
+  JOB_DESCRIPTION varchar(255),
+  CREATION_TIME  timestamp DEFAULT '0000-00-00 00:00:00',
+  COMPUTE_RESOURCE_CONSUMED varchar(255),
+  JOB_NAME varchar(255),
+  WORKING_DIR varchar(255),
+  PRIMARY KEY (JOB_ID),
+  FOREIGN KEY (TASK_ID) REFERENCES TASK(TASK_ID) ON DELETE CASCADE
+);
+
+CREATE TABLE JOB_STATUS (
+  STATUS_ID varchar(255),
+  JOB_ID varchar(255),
+  STATE varchar(255),
+  TIME_OF_STATE_CHANGE  timestamp DEFAULT '0000-00-00 00:00:00',
+  REASON CLOB,
+  PRIMARY KEY (STATUS_ID, JOB_ID),
+  FOREIGN KEY (JOB_ID) REFERENCES JOB(JOB_ID) ON DELETE CASCADE
+);
+
 CREATE TABLE CONFIGURATION
 (
         CONFIG_KEY VARCHAR(255),

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExpCatChildDataType.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExpCatChildDataType.java b/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExpCatChildDataType.java
index 845e308..6c1a310 100644
--- a/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExpCatChildDataType.java
+++ b/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExpCatChildDataType.java
@@ -33,5 +33,7 @@ public enum ExpCatChildDataType {
     PROCESS_RESOURCE_SCHEDULE,
     TASK,
     TASK_STATUS,
-    TASK_ERROR
+    TASK_ERROR,
+    JOB,
+    JOB_STATUS
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/airavata/blob/ec1ba5a2/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExperimentCatalogModelType.java
----------------------------------------------------------------------
diff --git a/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExperimentCatalogModelType.java b/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExperimentCatalogModelType.java
index 18f60d1..44cb2ed 100644
--- a/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExperimentCatalogModelType.java
+++ b/modules/registry/registry-cpi/src/main/java/org/apache/airavata/registry/cpi/ExperimentCatalogModelType.java
@@ -40,5 +40,7 @@ public enum ExperimentCatalogModelType {
     PROCESS_RESOURCE_SCHEDULE,
     TASK,
     TASK_STATUS,
-    TASK_ERROR
+    TASK_ERROR,
+    JOB,
+    JOB_STATUS
 }