This is an automated email from the ASF dual-hosted git repository.

oleewere pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ambari-infra.git


The following commit(s) were added to refs/heads/master by this push:
     new 07a56bc  AMBARI-24969 - Infra Manager: REST api cleanup (#20)
07a56bc is described below

commit 07a56bc2709c4daa3a762260604bbbe28cc24d64
Author: kasakrisz <33458261+kasakr...@users.noreply.github.com>
AuthorDate: Sat Dec 1 12:49:27 2018 +0100

    AMBARI-24969 - Infra Manager: REST api cleanup (#20)
    
    * AMBARI-24969 - Infra Manager: REST api cleanup
    
    * AMBARI-24969 - Infra Manager: REST api cleanup - fix build
---
 ambari-infra-manager-it/pom.xml                    |  84 ++-
 .../java/org/apache/ambari/infra/InfraClient.java  | 133 +---
 .../ambari/infra/steps/AbstractInfraSteps.java     |  21 +-
 .../apache/ambari/infra/steps/ExportJobsSteps.java |  48 +-
 .../{log4j.properties => log4j2-test.properties}   |  19 +-
 ambari-infra-manager/.gitignore                    |   4 +-
 ambari-infra-manager/docs/api/swagger.yaml         | 784 ---------------------
 ambari-infra-manager/pom.xml                       |  50 +-
 .../ambari/infra/conf/FsPermissionConverter.java   |  37 -
 .../infra/conf/StaticResourceConfiguration.java    |   4 +-
 .../infra/doc/InfraManagerApiDocStorage.java       |  92 ---
 .../ambari/infra/job/archive/DocumentExporter.java |  10 +-
 .../ambari/infra/job/cleanup/TaskHistoryWiper.java |  11 +-
 .../infra/job/deleting/DocumentWiperTasklet.java   |   3 +-
 .../OffsetDateTimeToStringConverter.java}          |  20 +-
 .../infra/json/StringToDurationConverter.java      |  12 +-
 .../infra/json/StringToFsPermissionConverter.java  |  11 +-
 .../apache/ambari/infra/manager/JobManager.java    |  39 +-
 .../DateUtil.java}                                 |  21 +-
 .../infra/model/ExecutionContextResponse.java      |   4 +-
 ...textResponse.java => ISO8601DateFormatter.java} |  35 +-
 .../ambari/infra/model/JobDetailsResponse.java     |  53 --
 .../infra/model/JobExecutionDetailsResponse.java   |  20 +-
 .../infra/model/JobExecutionInfoResponse.java      | 183 +++--
 .../infra/model/JobExecutionRestartRequest.java    |   3 +
 .../infra/model/JobExecutionStopRequest.java       |   3 +
 .../infra/model/JobInstanceDetailsResponse.java    |  30 +-
 .../infra/model/JobInstanceStartRequest.java       |   5 +-
 .../infra/model/StepExecutionContextResponse.java  |  15 +-
 .../infra/model/StepExecutionInfoResponse.java     | 127 ++--
 .../infra/model/StepExecutionProgressResponse.java |  12 +-
 .../infra/model/wrapper/JobExecutionData.java      | 118 ----
 .../infra/model/wrapper/StepExecutionData.java     | 133 ----
 .../apache/ambari/infra/rest/ApiDocResource.java   |  56 --
 .../org/apache/ambari/infra/rest/JobResource.java  |  10 +-
 .../src/main/resources/infra-manager.properties    |   1 +
 .../src/main/resources/swagger/swagger.html        |   2 +-
 .../infra/job/archive/DocumentExporterTest.java    |  31 +-
 .../infra/model/ISO8601DateFormatterTest.java      |  50 ++
 39 files changed, 595 insertions(+), 1699 deletions(-)

diff --git a/ambari-infra-manager-it/pom.xml b/ambari-infra-manager-it/pom.xml
index f1f296b..8745713 100644
--- a/ambari-infra-manager-it/pom.xml
+++ b/ambari-infra-manager-it/pom.xml
@@ -33,9 +33,12 @@
 
   <properties>
     <jbehave.version>4.0.5</jbehave.version>
-    <failsafe-plugin.version>2.20</failsafe-plugin.version>
-    <infra-manager.docker.host>localhost</infra-manager.docker.host>
+    <failsafePlugin.version>2.20</failsafePlugin.version>
+    <infraManager.docker.host>localhost</infraManager.docker.host>
     <stories.location>NONE</stories.location>
+    <okhttp.version>2.7.5</okhttp.version>
+    
<generatedSourcesPath>${project.build.directory}/generated-sources</generatedSourcesPath>
+    <generatedSourcesJavaPath>main/java</generatedSourcesJavaPath>
   </properties>
 
   <dependencies>
@@ -167,6 +170,32 @@
       <artifactId>log4j-core</artifactId>
       <version>2.11.1</version>
     </dependency>
+    <!-- swagger client related -->
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.swagger</groupId>
+      <artifactId>swagger-annotations</artifactId>
+      <version>1.5.21</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>io.gsonfire</groupId>
+      <artifactId>gson-fire</artifactId>
+      <version>1.8.3</version>
+    </dependency>
+    <dependency>
+      <groupId>com.squareup.okhttp</groupId>
+      <artifactId>okhttp</artifactId>
+      <version>${okhttp.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.squareup.okhttp</groupId>
+      <artifactId>logging-interceptor</artifactId>
+      <version>${okhttp.version}</version>
+    </dependency>
   </dependencies>
 
   <build>
@@ -182,6 +211,53 @@
         <directory>src/test/resources</directory>
       </testResource>
     </testResources>
+    <plugins>
+      <plugin>
+        <groupId>io.swagger</groupId>
+        <artifactId>swagger-codegen-maven-plugin</artifactId>
+        <version>2.3.1</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>generate</goal>
+            </goals>
+            <configuration>
+              
<inputSpec>${project.parent.basedir}/ambari-infra-manager/src/main/resources/swagger/swagger.yaml</inputSpec>
+              <language>java</language>
+              <generateApiTests>false</generateApiTests>
+              <generateModelTests>false</generateModelTests>
+              <output>${generatedSourcesPath}</output>
+              <configOptions>
+                <sourceFolder>${generatedSourcesJavaPath}</sourceFolder>
+                <apiPackage>org.apache.ambari.infra.client.api</apiPackage>
+                
<modelPackage>org.apache.ambari.infra.client.model</modelPackage>
+                
<invokerPackage>org.apache.ambari.infra.client.invoker</invokerPackage>
+                <dateLibrary>java8</dateLibrary>
+              </configOptions>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>3.0.0</version>
+        <executions>
+          <execution>
+            <id>add-generated-source</id>
+            <phase>initialize</phase>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                
<source>${generatedSourcesPath}/${generatedSourcesJavaPath}</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
   </build>
 
   <profiles>
@@ -197,7 +273,7 @@
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-failsafe-plugin</artifactId>
-            <version>${failsafe-plugin.version}</version>
+            <version>${failsafePlugin.version}</version>
             <executions>
               <execution>
                 <id>run-integration-tests</id>
@@ -212,7 +288,7 @@
                   </includes>
                   <systemPropertyVariables>
                     
<log4j.configuration>file:${project.build.testOutputDirectory}/log4j.properties</log4j.configuration>
-                    <docker.host>${infra-manager.docker.host}</docker.host>
+                    <docker.host>${infraManager.docker.host}</docker.host>
                     
<backend.stories.location>${stories.location}</backend.stories.location>
                   </systemPropertyVariables>
                 </configuration>
diff --git 
a/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/InfraClient.java
 
b/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/InfraClient.java
index 1b0b4cf..bce3c7e 100644
--- 
a/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/InfraClient.java
+++ 
b/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/InfraClient.java
@@ -18,134 +18,59 @@
  */
 package org.apache.ambari.infra;
 
-import static org.apache.commons.lang.StringUtils.isBlank;
+import java.util.List;
 
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.util.HashMap;
-import java.util.Map;
+import org.apache.ambari.infra.client.api.JobsApi;
+import org.apache.ambari.infra.client.invoker.ApiClient;
+import org.apache.ambari.infra.client.invoker.ApiException;
+import org.apache.ambari.infra.client.model.JobExecutionInfoResponse;
 
-import org.apache.commons.io.IOUtils;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.CredentialsProvider;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpRequestBase;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.impl.client.BasicCredentialsProvider;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-// TODO: use swagger
-public class InfraClient implements AutoCloseable {
-  private static final Logger logger = LogManager.getLogger(InfraClient.class);
-
-  private final CloseableHttpClient httpClient;
-  private final URI baseUrl;
+public class InfraClient {
+  private final JobsApi jobsApi;
 
   public InfraClient(String baseUrl) {
+    ApiClient apiClient = new ApiClient().setBasePath(baseUrl);
+    apiClient.setUsername("admin");
+    apiClient.setPassword("admin");
+    this.jobsApi = new JobsApi(apiClient);
+  }
+
+  public List<String> getJobs() {
     try {
-      this.baseUrl = new URI(baseUrl);
-    } catch (URISyntaxException e) {
+      return jobsApi.getAllJobNames();
+    } catch (ApiException e) {
       throw new RuntimeException(e);
     }
-
-    CredentialsProvider provider = new BasicCredentialsProvider();
-    UsernamePasswordCredentials credentials
-            = new UsernamePasswordCredentials("admin", "admin");
-    provider.setCredentials(AuthScope.ANY, credentials);
-
-    httpClient = HttpClientBuilder.create()
-            .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
-            .setDefaultCredentialsProvider(provider)
-            .build();
-  }
-
-  @Override
-  public void close() throws Exception {
-    httpClient.close();
   }
 
-  // TODO: return job data
-  public void getJobs() {
-    execute(new HttpGet(baseUrl));
-  }
-
-  private HttpResponse execute(HttpRequestBase post) {
-    try (CloseableHttpResponse response = httpClient.execute(post)) {
-      String responseBodyText = 
IOUtils.toString(response.getEntity().getContent(), Charset.defaultCharset());
-      int statusCode = response.getStatusLine().getStatusCode();
-      logger.info("Response code {} body {} ", statusCode, responseBodyText);
-      if (!(200 <= statusCode && statusCode <= 299))
-        throw new RuntimeException("Error while executing http request: " + 
responseBodyText);
-      return new HttpResponse(statusCode, responseBodyText);
-    } catch (ClientProtocolException e) {
+  public JobExecutionInfoResponse startJob(String jobName, String parameters) {
+    try {
+      return jobsApi.startJob(jobName, parameters);
+    } catch (ApiException e) {
       throw new RuntimeException(e);
-    } catch (IOException e) {
-      throw new UncheckedIOException(e);
     }
   }
 
-  public JobExecutionInfo startJob(String jobName, String parameters) {
-    URIBuilder uriBuilder = new URIBuilder(baseUrl);
-    uriBuilder.setScheme("http");
-    uriBuilder.setPath(uriBuilder.getPath() + "/" + jobName);
-    if (!isBlank(parameters))
-      uriBuilder.addParameter("params", parameters);
+  public void restartJob(String jobName, long jobId) {
     try {
-      String responseText = execute(new 
HttpPost(uriBuilder.build())).getBody();
-      Map<String, Object> responseContent = new 
ObjectMapper().readValue(responseText, new 
TypeReference<HashMap<String,Object>>() {});
-      if (!responseContent.containsKey("jobId"))
-        throw new NullPointerException("jobId is not found in start job 
responseContent");
-      if (!responseContent.containsKey("jobExecutionData"))
-        throw new NullPointerException("jobExecutionData is not found in start 
job responseContent");
-      if (!((Map)responseContent.get("jobExecutionData")).containsKey("id"))
-        throw new NullPointerException("id is not found in jobExecutionData");
-      return new JobExecutionInfo(responseContent.get("jobId").toString(), 
((Map)responseContent.get("jobExecutionData")).get("id").toString());
-    } catch (URISyntaxException | JsonParseException | JsonMappingException e) 
{
+      jobsApi.restartJobInstance(jobName, jobId, "RESTART");
+    } catch (ApiException e) {
       throw new RuntimeException(e);
-    } catch (IOException e) {
-      throw new UncheckedIOException(e);
     }
   }
 
-  public void restartJob(String jobName, String jobId) {
-    URIBuilder uriBuilder = new URIBuilder(baseUrl);
-    uriBuilder.setScheme("http");
-    uriBuilder.setPath(String.format("%s/%s/%s/executions", 
uriBuilder.getPath(), jobName, jobId));
-    uriBuilder.addParameter("operation", "RESTART");
+  public void stopJob(long jobExecutionId) {
     try {
-      HttpResponse httpResponse = execute(new HttpPost(uriBuilder.build()));
-      if (httpResponse.getCode() != 200)
-        throw new RuntimeException(httpResponse.getBody());
-    } catch (URISyntaxException e) {
+      jobsApi.stopOrAbandonJobExecution(jobExecutionId, "STOP");
+    } catch (ApiException e) {
       throw new RuntimeException(e);
     }
   }
 
-  public void stopJob(String jobExecutionId) {
-    URIBuilder uriBuilder = new URIBuilder(baseUrl);
-    uriBuilder.setScheme("http");
-    uriBuilder.setPath(String.format("%s/executions/%s", uriBuilder.getPath(), 
jobExecutionId));
-    uriBuilder.addParameter("operation", "STOP");
+  public boolean isRunning(String jobName) {
     try {
-      execute(new HttpDelete(uriBuilder.build()));
-    } catch (URISyntaxException e) {
+      return !jobsApi.getExecutionIdsByJobName(jobName).isEmpty();
+    } catch (ApiException e) {
       throw new RuntimeException(e);
     }
   }
diff --git 
a/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/steps/AbstractInfraSteps.java
 
b/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/steps/AbstractInfraSteps.java
index 9ecf489..985fda5 100644
--- 
a/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/steps/AbstractInfraSteps.java
+++ 
b/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/steps/AbstractInfraSteps.java
@@ -47,17 +47,16 @@ public abstract class AbstractInfraSteps {
 
   private static final int INFRA_MANAGER_PORT = 61890;
   private static final int FAKE_S3_PORT = 4569;
-  private static final int HDFS_PORT = 9000;
   protected static final String S3_BUCKET_NAME = "testbucket";
   private String ambariFolder;
   private String shellScriptLocation;
-  private String dockerHost;
   private S3Client s3client;
   private int documentId = 0;
   private Solr solr;
+  private InfraClient infraClient;
 
   public InfraClient getInfraClient() {
-    return new InfraClient(String.format("http://%s:%d/api/v1/jobs";, 
dockerHost, INFRA_MANAGER_PORT));
+    return infraClient;
   }
 
   public Solr getSolr() {
@@ -89,13 +88,16 @@ public abstract class AbstractInfraSteps {
       FileUtils.cleanDirectory(new File(localDataFolder));
     }
 
+    logger.info("Copy resources");
     FileUtils.copyDirectory(new ClassPathResource("conf").getFile(), new 
File(getInfraManagerConfDir()));
 
     shellScriptLocation = ambariFolder + 
"/ambari-infra/ambari-infra-manager/docker/infra-manager-docker-compose.sh";
     logger.info("Create new docker container for testing Ambari Infra Manager 
...");
     runCommand(new String[]{shellScriptLocation, "start"});
 
-    dockerHost = getDockerHost();
+    String dockerHost = getDockerHost();
+
+    this.infraClient = new InfraClient(String.format("http://%s:%d/api/v1";, 
dockerHost, INFRA_MANAGER_PORT));
 
     solr = new Solr();
     solr.waitUntilSolrIsUp();
@@ -110,11 +112,10 @@ public abstract class AbstractInfraSteps {
     checkInfraManagerReachable();
   }
 
-  private void checkInfraManagerReachable() throws Exception {
-    try (InfraClient httpClient = getInfraClient()) {
-      doWithin(30, "Start Ambari Infra Manager", httpClient::getJobs);
-      logger.info("Ambari Infra Manager is up and running");
-    }
+  private void checkInfraManagerReachable() {
+    InfraClient infraClient = getInfraClient();
+    doWithin(30, "Start Ambari Infra Manager", infraClient::getJobs);
+    logger.info("Ambari Infra Manager is up and running");
   }
 
   protected SolrInputDocument addDocument(OffsetDateTime logtime) {
@@ -149,7 +150,7 @@ public abstract class AbstractInfraSteps {
     solrInputDocument.addField("logtime", new 
Date(logtime.toInstant().toEpochMilli()));
     solrInputDocument.addField("evtTime", new 
Date(logtime.toInstant().toEpochMilli()));
     solrInputDocument.addField("_ttl_", "+7DAYS");
-    solrInputDocument.addField("_expire_at_", "2017-12-15T10:23:19.106Z");
+    solrInputDocument.addField("_expire_at_", new 
Date(logtime.plusDays(7).toInstant().toEpochMilli()));
     solr.add(solrInputDocument);
     return solrInputDocument;
   }
diff --git 
a/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/steps/ExportJobsSteps.java
 
b/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/steps/ExportJobsSteps.java
index e67762e..0825290 100644
--- 
a/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/steps/ExportJobsSteps.java
+++ 
b/ambari-infra-manager-it/src/test/java/org/apache/ambari/infra/steps/ExportJobsSteps.java
@@ -40,8 +40,8 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.ambari.infra.InfraClient;
-import org.apache.ambari.infra.JobExecutionInfo;
 import org.apache.ambari.infra.S3Client;
+import org.apache.ambari.infra.client.model.JobExecutionInfoResponse;
 import 
org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -58,7 +58,7 @@ public class ExportJobsSteps extends AbstractInfraSteps {
   private static final Logger logger = 
LogManager.getLogger(ExportJobsSteps.class);
   private Set<String> documentIds = new HashSet<>();
 
-  private Map<String, JobExecutionInfo> launchedJobs = new HashMap<>();
+  private Map<String, JobExecutionInfoResponse> launchedJobs = new HashMap<>();
 
   @Given("$count documents in solr")
   public void addDocuments(int count) {
@@ -94,32 +94,24 @@ public class ExportJobsSteps extends AbstractInfraSteps {
   @When("start $jobName job with parameters $parameters after $waitSec 
seconds")
   public void startJob(String jobName, String parameters, int waitSec) throws 
Exception {
     Thread.sleep(waitSec * 1000);
-    try (InfraClient httpClient = getInfraClient()) {
-      JobExecutionInfo jobExecutionInfo = httpClient.startJob(jobName, 
parameters);
-      logger.info("Job {} started: {}", jobName, jobExecutionInfo);
-      launchedJobs.put(jobName, jobExecutionInfo);
-    }
+    JobExecutionInfoResponse jobExecutionInfo = 
getInfraClient().startJob(jobName, parameters);
+    logger.info("Job {} started: {}", jobName, jobExecutionInfo);
+    launchedJobs.put(jobName, jobExecutionInfo);
   }
 
   @When("restart $jobName job within $waitSec seconds")
   public void restartJob(String jobName, int waitSec) {
-    doWithin(waitSec, "Restarting job " + jobName, () -> {
-      try (InfraClient httpClient = getInfraClient()) {
-        httpClient.restartJob(jobName, launchedJobs.get(jobName).getJobId());
-      } catch (Exception e) {
-        throw new RuntimeException(e);
-      }
-    });
+    doWithin(waitSec, "Restarting job " + jobName, () ->
+            getInfraClient().restartJob(jobName, 
launchedJobs.get(jobName).getJobInstanceId()));
   }
 
   @When("stop job $jobName after at least $count file exists in s3 with 
filename containing text $text within $waitSec seconds")
   public void stopJob(String jobName, int count, String text, int waitSec) 
throws Exception {
     S3Client s3Client = getS3client();
     doWithin(waitSec, "check uploaded files to s3", () -> 
s3Client.listObjectKeys(text).size() > count);
-
-    try (InfraClient httpClient = getInfraClient()) {
-      httpClient.stopJob(launchedJobs.get(jobName).getExecutionId());
-    }
+    InfraClient infraClient = getInfraClient();
+    infraClient.stopJob(launchedJobs.get(jobName).getJobExecutionId());
+    doWithin(waitSec, String.format("Wait for job %s stops", jobName), () -> 
infraClient.isRunning(jobName));
   }
 
   @When("delete file with key $key from s3")
@@ -182,7 +174,7 @@ public class ExportJobsSteps extends AbstractInfraSteps {
 
   @Then("Check $count files exists on local filesystem with filenames 
containing the text $text in the folder $path for job $jobName")
   public void checkNumberOfFilesOnLocalFilesystem(long count, String text, 
String path, String jobName) {
-    File destinationDirectory = new File(getLocalDataFolder(), 
path.replace("${jobId}", launchedJobs.get(jobName).getJobId()));
+    File destinationDirectory = new File(getLocalDataFolder(), 
path.replace("${jobId}", 
Long.toString(launchedJobs.get(jobName).getJobInstanceId())));
     logger.info("Destination directory path: {}", 
destinationDirectory.getAbsolutePath());
     doWithin(5, "Destination directory exists", destinationDirectory::exists);
 
@@ -216,7 +208,21 @@ public class ExportJobsSteps extends AbstractInfraSteps {
   }
 
   @AfterScenario
-  public void waitABit() throws InterruptedException {
-    Thread.sleep(5000);
+  public void waitForJobStops() throws InterruptedException {
+    InfraClient infraClient = getInfraClient();
+    doWithin(20, "Stop all launched jobs", () -> {
+      int runningJobCount = 0;
+      for (String jobName : launchedJobs.keySet()) {
+        if (launchedJobs.get(jobName) == null)
+          continue;
+        if (!infraClient.isRunning(jobName)) {
+          launchedJobs.put(jobName, null);
+        }
+        else {
+          ++runningJobCount;
+        }
+      }
+      return runningJobCount == 0;
+    });
   }
 }
diff --git a/ambari-infra-manager-it/src/test/resources/log4j.properties 
b/ambari-infra-manager-it/src/test/resources/log4j2-test.properties
similarity index 57%
rename from ambari-infra-manager-it/src/test/resources/log4j.properties
rename to ambari-infra-manager-it/src/test/resources/log4j2-test.properties
index 956bc63..4e488fd 100644
--- a/ambari-infra-manager-it/src/test/resources/log4j.properties
+++ b/ambari-infra-manager-it/src/test/resources/log4j2-test.properties
@@ -9,8 +9,17 @@
 #   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.
-log4j.rootLogger=INFO, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p 
%c{1}:%L - %m%n
\ No newline at end of file
+
+status = error
+dest = err
+name = PropertiesConfig
+
+appender.console.type = Console
+appender.console.name = STDOUT
+appender.console.layout.type = PatternLayout
+appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
+appender.console.filter.threshold.type = ThresholdFilter
+appender.console.filter.threshold.level = info
+
+rootLogger.level = info
+rootLogger.appenderRef.stdout.ref = STDOUT
diff --git a/ambari-infra-manager/.gitignore b/ambari-infra-manager/.gitignore
index 4aece78..dd3661e 100644
--- a/ambari-infra-manager/.gitignore
+++ b/ambari-infra-manager/.gitignore
@@ -3,4 +3,6 @@ out/*
 Profile
 .env
 test-out
-test.db
\ No newline at end of file
+test.db
+**/swagger/swagger.json
+**/swagger/swagger.yaml
\ No newline at end of file
diff --git a/ambari-infra-manager/docs/api/swagger.yaml 
b/ambari-infra-manager/docs/api/swagger.yaml
deleted file mode 100644
index 6fad22d..0000000
--- a/ambari-infra-manager/docs/api/swagger.yaml
+++ /dev/null
@@ -1,784 +0,0 @@
----
-swagger: "2.0"
-info:
-  description: "Manager component for Ambari Infra"
-  version: "1.0.0"
-  title: "Infra Manager REST API"
-  license:
-    name: "Apache 2.0"
-    url: "http://www.apache.org/licenses/LICENSE-2.0.html";
-basePath: "/api/v1"
-tags:
-- name: "jobs"
-schemes:
-- "http"
-- "https"
-paths:
-  /jobs:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get all jobs"
-      description: ""
-      operationId: "getAllJobs"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "page"
-        in: "query"
-        required: false
-        type: "integer"
-        default: 0
-        format: "int32"
-      - name: "size"
-        in: "query"
-        required: false
-        type: "integer"
-        default: 20
-        format: "int32"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            type: "array"
-            items:
-              $ref: "#/definitions/JobInfo"
-  /jobs/executions:
-    delete:
-      tags:
-      - "jobs"
-      summary: "Stop all job executions."
-      description: ""
-      operationId: "stopAll"
-      produces:
-      - "application/json"
-      parameters: []
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            type: "integer"
-            format: "int32"
-  /jobs/executions/{jobExecutionId}:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get job and step details for job execution instance."
-      description: ""
-      operationId: "getExecutionInfo"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "jobExecutionId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/JobExecutionDetailsResponse"
-    delete:
-      tags:
-      - "jobs"
-      summary: "Stop or abandon a running job execution."
-      description: ""
-      operationId: "stopOrAbandonJobExecution"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "jobExecutionId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      - name: "operation"
-        in: "query"
-        required: true
-        type: "string"
-        enum:
-        - "STOP"
-        - "ABANDON"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/JobExecutionInfoResponse"
-  /jobs/executions/{jobExecutionId}/context:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get execution context for specific job."
-      description: ""
-      operationId: "getExecutionContextByJobExecId"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "jobExecutionId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/ExecutionContextResponse"
-  /jobs/executions/{jobExecutionId}/steps/{stepExecutionId}:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get step execution details."
-      description: ""
-      operationId: "getStepExecution"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "jobExecutionId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      - name: "stepExecutionId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/StepExecutionInfoResponse"
-  /jobs/executions/{jobExecutionId}/steps/{stepExecutionId}/execution-context:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get the execution context of step execution."
-      description: ""
-      operationId: "getStepExecutionContext"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "jobExecutionId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      - name: "stepExecutionId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/StepExecutionContextResponse"
-  /jobs/executions/{jobExecutionId}/steps/{stepExecutionId}/progress:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get progress of step execution."
-      description: ""
-      operationId: "getStepExecutionProgress"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "jobExecutionId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      - name: "stepExecutionId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/StepExecutionProgressResponse"
-  /jobs/info/names:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get all job names"
-      description: ""
-      operationId: "getAllJobNames"
-      produces:
-      - "application/json"
-      parameters: []
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            type: "array"
-            uniqueItems: true
-            items:
-              type: "string"
-  /jobs/{jobName}:
-    post:
-      tags:
-      - "jobs"
-      summary: "Start a new job instance by job name."
-      description: ""
-      operationId: "startJob"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "jobName"
-        in: "path"
-        required: true
-        type: "string"
-      - name: "params"
-        in: "query"
-        required: false
-        type: "string"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/JobExecutionInfoResponse"
-  /jobs/{jobName}/executions:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get the id values of all the running job instances."
-      description: ""
-      operationId: "getExecutionIdsByJobName"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "jobName"
-        in: "path"
-        required: true
-        type: "string"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            type: "array"
-            uniqueItems: true
-            items:
-              type: "integer"
-              format: "int64"
-  /jobs/{jobName}/info:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get job details by job name."
-      description: ""
-      operationId: "getJobDetails"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "page"
-        in: "query"
-        required: false
-        type: "integer"
-        default: 0
-        format: "int32"
-      - name: "size"
-        in: "query"
-        required: false
-        type: "integer"
-        default: 20
-        format: "int32"
-      - name: "jobName"
-        in: "path"
-        required: true
-        type: "string"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/JobDetailsResponse"
-  /jobs/{jobName}/{jobInstanceId}/executions:
-    get:
-      tags:
-      - "jobs"
-      summary: "Get execution for job instance."
-      description: ""
-      operationId: "getExecutionsForInstance"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "jobName"
-        in: "path"
-        required: true
-        type: "string"
-      - name: "jobInstanceId"
-        in: "path"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            type: "array"
-            items:
-              $ref: "#/definitions/JobExecutionInfoResponse"
-    post:
-      tags:
-      - "jobs"
-      summary: "Restart job instance."
-      description: ""
-      operationId: "restartJobInstance"
-      produces:
-      - "application/json"
-      parameters:
-      - in: "body"
-        name: "body"
-        required: false
-        schema:
-          $ref: "#/definitions/JobExecutionRestartRequest"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/JobExecutionInfoResponse"
-definitions:
-  JobExecutionData:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      executionContext:
-        $ref: "#/definitions/ExecutionContext"
-      jobInstance:
-        $ref: "#/definitions/JobInstance"
-      jobId:
-        type: "integer"
-        format: "int64"
-      jobParameters:
-        $ref: "#/definitions/JobParameters"
-      failureExceptions:
-        type: "array"
-        items:
-          $ref: "#/definitions/Throwable"
-      endTime:
-        type: "string"
-        format: "date-time"
-      exitStatus:
-        $ref: "#/definitions/ExitStatus"
-      createTime:
-        type: "string"
-        format: "date-time"
-      lastUpdated:
-        type: "string"
-        format: "date-time"
-      jobConfigurationName:
-        type: "string"
-      startTime:
-        type: "string"
-        format: "date-time"
-      status:
-        type: "string"
-        enum:
-        - "COMPLETED"
-        - "STARTING"
-        - "STARTED"
-        - "STOPPING"
-        - "STOPPED"
-        - "FAILED"
-        - "ABANDONED"
-        - "UNKNOWN"
-      stepExecutionDataList:
-        type: "array"
-        items:
-          $ref: "#/definitions/StepExecutionData"
-  JobInstance:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      version:
-        type: "integer"
-        format: "int32"
-      jobName:
-        type: "string"
-      instanceId:
-        type: "integer"
-        format: "int64"
-  StepExecutionData:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      jobExecutionId:
-        type: "integer"
-        format: "int64"
-      executionContext:
-        $ref: "#/definitions/ExecutionContext"
-      stepName:
-        type: "string"
-      terminateOnly:
-        type: "boolean"
-        default: false
-      failureExceptions:
-        type: "array"
-        items:
-          $ref: "#/definitions/Throwable"
-      endTime:
-        type: "string"
-        format: "date-time"
-      exitStatus:
-        $ref: "#/definitions/ExitStatus"
-      lastUpdated:
-        type: "string"
-        format: "date-time"
-      commitCount:
-        type: "integer"
-        format: "int32"
-      readCount:
-        type: "integer"
-        format: "int32"
-      filterCount:
-        type: "integer"
-        format: "int32"
-      writeCount:
-        type: "integer"
-        format: "int32"
-      readSkipCount:
-        type: "integer"
-        format: "int32"
-      writeSkipCount:
-        type: "integer"
-        format: "int32"
-      processSkipCount:
-        type: "integer"
-        format: "int32"
-      rollbackCount:
-        type: "integer"
-        format: "int32"
-      startTime:
-        type: "string"
-        format: "date-time"
-      status:
-        type: "string"
-        enum:
-        - "COMPLETED"
-        - "STARTING"
-        - "STARTED"
-        - "STOPPING"
-        - "STOPPED"
-        - "FAILED"
-        - "ABANDONED"
-        - "UNKNOWN"
-  StackTraceElement:
-    type: "object"
-    properties:
-      methodName:
-        type: "string"
-      fileName:
-        type: "string"
-      lineNumber:
-        type: "integer"
-        format: "int32"
-      className:
-        type: "string"
-      nativeMethod:
-        type: "boolean"
-        default: false
-  JobExecutionDetailsResponse:
-    type: "object"
-    properties:
-      jobExecutionInfoResponse:
-        $ref: "#/definitions/JobExecutionInfoResponse"
-      stepExecutionInfoList:
-        type: "array"
-        items:
-          $ref: "#/definitions/StepExecutionInfoResponse"
-  StepExecutionContextResponse:
-    type: "object"
-    properties:
-      executionContextMap:
-        type: "object"
-        additionalProperties:
-          type: "object"
-      jobExecutionId:
-        type: "integer"
-        format: "int64"
-      stepExecutionId:
-        type: "integer"
-        format: "int64"
-      stepName:
-        type: "string"
-  StepExecutionProgress:
-    type: "object"
-    properties:
-      estimatedPercentCompleteMessage:
-        $ref: "#/definitions/MessageSourceResolvable"
-      estimatedPercentComplete:
-        type: "number"
-        format: "double"
-  ExitStatus:
-    type: "object"
-    properties:
-      exitCode:
-        type: "string"
-      exitDescription:
-        type: "string"
-      running:
-        type: "boolean"
-        default: false
-  ExecutionContextResponse:
-    type: "object"
-    properties:
-      jobExecutionId:
-        type: "integer"
-        format: "int64"
-      executionContextMap:
-        type: "object"
-        additionalProperties:
-          type: "object"
-  StepExecutionHistory:
-    type: "object"
-    properties:
-      stepName:
-        type: "string"
-      count:
-        type: "integer"
-        format: "int32"
-      commitCount:
-        $ref: "#/definitions/CumulativeHistory"
-      rollbackCount:
-        $ref: "#/definitions/CumulativeHistory"
-      readCount:
-        $ref: "#/definitions/CumulativeHistory"
-      writeCount:
-        $ref: "#/definitions/CumulativeHistory"
-      filterCount:
-        $ref: "#/definitions/CumulativeHistory"
-      readSkipCount:
-        $ref: "#/definitions/CumulativeHistory"
-      writeSkipCount:
-        $ref: "#/definitions/CumulativeHistory"
-      processSkipCount:
-        $ref: "#/definitions/CumulativeHistory"
-      duration:
-        $ref: "#/definitions/CumulativeHistory"
-      durationPerRead:
-        $ref: "#/definitions/CumulativeHistory"
-  TimeZone:
-    type: "object"
-    properties:
-      displayName:
-        type: "string"
-      id:
-        type: "string"
-      dstsavings:
-        type: "integer"
-        format: "int32"
-      rawOffset:
-        type: "integer"
-        format: "int32"
-  MessageSourceResolvable:
-    type: "object"
-    properties:
-      arguments:
-        type: "array"
-        items:
-          type: "object"
-      codes:
-        type: "array"
-        items:
-          type: "string"
-      defaultMessage:
-        type: "string"
-  ExecutionContext:
-    type: "object"
-    properties:
-      dirty:
-        type: "boolean"
-        default: false
-      empty:
-        type: "boolean"
-        default: false
-  StepExecutionInfoResponse:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      jobExecutionId:
-        type: "integer"
-        format: "int64"
-      jobName:
-        type: "string"
-      name:
-        type: "string"
-      startDate:
-        type: "string"
-      startTime:
-        type: "string"
-      duration:
-        type: "string"
-      durationMillis:
-        type: "integer"
-        format: "int64"
-      exitCode:
-        type: "string"
-      status:
-        type: "string"
-  JobExecutionInfoResponse:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      stepExecutionCount:
-        type: "integer"
-        format: "int32"
-      jobId:
-        type: "integer"
-        format: "int64"
-      jobName:
-        type: "string"
-      startDate:
-        type: "string"
-      startTime:
-        type: "string"
-      duration:
-        type: "string"
-      jobExecutionData:
-        $ref: "#/definitions/JobExecutionData"
-      jobParameters:
-        type: "object"
-        additionalProperties:
-          type: "object"
-      jobParametersString:
-        type: "string"
-      restartable:
-        type: "boolean"
-        default: false
-      abandonable:
-        type: "boolean"
-        default: false
-      stoppable:
-        type: "boolean"
-        default: false
-      timeZone:
-        $ref: "#/definitions/TimeZone"
-  JobInfo:
-    type: "object"
-    properties:
-      name:
-        type: "string"
-      executionCount:
-        type: "integer"
-        format: "int32"
-      launchable:
-        type: "boolean"
-        default: false
-      incrementable:
-        type: "boolean"
-        default: false
-      jobInstanceId:
-        type: "integer"
-        format: "int64"
-  JobExecutionRestartRequest:
-    type: "object"
-    properties:
-      jobName:
-        type: "string"
-      jobInstanceId:
-        type: "integer"
-        format: "int64"
-      operation:
-        type: "string"
-        enum:
-        - "RESTART"
-  Throwable:
-    type: "object"
-    properties:
-      cause:
-        $ref: "#/definitions/Throwable"
-      stackTrace:
-        type: "array"
-        items:
-          $ref: "#/definitions/StackTraceElement"
-      message:
-        type: "string"
-      localizedMessage:
-        type: "string"
-      suppressed:
-        type: "array"
-        items:
-          $ref: "#/definitions/Throwable"
-  JobParameters:
-    type: "object"
-    properties:
-      parameters:
-        type: "object"
-        additionalProperties:
-          $ref: "#/definitions/JobParameter"
-      empty:
-        type: "boolean"
-        default: false
-  CumulativeHistory:
-    type: "object"
-    properties:
-      count:
-        type: "integer"
-        format: "int32"
-      min:
-        type: "number"
-        format: "double"
-      max:
-        type: "number"
-        format: "double"
-      standardDeviation:
-        type: "number"
-        format: "double"
-      mean:
-        type: "number"
-        format: "double"
-  JobInstanceDetailsResponse:
-    type: "object"
-    properties:
-      jobInstance:
-        $ref: "#/definitions/JobInstance"
-      jobExecutionInfoResponseList:
-        type: "array"
-        items:
-          $ref: "#/definitions/JobExecutionInfoResponse"
-  JobParameter:
-    type: "object"
-    properties:
-      identifying:
-        type: "boolean"
-        default: false
-      value:
-        type: "object"
-      type:
-        type: "string"
-        enum:
-        - "STRING"
-        - "DATE"
-        - "LONG"
-        - "DOUBLE"
-  StepExecutionProgressResponse:
-    type: "object"
-    properties:
-      stepExecutionProgress:
-        $ref: "#/definitions/StepExecutionProgress"
-      stepExecutionHistory:
-        $ref: "#/definitions/StepExecutionHistory"
-      stepExecutionInfoResponse:
-        $ref: "#/definitions/StepExecutionInfoResponse"
-  JobDetailsResponse:
-    type: "object"
-    properties:
-      jobInfo:
-        $ref: "#/definitions/JobInfo"
-      jobInstanceDetailsResponseList:
-        type: "array"
-        items:
-          $ref: "#/definitions/JobInstanceDetailsResponse"
diff --git a/ambari-infra-manager/pom.xml b/ambari-infra-manager/pom.xml
index 722bf51..d595f99 100644
--- a/ambari-infra-manager/pom.xml
+++ b/ambari-infra-manager/pom.xml
@@ -30,18 +30,19 @@
   <artifactId>ambari-infra-manager</artifactId>
 
   <properties>
-    <spring.version>5.1.1.RELEASE</spring.version>
-    <spring.security.version>5.1.1.RELEASE</spring.security.version>
+    <spring.version>5.1.3.RELEASE</spring.version>
+    <spring.security.version>5.1.2.RELEASE</spring.security.version>
     <spring.ldap.version>2.3.2.RELEASE</spring.ldap.version>
     <jersey.version>2.27</jersey.version>
     <jetty.version>9.4.11.v20180605</jetty.version>
-    <spring-batch.version>3.0.7.RELEASE</spring-batch.version>
+    <spring-batch.version>4.1.0.RELEASE</spring-batch.version>
     <sqlite.version>3.8.11.2</sqlite.version>
     <spring-data-solr.version>3.0.10.RELEASE</spring-data-solr.version>
     <spring-boot.version>2.0.6.RELEASE</spring-boot.version>
     <swagger.version>1.5.16</swagger.version>
     <jjwt.version>0.6.0</jjwt.version>
     <aws-sdk.version>1.11.445</aws-sdk.version>
+    <swagger-maven-plugin-version>3.1.7</swagger-maven-plugin-version>
   </properties>
 
   <build>
@@ -117,6 +118,49 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>com.github.kongchen</groupId>
+        <artifactId>swagger-maven-plugin</artifactId>
+        <version>${swagger-maven-plugin-version}</version>
+        <configuration>
+          <apiSources>
+            <apiSource>
+              <springmvc>false</springmvc>
+              <locations>org.apache.ambari.infra.rest</locations>
+              <schemes>
+                <scheme>http</scheme>
+                <scheme>https</scheme>
+              </schemes>
+              <basePath>/api/v1</basePath>
+              <info>
+                <title>Infra Manager REST API</title>
+                <version>1.0.0</version>
+                <description>Ambari Infra Manager REST APIs has inherent 
support for querying, sorting and pagination</description>
+                <license>
+                  <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+                  <name>Apache License, Version 2.0</name>
+                </license>
+              </info>
+              <outputFormats>yaml,json</outputFormats>
+              
<swaggerDirectory>${project.basedir}/src/main/resources/swagger</swaggerDirectory>
+              <securityDefinitions>
+                <securityDefinition>
+                  <name>basicAuth</name>
+                  <type>basic</type>
+                </securityDefinition>
+              </securityDefinitions>
+            </apiSource>
+          </apiSources>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>compile</phase>
+            <goals>
+              <goal>generate</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/FsPermissionConverter.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/FsPermissionConverter.java
deleted file mode 100644
index 5e794a7..0000000
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/FsPermissionConverter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.ambari.infra.conf;
-
-import static 
org.apache.ambari.infra.json.StringToFsPermissionConverter.toFsPermission;
-
-import javax.annotation.Nullable;
-import javax.inject.Named;
-
-import org.apache.hadoop.fs.permission.FsPermission;
-import 
org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
-import org.springframework.core.convert.converter.Converter;
-
-@Named
-@ConfigurationPropertiesBinding
-public class FsPermissionConverter implements Converter<String, FsPermission> {
-  @Override
-  public FsPermission convert(@Nullable String s) {
-    return toFsPermission(s);
-  }
-}
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/StaticResourceConfiguration.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/StaticResourceConfiguration.java
index f0cd3cf..9651271 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/StaticResourceConfiguration.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/StaticResourceConfiguration.java
@@ -22,11 +22,11 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 import 
org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import 
org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
-import 
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 @EnableWebMvc
 @Configuration
-public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {
+public class StaticResourceConfiguration implements WebMvcConfigurer {
 
   private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
     "classpath:/static/", 
"classpath:/swagger/","classpath:META-INF/resources/webjars/"
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/doc/InfraManagerApiDocStorage.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/doc/InfraManagerApiDocStorage.java
deleted file mode 100644
index 5ababcc..0000000
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/doc/InfraManagerApiDocStorage.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.ambari.infra.doc;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import io.swagger.jaxrs.config.BeanConfig;
-import io.swagger.models.Swagger;
-import io.swagger.models.auth.BasicAuthDefinition;
-import io.swagger.util.Yaml;
-
-@Named
-public class InfraManagerApiDocStorage {
-
-  private static final Logger logger = 
LogManager.getLogger(InfraManagerApiDocStorage.class);
-
-  private final Map<String, Object> swaggerMap = new ConcurrentHashMap<>();
-
-  @Inject
-  private BeanConfig beanConfig;
-
-  @PostConstruct
-  private void postConstruct() {
-    Thread loadApiDocThread = new Thread("load_swagger_api_doc") {
-      @Override
-      public void run() {
-        logger.info("Start thread to scan REST API doc from endpoints.");
-        Swagger swagger = beanConfig.getSwagger();
-        swagger.addSecurityDefinition("basicAuth", new BasicAuthDefinition());
-        beanConfig.configure(swagger);
-        beanConfig.scanAndRead();
-        setSwagger(swagger);
-        try {
-          String yaml = Yaml.mapper().writeValueAsString(swagger);
-          StringBuilder b = new StringBuilder();
-          String[] parts = yaml.split("\n");
-          for (String part : parts) {
-            b.append(part);
-            b.append("\n");
-          }
-          setSwaggerYaml(b.toString());
-        } catch (Exception e) {
-          e.printStackTrace();
-        }
-        logger.info("Scanning REST API endpoints and generating docs has been 
successful.");
-      }
-    };
-    loadApiDocThread.setDaemon(true);
-    loadApiDocThread.start();
-  }
-
-  public Swagger getSwagger() {
-    return (Swagger) swaggerMap.get("swaggerObject");
-  }
-
-  public void setSwagger(final Swagger swagger) {
-    swaggerMap.put("swaggerObject", swagger);
-  }
-
-  public void setSwaggerYaml(final String swaggerYaml) {
-    swaggerMap.put("swaggerYaml", swaggerYaml);
-  }
-
-  public String getSwaggerYaml() {
-    return (String) swaggerMap.get("swaggerYaml");
-  }
-
-}
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/archive/DocumentExporter.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/archive/DocumentExporter.java
index f61746d..8c4a067 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/archive/DocumentExporter.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/archive/DocumentExporter.java
@@ -21,7 +21,6 @@ package org.apache.ambari.infra.job.archive;
 import org.apache.ambari.infra.job.JobContextRepository;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.springframework.batch.core.BatchStatus;
 import org.springframework.batch.core.ExitStatus;
 import org.springframework.batch.core.StepContribution;
 import org.springframework.batch.core.StepExecution;
@@ -31,6 +30,7 @@ import org.springframework.batch.core.step.tasklet.Tasklet;
 import org.springframework.batch.item.ExecutionContext;
 import org.springframework.batch.item.ItemStreamReader;
 import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.lang.NonNull;
 
 public class DocumentExporter implements Tasklet, StepExecutionListener {
 
@@ -50,12 +50,12 @@ public class DocumentExporter implements Tasklet, 
StepExecutionListener {
   }
 
   @Override
-  public void beforeStep(StepExecution stepExecution) {
+  public void beforeStep(@NonNull StepExecution stepExecution) {
 
   }
 
   @Override
-  public ExitStatus afterStep(StepExecution stepExecution) {
+  public ExitStatus afterStep(@NonNull StepExecution stepExecution) {
     if (complete) {
       return ExitStatus.COMPLETED;
     }
@@ -65,7 +65,7 @@ public class DocumentExporter implements Tasklet, 
StepExecutionListener {
   }
 
   @Override
-  public RepeatStatus execute(StepContribution contribution, ChunkContext 
chunkContext) throws Exception {
+  public RepeatStatus execute(@NonNull StepContribution contribution, @NonNull 
ChunkContext chunkContext) throws Exception {
     StepExecution stepExecution = 
chunkContext.getStepContext().getStepExecution();
     ExecutionContext executionContext = stepExecution.getExecutionContext();
     documentReader.open(executionContext);
@@ -77,7 +77,7 @@ public class DocumentExporter implements Tasklet, 
StepExecutionListener {
       while ((document = documentReader.read()) != null) {
         if (writer != null && writtenCount >= writeBlockSize) {
           stepExecution = 
jobContextRepository.getStepExecution(stepExecution.getJobExecutionId(), 
stepExecution.getId());
-          if (stepExecution.getJobExecution().getStatus() == 
BatchStatus.STOPPING) {
+          if (stepExecution.isTerminateOnly()) {
             logger.info("Received stop signal.");
             writer.revert();
             writer = null;
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/cleanup/TaskHistoryWiper.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/cleanup/TaskHistoryWiper.java
index 5a296de..2627f4c 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/cleanup/TaskHistoryWiper.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/cleanup/TaskHistoryWiper.java
@@ -28,20 +28,21 @@ import org.springframework.batch.core.StepContribution;
 import org.springframework.batch.core.scope.context.ChunkContext;
 import org.springframework.batch.core.step.tasklet.Tasklet;
 import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.lang.NonNull;
 
 public class TaskHistoryWiper implements Tasklet {
 
   private static final Logger logger = 
LogManager.getLogger(TaskHistoryWiper.class);
-  public static final Duration DEFAULT_TTL = Duration.ofHours(1);
+  private static final Duration MINIMUM_TTL = Duration.ofHours(1);
 
   private final InfraJobExecutionDao infraJobExecutionDao;
   private final Duration ttl;
 
   public TaskHistoryWiper(InfraJobExecutionDao infraJobExecutionDao, Duration 
ttl) {
     this.infraJobExecutionDao = infraJobExecutionDao;
-    if (ttl == null || ttl.compareTo(DEFAULT_TTL) < 0) {
-      logger.info("The ttl value ({}) less than the minimum required. Using 
the default ({}) instead", ttl, DEFAULT_TTL);
-      this.ttl = DEFAULT_TTL;
+    if (ttl == null || ttl.compareTo(MINIMUM_TTL) < 0) {
+      logger.info("The ttl value ({}) less than the minimum required. Using 
the minimum ({}) instead", ttl, MINIMUM_TTL);
+      this.ttl = MINIMUM_TTL;
     }
     else {
       this.ttl = ttl;
@@ -49,7 +50,7 @@ public class TaskHistoryWiper implements Tasklet {
   }
 
   @Override
-  public RepeatStatus execute(StepContribution contribution, ChunkContext 
chunkContext) {
+  public RepeatStatus execute(@NonNull StepContribution contribution, @NonNull 
ChunkContext chunkContext) {
     infraJobExecutionDao.deleteJobExecutions(OffsetDateTime.now().minus(ttl));
     return RepeatStatus.FINISHED;
   }
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/deleting/DocumentWiperTasklet.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/deleting/DocumentWiperTasklet.java
index cae64f4..9bde32a 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/deleting/DocumentWiperTasklet.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/job/deleting/DocumentWiperTasklet.java
@@ -26,6 +26,7 @@ import org.springframework.batch.core.StepContribution;
 import org.springframework.batch.core.scope.context.ChunkContext;
 import org.springframework.batch.core.step.tasklet.Tasklet;
 import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.lang.NonNull;
 
 public class DocumentWiperTasklet extends SolrDAOBase implements Tasklet {
   private final DeletingProperties parameters;
@@ -36,7 +37,7 @@ public class DocumentWiperTasklet extends SolrDAOBase 
implements Tasklet {
   }
 
   @Override
-  public RepeatStatus execute(StepContribution contribution, ChunkContext 
chunkContext) {
+  public RepeatStatus execute(@NonNull StepContribution contribution, @NonNull 
ChunkContext chunkContext) {
     delete(String.format("%s:[%s TO %s]",
             parameters.getFilterField(),
             getValue(parameters.getStart()),
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/DurationConverter.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/OffsetDateTimeToStringConverter.java
similarity index 60%
rename from 
ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/DurationConverter.java
rename to 
ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/OffsetDateTimeToStringConverter.java
index 93b4794..25bdf19 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/conf/DurationConverter.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/OffsetDateTimeToStringConverter.java
@@ -16,23 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.ambari.infra.conf;
+package org.apache.ambari.infra.json;
 
-import static 
org.apache.ambari.infra.json.StringToDurationConverter.toDuration;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
 
-import java.time.Duration;
+import com.fasterxml.jackson.databind.util.StdConverter;
 
-import javax.annotation.Nullable;
-import javax.inject.Named;
+public class OffsetDateTimeToStringConverter extends 
StdConverter<OffsetDateTime, String> {
 
-import 
org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
-import org.springframework.core.convert.converter.Converter;
-
-@Named
-@ConfigurationPropertiesBinding
-public class DurationConverter implements Converter<String, Duration> {
   @Override
-  public Duration convert(@Nullable String s) {
-    return toDuration(s);
+  public String convert(OffsetDateTime value) {
+    return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value);
   }
 }
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToDurationConverter.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToDurationConverter.java
index 2a385cf..4746048 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToDurationConverter.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToDurationConverter.java
@@ -20,11 +20,19 @@ package org.apache.ambari.infra.json;
 
 import java.time.Duration;
 
+import javax.inject.Named;
+
+import 
org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.lang.NonNull;
+
 import com.fasterxml.jackson.databind.util.StdConverter;
 
-public class StringToDurationConverter extends StdConverter<String, Duration> {
+@Named
+@ConfigurationPropertiesBinding
+public class StringToDurationConverter extends StdConverter<String, Duration> 
implements Converter<String, Duration> {
   @Override
-  public Duration convert(String value) {
+  public Duration convert(@NonNull String value) {
     return toDuration(value);
   }
 
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToFsPermissionConverter.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToFsPermissionConverter.java
index 70e4902..e271346 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToFsPermissionConverter.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToFsPermissionConverter.java
@@ -20,13 +20,20 @@ package org.apache.ambari.infra.json;
 
 import static org.apache.commons.lang.StringUtils.isBlank;
 
+import javax.inject.Named;
+
 import org.apache.hadoop.fs.permission.FsPermission;
+import 
org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.lang.NonNull;
 
 import com.fasterxml.jackson.databind.util.StdConverter;
 
-public class StringToFsPermissionConverter extends StdConverter<String, 
FsPermission> {
+@Named
+@ConfigurationPropertiesBinding
+public class StringToFsPermissionConverter extends StdConverter<String, 
FsPermission> implements Converter<String, FsPermission> {
   @Override
-  public FsPermission convert(String value) {
+  public FsPermission convert(@NonNull String value) {
     return toFsPermission(value);
   }
 
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/manager/JobManager.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/manager/JobManager.java
index 86ffc1a..7886452 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/manager/JobManager.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/manager/JobManager.java
@@ -18,6 +18,8 @@
  */
 package org.apache.ambari.infra.manager;
 
+import static java.util.Collections.unmodifiableList;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Comparator;
@@ -26,13 +28,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.TimeZone;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.apache.ambari.infra.model.ExecutionContextResponse;
-import org.apache.ambari.infra.model.JobDetailsResponse;
 import org.apache.ambari.infra.model.JobExecutionDetailsResponse;
 import org.apache.ambari.infra.model.JobExecutionInfoResponse;
 import org.apache.ambari.infra.model.JobInstanceDetailsResponse;
@@ -78,8 +78,6 @@ public class JobManager implements Jobs {
   @Inject
   private JobExplorer jobExplorer;
 
-  private TimeZone timeZone = TimeZone.getDefault();
-
   public Set<String> getAllJobNames() {
     return jobOperator.getJobNames();
   }
@@ -97,7 +95,7 @@ public class JobManager implements Jobs {
     if (!running.isEmpty())
       throw new JobExecutionAlreadyRunningException("An instance of this job 
is already active: "+jobName);
 
-    return new JobExecutionInfoResponse(jobService.launch(jobName, 
jobParameters), timeZone);
+    return new JobExecutionInfoResponse(jobService.launch(jobName, 
jobParameters));
   }
 
   @Override
@@ -143,10 +141,10 @@ public class JobManager implements Jobs {
     JobExecution jobExecution = jobService.getJobExecution(jobExecutionId);
     List<StepExecutionInfoResponse> stepExecutionInfoList = new ArrayList<>();
     for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
-      stepExecutionInfoList.add(new StepExecutionInfoResponse(stepExecution, 
timeZone));
+      stepExecutionInfoList.add(new StepExecutionInfoResponse(stepExecution));
     }
-    
stepExecutionInfoList.sort(Comparator.comparing(StepExecutionInfoResponse::getId));
-    return new JobExecutionDetailsResponse(new 
JobExecutionInfoResponse(jobExecution, timeZone), stepExecutionInfoList);
+    
stepExecutionInfoList.sort(Comparator.comparing(StepExecutionInfoResponse::getStepExecutionId));
+    return new JobExecutionDetailsResponse(new 
JobExecutionInfoResponse(jobExecution), stepExecutionInfoList);
   }
 
   /**
@@ -163,7 +161,7 @@ public class JobManager implements Jobs {
       throw new UnsupportedOperationException("Unsupported operaration");
     }
     logger.info("Job {} was marked {}", 
jobExecution.getJobInstance().getJobName(), operation.name());
-    return new JobExecutionInfoResponse(jobExecution, timeZone);
+    return new JobExecutionInfoResponse(jobExecution);
   }
 
   /**
@@ -188,7 +186,7 @@ public class JobManager implements Jobs {
       Collection<JobExecution> jobExecutions = 
jobService.getJobExecutionsForJobInstance(jobName, jobInstanceId);
       JobExecution jobExecution = jobExecutions.iterator().next();
       Long jobExecutionId = jobExecution.getId();
-      return new JobExecutionInfoResponse(jobService.restart(jobExecutionId), 
timeZone);
+      return new JobExecutionInfoResponse(jobService.restart(jobExecutionId));
     } else {
       throw new UnsupportedOperationException("Unsupported operation (try: 
RESTART)");
     }
@@ -223,7 +221,7 @@ public class JobManager implements Jobs {
     JobInstance jobInstance = jobService.getJobInstance(jobInstanceId);
     Collection<JobExecution> jobExecutions = 
jobService.getJobExecutionsForJobInstance(jobName, jobInstance.getInstanceId());
     for (JobExecution jobExecution : jobExecutions) {
-      result.add(new JobExecutionInfoResponse(jobExecution, timeZone));
+      result.add(new JobExecutionInfoResponse(jobExecution));
     }
     return result;
   }
@@ -231,25 +229,26 @@ public class JobManager implements Jobs {
   /**
    * Get job details for a specific job. (paged)
    */
-  public JobDetailsResponse getJobDetails(String jobName, int page, int size) 
throws NoSuchJobException {
+  public List<JobInstanceDetailsResponse> getJobDetails(String jobName, int 
page, int size) throws NoSuchJobException {
     List<JobInstanceDetailsResponse> jobInstanceResponses = 
Lists.newArrayList();
     Collection<JobInstance> jobInstances = 
jobService.listJobInstances(jobName, page, size);
 
-    int count = jobService.countJobExecutionsForJob(jobName);
     boolean launchable = jobService.isLaunchable(jobName);
-    boolean isIncrementable = jobService.isIncrementable(jobName);
+    boolean incrementable = jobService.isIncrementable(jobName);
 
     for (JobInstance jobInstance: jobInstances) {
-      List<JobExecutionInfoResponse> executionInfos = Lists.newArrayList();
+      List<JobExecutionInfoResponse> executionInfoResponses = 
Lists.newArrayList();
       Collection<JobExecution> jobExecutions = 
jobService.getJobExecutionsForJobInstance(jobName, jobInstance.getId());
       if (jobExecutions != null) {
         for (JobExecution jobExecution : jobExecutions) {
-          executionInfos.add(new JobExecutionInfoResponse(jobExecution, 
timeZone));
+          executionInfoResponses.add(new 
JobExecutionInfoResponse(jobExecution));
         }
       }
-      jobInstanceResponses.add(new JobInstanceDetailsResponse(jobInstance, 
executionInfos));
+      jobInstanceResponses.add(new JobInstanceDetailsResponse(
+              new JobInfo(jobName, executionInfoResponses.size(), 
jobInstance.getInstanceId(), launchable, incrementable),
+              executionInfoResponses));
     }
-    return new JobDetailsResponse(new JobInfo(jobName, count, launchable, 
isIncrementable), jobInstanceResponses);
+    return unmodifiableList(jobInstanceResponses);
   }
 
   /**
@@ -257,7 +256,7 @@ public class JobManager implements Jobs {
    */
   public StepExecutionInfoResponse getStepExecution(Long jobExecutionId, Long 
stepExecutionId) throws NoSuchStepExecutionException, 
NoSuchJobExecutionException {
     StepExecution stepExecution = jobService.getStepExecution(jobExecutionId, 
stepExecutionId);
-    return new StepExecutionInfoResponse(stepExecution, timeZone);
+    return new StepExecutionInfoResponse(stepExecution);
   }
 
   /**
@@ -277,7 +276,7 @@ public class JobManager implements Jobs {
    */
   public StepExecutionProgressResponse getStepExecutionProgress(Long 
jobExecutionId, Long stepExecutionId) throws NoSuchStepExecutionException, 
NoSuchJobExecutionException {
     StepExecution stepExecution = jobService.getStepExecution(jobExecutionId, 
stepExecutionId);
-    StepExecutionInfoResponse stepExecutionInfoResponse = new 
StepExecutionInfoResponse(stepExecution, timeZone);
+    StepExecutionInfoResponse stepExecutionInfoResponse = new 
StepExecutionInfoResponse(stepExecution);
     String stepName = stepExecution.getStepName();
     if (stepName.contains(":partition")) {
       stepName = stepName.replaceAll("(:partition).*", "$1*");
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToDurationConverter.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/DateUtil.java
similarity index 66%
copy from 
ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToDurationConverter.java
copy to 
ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/DateUtil.java
index 2a385cf..810a95b 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/json/StringToDurationConverter.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/DateUtil.java
@@ -16,19 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.ambari.infra.json;
+package org.apache.ambari.infra.model;
 
-import java.time.Duration;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.util.Date;
 
-import com.fasterxml.jackson.databind.util.StdConverter;
-
-public class StringToDurationConverter extends StdConverter<String, Duration> {
-  @Override
-  public Duration convert(String value) {
-    return toDuration(value);
-  }
-
-  public static Duration toDuration(String value) {
-    return value == null ? null : Duration.parse(value);
+public class DateUtil {
+  public static OffsetDateTime toOffsetDateTime(Date date) {
+    if (date == null)
+      return null;
+    return date.toInstant().atOffset(ZoneOffset.UTC);
   }
 }
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ExecutionContextResponse.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ExecutionContextResponse.java
index 2d46c54..0eb1a16 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ExecutionContextResponse.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ExecutionContextResponse.java
@@ -18,6 +18,8 @@
  */
 package org.apache.ambari.infra.model;
 
+import static java.util.Collections.unmodifiableMap;
+
 import java.util.Map;
 
 public class ExecutionContextResponse {
@@ -27,7 +29,7 @@ public class ExecutionContextResponse {
 
   public ExecutionContextResponse(Long jobExecutionId, Map<String, Object> 
executionContextMap) {
     this.jobExecutionId = jobExecutionId;
-    this.executionContextMap = executionContextMap;
+    this.executionContextMap = unmodifiableMap(executionContextMap);
   }
 
   public Long getJobExecutionId() {
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ExecutionContextResponse.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ISO8601DateFormatter.java
similarity index 52%
copy from 
ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ExecutionContextResponse.java
copy to 
ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ISO8601DateFormatter.java
index 2d46c54..5f945b6 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ExecutionContextResponse.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/ISO8601DateFormatter.java
@@ -6,9 +6,9 @@
  * 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
@@ -18,23 +18,24 @@
  */
 package org.apache.ambari.infra.model;
 
-import java.util.Map;
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
 
-public class ExecutionContextResponse {
-
-  private final Long jobExecutionId;
-  private final Map<String, Object> executionContextMap;
-
-  public ExecutionContextResponse(Long jobExecutionId, Map<String, Object> 
executionContextMap) {
-    this.jobExecutionId = jobExecutionId;
-    this.executionContextMap = executionContextMap;
-  }
-
-  public Long getJobExecutionId() {
-    return jobExecutionId;
+public class ISO8601DateFormatter extends DateFormat {
+  @Override
+  public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition 
fieldPosition) {
+    
toAppendTo.append(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(DateUtil.toOffsetDateTime(date)));
+    return toAppendTo;
   }
 
-  public Map<String, Object> getExecutionContextMap() {
-    return executionContextMap;
+  @Override
+  public Date parse(String source, ParsePosition pos) {
+    OffsetDateTime offsetDateTime = OffsetDateTime.parse(source, 
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+    pos.setIndex(pos.getIndex() + source.length());
+    return Date.from(offsetDateTime.toInstant());
   }
 }
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobDetailsResponse.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobDetailsResponse.java
deleted file mode 100644
index cd34fef..0000000
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobDetailsResponse.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.ambari.infra.model;
-
-import org.springframework.batch.admin.web.JobInfo;
-
-import java.util.List;
-
-public class JobDetailsResponse {
-
-  private JobInfo jobInfo;
-  private List<JobInstanceDetailsResponse> jobInstanceDetailsResponseList;
-
-  public JobDetailsResponse() {
-  }
-
-  public JobDetailsResponse(JobInfo jobInfo, List<JobInstanceDetailsResponse> 
jobInstanceDetailsResponseList) {
-    this.jobInfo = jobInfo;
-    this.jobInstanceDetailsResponseList = jobInstanceDetailsResponseList;
-  }
-
-  public JobInfo getJobInfo() {
-    return jobInfo;
-  }
-
-  public void setJobInfo(JobInfo jobInfo) {
-    this.jobInfo = jobInfo;
-  }
-
-  public List<JobInstanceDetailsResponse> getJobInstanceDetailsResponseList() {
-    return jobInstanceDetailsResponseList;
-  }
-
-  public void 
setJobInstanceDetailsResponseList(List<JobInstanceDetailsResponse> 
jobInstanceDetailsResponseList) {
-    this.jobInstanceDetailsResponseList = jobInstanceDetailsResponseList;
-  }
-}
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionDetailsResponse.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionDetailsResponse.java
index 695b57f..9e19344 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionDetailsResponse.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionDetailsResponse.java
@@ -18,32 +18,30 @@
  */
 package org.apache.ambari.infra.model;
 
+import static java.util.Collections.unmodifiableList;
+
 import java.util.List;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
+
 public class JobExecutionDetailsResponse {
 
-  private JobExecutionInfoResponse jobExecutionInfoResponse;
+  @JsonProperty("jobExecution")
+  private final JobExecutionInfoResponse jobExecutionInfoResponse;
 
-  private List<StepExecutionInfoResponse> stepExecutionInfoList;
+  @JsonProperty("stepExecutionList")
+  private final List<StepExecutionInfoResponse> stepExecutionInfoList;
 
   public JobExecutionDetailsResponse(JobExecutionInfoResponse 
jobExecutionInfoResponse, List<StepExecutionInfoResponse> 
stepExecutionInfoList) {
     this.jobExecutionInfoResponse = jobExecutionInfoResponse;
-    this.stepExecutionInfoList = stepExecutionInfoList;
+    this.stepExecutionInfoList = unmodifiableList(stepExecutionInfoList);
   }
 
   public JobExecutionInfoResponse getJobExecutionInfoResponse() {
     return jobExecutionInfoResponse;
   }
 
-  public void setJobExecutionInfoResponse(JobExecutionInfoResponse 
jobExecutionInfoResponse) {
-    this.jobExecutionInfoResponse = jobExecutionInfoResponse;
-  }
-
   public List<StepExecutionInfoResponse> getStepExecutionInfoList() {
     return stepExecutionInfoList;
   }
-
-  public void setStepExecutionInfoList(List<StepExecutionInfoResponse> 
stepExecutionInfoList) {
-    this.stepExecutionInfoList = stepExecutionInfoList;
-  }
 }
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionInfoResponse.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionInfoResponse.java
index a7e4a4f..1034eb8 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionInfoResponse.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionInfoResponse.java
@@ -18,111 +18,122 @@
  */
 package org.apache.ambari.infra.model;
 
-import org.apache.ambari.infra.model.wrapper.JobExecutionData;
-import org.springframework.batch.admin.web.JobParametersExtractor;
+import static java.util.Collections.unmodifiableList;
+import static org.apache.ambari.infra.model.DateUtil.toOffsetDateTime;
+
+import java.time.Duration;
+import java.time.OffsetDateTime;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.ambari.infra.json.DurationToStringConverter;
+import org.apache.ambari.infra.json.OffsetDateTimeToStringConverter;
 import org.springframework.batch.core.BatchStatus;
 import org.springframework.batch.core.JobExecution;
 import org.springframework.batch.core.JobInstance;
 import org.springframework.batch.core.converter.DefaultJobParametersConverter;
-import org.springframework.batch.core.converter.JobParametersConverter;
 
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Properties;
-import java.util.TimeZone;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import io.swagger.annotations.ApiModelProperty;
 
 public class JobExecutionInfoResponse {
-  private Long id;
-  private int stepExecutionCount;
-  private Long jobId;
-  private String jobName;
-  private String startDate = "";
-  private String startTime = "";
-  private String duration = "";
-  private JobExecutionData jobExecutionData;
-  private Properties jobParameters;
-  private String jobParametersString;
-  private boolean restartable = false;
-  private boolean abandonable = false;
-  private boolean stoppable = false;
-  private final TimeZone timeZone;
-
-
-  public JobExecutionInfoResponse(JobExecution jobExecution, TimeZone 
timeZone) {
-    JobParametersConverter converter = new DefaultJobParametersConverter();
-    this.jobExecutionData = new JobExecutionData(jobExecution);
-    this.timeZone = timeZone;
-    this.id = jobExecutionData.getId();
-    this.jobId = jobExecutionData.getJobId();
-    this.stepExecutionCount = jobExecutionData.getStepExecutions().size();
-    this.jobParameters = 
converter.getProperties(jobExecutionData.getJobParameters());
-    this.jobParametersString = (new 
JobParametersExtractor()).fromJobParameters(jobExecutionData.getJobParameters());
-    JobInstance jobInstance = jobExecutionData.getJobInstance();
+  private static final DefaultJobParametersConverter 
DEFAULT_JOB_PARAMETERS_CONVERTER = new DefaultJobParametersConverter();
+
+  static {
+    DEFAULT_JOB_PARAMETERS_CONVERTER.setDateFormat(new ISO8601DateFormatter());
+  }
+
+  private final Long jobExecutionId;
+  private final Long jobInstanceId;
+  private final String jobName;
+  @JsonSerialize(converter = OffsetDateTimeToStringConverter.class)
+  private final OffsetDateTime creationTime;
+  @JsonSerialize(converter = OffsetDateTimeToStringConverter.class)
+  private final OffsetDateTime startTime;
+  @JsonSerialize(converter = OffsetDateTimeToStringConverter.class)
+  private final OffsetDateTime lastUpdatedTime;
+  @JsonSerialize(converter = OffsetDateTimeToStringConverter.class)
+  private final OffsetDateTime endTime;
+  @JsonSerialize(converter = DurationToStringConverter.class)
+  @ApiModelProperty(dataType = "java.lang.String", example = "PT5.311S")
+  private final Duration duration;
+  private final Properties jobParameters;
+  private final BatchStatus batchStatus;
+  @ApiModelProperty(example = "COMPLETED", allowableValues = "UNKNOWN, 
EXECUTING, COMPLETED, NOOP, FAILED, STOPPED")
+  private final String exitCode;
+  private final String exitDescription;
+  private final boolean restartable;
+  private final boolean abandonable;
+  private final boolean stoppable;
+  private final List<Throwable> failureExceptions;
+  private final String jobConfigurationName;
+
+
+  public JobExecutionInfoResponse(JobExecution jobExecution) {
+    this.jobExecutionId = jobExecution.getId();
+    this.jobInstanceId = jobExecution.getJobId();
+    this.jobParameters = 
DEFAULT_JOB_PARAMETERS_CONVERTER.getProperties(jobExecution.getJobParameters());
+    this.creationTime = toOffsetDateTime(jobExecution.getCreateTime());
+    this.startTime = toOffsetDateTime(jobExecution.getStartTime());
+    this.lastUpdatedTime = toOffsetDateTime(jobExecution.getLastUpdated());
+    this.endTime = toOffsetDateTime(jobExecution.getEndTime());
+    JobInstance jobInstance = jobExecution.getJobInstance();
+    this.batchStatus = jobExecution.getStatus();
+    this.restartable = batchStatus.isGreaterThan(BatchStatus.STOPPING) && 
batchStatus.isLessThan(BatchStatus.ABANDONED);
+    this.abandonable = batchStatus.isGreaterThan(BatchStatus.STARTED) && 
batchStatus != BatchStatus.ABANDONED;
+    this.stoppable = batchStatus.isLessThan(BatchStatus.STOPPING);
+
+    if (jobExecution.getExitStatus() != null) {
+      this.exitCode = jobExecution.getExitStatus().getExitCode();
+      this.exitDescription = jobExecution.getExitStatus().getExitDescription();
+    }
+    else {
+      this.exitCode = null;
+      this.exitDescription = null;
+    }
+
     if(jobInstance != null) {
       this.jobName = jobInstance.getJobName();
-      BatchStatus endTime = jobExecutionData.getStatus();
-      this.restartable = endTime.isGreaterThan(BatchStatus.STOPPING) && 
endTime.isLessThan(BatchStatus.ABANDONED);
-      this.abandonable = endTime.isGreaterThan(BatchStatus.STARTED) && endTime 
!= BatchStatus.ABANDONED;
-      this.stoppable = endTime.isLessThan(BatchStatus.STOPPING);
     } else {
       this.jobName = "?";
     }
 
-    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
-    SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
-    SimpleDateFormat durationFormat = new SimpleDateFormat("HH:mm:ss");
-
-    durationFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
-    timeFormat.setTimeZone(timeZone);
-    dateFormat.setTimeZone(timeZone);
-    if(jobExecutionData.getStartTime() != null) {
-      this.startDate = dateFormat.format(jobExecutionData.getStartTime());
-      this.startTime = timeFormat.format(jobExecutionData.getStartTime());
-      Date endTime1 = jobExecutionData.getEndTime() != null? 
jobExecutionData.getEndTime():new Date();
-      this.duration = durationFormat.format(new Date(endTime1.getTime() - 
jobExecutionData.getStartTime().getTime()));
+    if(startTime != null && endTime != null) {
+      this.duration = Duration.between(startTime, endTime);
+    }
+    else {
+      this.duration = null;
     }
-  }
 
-  public Long getId() {
-    return id;
+    this.failureExceptions = 
unmodifiableList(jobExecution.getFailureExceptions());
+    this.jobConfigurationName = jobExecution.getJobConfigurationName();
   }
 
-  public int getStepExecutionCount() {
-    return stepExecutionCount;
+  public Long getJobExecutionId() {
+    return jobExecutionId;
   }
 
-  public Long getJobId() {
-    return jobId;
+  public Long getJobInstanceId() {
+    return jobInstanceId;
   }
 
   public String getJobName() {
     return jobName;
   }
 
-  public String getStartDate() {
-    return startDate;
-  }
-
-  public String getStartTime() {
+  public OffsetDateTime getStartTime() {
     return startTime;
   }
 
-  public String getDuration() {
+  public Duration getDuration() {
     return duration;
   }
 
-  public JobExecutionData getJobExecutionData() {
-    return jobExecutionData;
-  }
-
   public Properties getJobParameters() {
     return jobParameters;
   }
 
-  public String getJobParametersString() {
-    return jobParametersString;
-  }
-
   public boolean isRestartable() {
     return restartable;
   }
@@ -135,7 +146,35 @@ public class JobExecutionInfoResponse {
     return stoppable;
   }
 
-  public TimeZone getTimeZone() {
-    return timeZone;
+  public BatchStatus getBatchStatus() {
+    return batchStatus;
+  }
+
+  public OffsetDateTime getCreationTime() {
+    return creationTime;
+  }
+
+  public OffsetDateTime getEndTime() {
+    return endTime;
+  }
+
+  public OffsetDateTime getLastUpdatedTime() {
+    return lastUpdatedTime;
+  }
+
+  public String getExitCode() {
+    return exitCode;
+  }
+
+  public String getExitDescription() {
+    return exitDescription;
+  }
+
+  public List<Throwable> getFailureExceptions() {
+    return this.failureExceptions;
+  }
+
+  public String getJobConfigurationName() {
+    return this.jobConfigurationName;
   }
 }
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionRestartRequest.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionRestartRequest.java
index 3eab25f..fe36c5b 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionRestartRequest.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionRestartRequest.java
@@ -22,6 +22,8 @@ import javax.validation.constraints.NotNull;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.QueryParam;
 
+import io.swagger.annotations.ApiParam;
+
 public class JobExecutionRestartRequest {
 
   @PathParam("jobName")
@@ -34,6 +36,7 @@ public class JobExecutionRestartRequest {
 
   @QueryParam("operation")
   @NotNull
+  @ApiParam(required = true)
   private JobOperationParams.JobRestartOperationParam operation;
 
   public String getJobName() {
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionStopRequest.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionStopRequest.java
index b176f12..510e694 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionStopRequest.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobExecutionStopRequest.java
@@ -22,6 +22,8 @@ import javax.validation.constraints.NotNull;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.QueryParam;
 
+import io.swagger.annotations.ApiParam;
+
 public class JobExecutionStopRequest {
 
   @PathParam("jobExecutionId")
@@ -30,6 +32,7 @@ public class JobExecutionStopRequest {
 
   @QueryParam("operation")
   @NotNull
+  @ApiParam(required = true)
   private JobOperationParams.JobStopOrAbandonOperationParam operation;
 
   public Long getJobExecutionId() {
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobInstanceDetailsResponse.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobInstanceDetailsResponse.java
index af88654..9bb7994 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobInstanceDetailsResponse.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobInstanceDetailsResponse.java
@@ -18,37 +18,31 @@
  */
 package org.apache.ambari.infra.model;
 
-import org.springframework.batch.core.JobInstance;
+import static java.util.Collections.unmodifiableList;
 
 import java.util.List;
 
-public class JobInstanceDetailsResponse {
+import org.springframework.batch.admin.web.JobInfo;
 
-  private JobInstance jobInstance;
+import com.fasterxml.jackson.annotation.JsonProperty;
 
-  private List<JobExecutionInfoResponse> jobExecutionInfoResponseList;
 
-  public JobInstanceDetailsResponse() {
-  }
+public class JobInstanceDetailsResponse {
 
-  public JobInstanceDetailsResponse(JobInstance jobInstance, 
List<JobExecutionInfoResponse> jobExecutionInfoResponseList) {
-    this.jobInstance = jobInstance;
-    this.jobExecutionInfoResponseList = jobExecutionInfoResponseList;
-  }
+  private final JobInfo jobInfo;
+  @JsonProperty("jobExecutionList")
+  private final List<JobExecutionInfoResponse> jobExecutionInfoResponseList;
 
-  public JobInstance getJobInstance() {
-    return jobInstance;
+  public JobInstanceDetailsResponse(JobInfo jobInfo, 
List<JobExecutionInfoResponse> jobExecutionInfoResponseList) {
+    this.jobInfo = jobInfo;
+    this.jobExecutionInfoResponseList = 
unmodifiableList(jobExecutionInfoResponseList);
   }
 
-  public void setJobInstance(JobInstance jobInstance) {
-    this.jobInstance = jobInstance;
+  public JobInfo getJobInfo() {
+    return jobInfo;
   }
 
   public List<JobExecutionInfoResponse> getJobExecutionInfoResponseList() {
     return jobExecutionInfoResponseList;
   }
-
-  public void setJobExecutionInfoResponseList(List<JobExecutionInfoResponse> 
jobExecutionInfoResponseList) {
-    this.jobExecutionInfoResponseList = jobExecutionInfoResponseList;
-  }
 }
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobInstanceStartRequest.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobInstanceStartRequest.java
index 905a4fa..5c760f6 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobInstanceStartRequest.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/JobInstanceStartRequest.java
@@ -22,14 +22,17 @@ import javax.validation.constraints.NotNull;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.QueryParam;
 
+import io.swagger.annotations.ApiParam;
+
 public class JobInstanceStartRequest {
 
   @PathParam("jobName")
   @NotNull
+  @ApiParam(required = true)
   private String jobName;
 
   @QueryParam("params")
-  String params;
+  private String params;
 
   public String getJobName() {
     return jobName;
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionContextResponse.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionContextResponse.java
index 0e67a87..9ce56af 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionContextResponse.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionContextResponse.java
@@ -18,23 +18,22 @@
  */
 package org.apache.ambari.infra.model;
 
+import static java.util.Collections.unmodifiableMap;
+
 import java.util.Map;
 
 public class StepExecutionContextResponse {
 
-  private Map<String, Object> executionContextMap;
-
-  private Long jobExecutionId;
+  private final Map<String, Object> executionContextMap;
 
-  private Long stepExecutionId;
+  private final Long jobExecutionId;
 
-  private String stepName;
+  private final Long stepExecutionId;
 
-  public StepExecutionContextResponse() {
-  }
+  private final String stepName;
 
   public StepExecutionContextResponse(Map<String, Object> executionContextMap, 
Long jobExecutionId, Long stepExecutionId, String stepName) {
-    this.executionContextMap = executionContextMap;
+    this.executionContextMap = unmodifiableMap(executionContextMap);
     this.jobExecutionId = jobExecutionId;
     this.stepExecutionId = stepExecutionId;
     this.stepName = stepName;
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionInfoResponse.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionInfoResponse.java
index ed04767..011eaea 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionInfoResponse.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionInfoResponse.java
@@ -18,98 +18,101 @@
  */
 package org.apache.ambari.infra.model;
 
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.apache.ambari.infra.model.wrapper.StepExecutionData;
-import org.springframework.batch.core.JobExecution;
+import static org.apache.ambari.infra.model.DateUtil.toOffsetDateTime;
+
+import java.time.Duration;
+import java.time.OffsetDateTime;
+
+import org.apache.ambari.infra.json.DurationToStringConverter;
+import org.apache.ambari.infra.json.OffsetDateTimeToStringConverter;
+import org.springframework.batch.core.BatchStatus;
 import org.springframework.batch.core.StepExecution;
 
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.TimeZone;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
-public class StepExecutionInfoResponse {
-  private Long id;
-  private Long jobExecutionId;
-  private String jobName;
-  private String name;
-  private String startDate = "-";
-  private String startTime = "-";
-  private String duration = "-";
-  private StepExecutionData stepExecutionData;
-  private long durationMillis;
-
-  public StepExecutionInfoResponse(String jobName, Long jobExecutionId, String 
name, TimeZone timeZone) {
-    this.jobName = jobName;
-    this.jobExecutionId = jobExecutionId;
-    this.name = name;
-    this.stepExecutionData = new StepExecutionData(new StepExecution(name, new 
JobExecution(jobExecutionId)));
-  }
+import io.swagger.annotations.ApiModelProperty;
 
-  public StepExecutionInfoResponse(StepExecution stepExecution, TimeZone 
timeZone) {
-    this.stepExecutionData = new StepExecutionData(stepExecution);
-    this.id = stepExecutionData.getId();
-    this.name = stepExecutionData.getStepName();
-    this.jobName = stepExecutionData.getJobExecution() != null && 
stepExecutionData.getJobExecution().getJobInstance() != null? 
stepExecutionData.getJobExecution().getJobInstance().getJobName():"?";
-    this.jobExecutionId = stepExecutionData.getJobExecutionId();
-    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
-    SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
-    SimpleDateFormat durationFormat = new SimpleDateFormat("HH:mm:ss");
-
-    durationFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
-    timeFormat.setTimeZone(timeZone);
-    dateFormat.setTimeZone(timeZone);
-    if(stepExecutionData.getStartTime() != null) {
-      this.startDate = dateFormat.format(stepExecutionData.getStartTime());
-      this.startTime = timeFormat.format(stepExecutionData.getStartTime());
-      Date endTime = stepExecutionData.getEndTime() != null? 
stepExecutionData.getEndTime():new Date();
-      this.durationMillis = endTime.getTime() - 
stepExecutionData.getStartTime().getTime();
-      this.duration = durationFormat.format(new Date(this.durationMillis));
+public class StepExecutionInfoResponse {
+  private final Long stepExecutionId;
+  private final Long jobExecutionId;
+  private final String jobName;
+  private final String stepName;
+  @JsonSerialize(converter = OffsetDateTimeToStringConverter.class)
+  private final OffsetDateTime startTime;
+  @JsonSerialize(converter = OffsetDateTimeToStringConverter.class)
+  private final OffsetDateTime endTime;
+  @JsonSerialize(converter = DurationToStringConverter.class)
+  @ApiModelProperty(dataType = "java.lang.String", example = "PT5.311S")
+  private final Duration duration;
+  private final BatchStatus batchStatus;
+  @ApiModelProperty(example = "COMPLETED", allowableValues = "UNKNOWN, 
EXECUTING, COMPLETED, NOOP, FAILED, STOPPED")
+  private final String exitCode;
+  private final String exitDescription;
+
+
+  public StepExecutionInfoResponse(StepExecution stepExecution) {
+    this.stepExecutionId = stepExecution.getId();
+    this.stepName = stepExecution.getStepName();
+    this.jobName = stepExecution.getJobExecution() != null && 
stepExecution.getJobExecution().getJobInstance() != null ? 
stepExecution.getJobExecution().getJobInstance().getJobName() : "?";
+    this.jobExecutionId = stepExecution.getJobExecutionId();
+    this.startTime = toOffsetDateTime(stepExecution.getStartTime());
+    this.endTime = toOffsetDateTime(stepExecution.getEndTime());
+
+    if(this.startTime != null && this.endTime != null) {
+      this.duration = Duration.between(this.startTime, this.endTime);
+    }
+    else {
+      this.duration = null;
     }
 
+    this.batchStatus = stepExecution.getStatus();
+    if (stepExecution.getExitStatus() != null) {
+      this.exitCode = stepExecution.getExitStatus().getExitCode();
+      this.exitDescription = 
stepExecution.getExitStatus().getExitDescription();
+    }
+    else {
+      this.exitCode = null;
+      this.exitDescription = null;
+    }
   }
 
-  public Long getId() {
-    return this.id;
+  public Long getStepExecutionId() {
+    return this.stepExecutionId;
   }
 
   public Long getJobExecutionId() {
     return this.jobExecutionId;
   }
 
-  public String getName() {
-    return this.name;
+  public String getStepName() {
+    return this.stepName;
   }
 
   public String getJobName() {
     return this.jobName;
   }
 
-  public String getStartDate() {
-    return this.startDate;
-  }
-
-  public String getStartTime() {
-    return this.startTime;
+  public OffsetDateTime getStartTime() {
+    return startTime;
   }
 
-  public String getDuration() {
-    return this.duration;
+  public OffsetDateTime getEndTime() {
+    return endTime;
   }
 
-  public long getDurationMillis() {
-    return this.durationMillis;
+  public Duration getDuration() {
+    return duration;
   }
 
-  public String getStatus() {
-    return this.id != 
null?this.stepExecutionData.getStatus().toString():"NONE";
+  public BatchStatus getBatchStatus() {
+    return batchStatus;
   }
 
   public String getExitCode() {
-    return this.id != 
null?this.stepExecutionData.getExitStatus().getExitCode():"NONE";
+    return exitCode;
   }
 
-  @JsonIgnore
-  public StepExecutionData getStepExecution() {
-    return this.stepExecutionData;
+  public String getExitDescription() {
+    return exitDescription;
   }
 }
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionProgressResponse.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionProgressResponse.java
index 26f9ed4..d2404e5 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionProgressResponse.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/StepExecutionProgressResponse.java
@@ -21,16 +21,16 @@ package org.apache.ambari.infra.model;
 import org.springframework.batch.admin.history.StepExecutionHistory;
 import org.springframework.batch.admin.web.StepExecutionProgress;
 
-public class StepExecutionProgressResponse {
+import com.fasterxml.jackson.annotation.JsonProperty;
 
-  private StepExecutionProgress stepExecutionProgress;
+public class StepExecutionProgressResponse {
 
-  private StepExecutionHistory stepExecutionHistory;
+  private final StepExecutionProgress stepExecutionProgress;
 
-  private StepExecutionInfoResponse stepExecutionInfoResponse;
+  private final StepExecutionHistory stepExecutionHistory;
 
-  public StepExecutionProgressResponse() {
-  }
+  @JsonProperty("stepExecution")
+  private final StepExecutionInfoResponse stepExecutionInfoResponse;
 
   public StepExecutionProgressResponse(StepExecutionProgress 
stepExecutionProgress, StepExecutionHistory stepExecutionHistory,
                                        StepExecutionInfoResponse 
stepExecutionInfoResponse) {
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/wrapper/JobExecutionData.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/wrapper/JobExecutionData.java
deleted file mode 100644
index 28e262a..0000000
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/wrapper/JobExecutionData.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.ambari.infra.model.wrapper;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.google.common.collect.Lists;
-import org.springframework.batch.core.BatchStatus;
-import org.springframework.batch.core.ExitStatus;
-import org.springframework.batch.core.JobExecution;
-import org.springframework.batch.core.JobInstance;
-import org.springframework.batch.core.JobParameters;
-import org.springframework.batch.core.StepExecution;
-import org.springframework.batch.item.ExecutionContext;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Wrapper for #{{@link JobExecution}}
- */
-public class JobExecutionData {
-
-  private JobExecution jobExecution;
-
-  public JobExecutionData(JobExecution jobExecution) {
-    this.jobExecution = jobExecution;
-  }
-
-  @JsonIgnore
-  public JobExecution getJobExecution() {
-    return jobExecution;
-  }
-
-  @JsonIgnore
-  public Collection<StepExecution> getStepExecutions() {
-    return jobExecution.getStepExecutions();
-  }
-
-  public JobParameters getJobParameters() {
-    return jobExecution.getJobParameters();
-  }
-
-  public JobInstance getJobInstance() {
-    return jobExecution.getJobInstance();
-  }
-
-  public Collection<StepExecutionData> getStepExecutionDataList() {
-    List<StepExecutionData> stepExecutionDataList = Lists.newArrayList();
-    Collection<StepExecution> stepExecutions = getStepExecutions();
-    if (stepExecutions != null) {
-      for (StepExecution stepExecution : stepExecutions) {
-        stepExecutionDataList.add(new StepExecutionData(stepExecution));
-      }
-    }
-    return stepExecutionDataList;
-  }
-
-  public BatchStatus getStatus() {
-    return jobExecution.getStatus();
-  }
-
-  public Date getStartTime() {
-    return jobExecution.getStartTime();
-  }
-
-  public Date getCreateTime() {
-    return jobExecution.getCreateTime();
-  }
-
-  public Date getEndTime() {
-    return jobExecution.getEndTime();
-  }
-
-  public Date getLastUpdated() {
-    return jobExecution.getLastUpdated();
-  }
-
-  public ExitStatus getExitStatus() {
-    return jobExecution.getExitStatus();
-  }
-
-  public ExecutionContext getExecutionContext() {
-    return jobExecution.getExecutionContext();
-  }
-
-  public List<Throwable> getFailureExceptions() {
-    return jobExecution.getFailureExceptions();
-  }
-
-  public String getJobConfigurationName() {
-    return jobExecution.getJobConfigurationName();
-  }
-
-  public Long getId() {
-    return jobExecution.getId();
-  }
-
-  public Long getJobId() {
-    return jobExecution.getJobId();
-  }
-}
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/wrapper/StepExecutionData.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/wrapper/StepExecutionData.java
deleted file mode 100644
index 26552ae..0000000
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/model/wrapper/StepExecutionData.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.ambari.infra.model.wrapper;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.springframework.batch.core.BatchStatus;
-import org.springframework.batch.core.ExitStatus;
-import org.springframework.batch.core.JobExecution;
-import org.springframework.batch.core.StepExecution;
-import org.springframework.batch.item.ExecutionContext;
-
-import java.util.Date;
-import java.util.List;
-
-/**
- * Wrapper for #{{@link StepExecution}}
- */
-public class StepExecutionData {
-
-  @JsonIgnore
-  private final JobExecution jobExecution;
-
-  @JsonIgnore
-  private final StepExecution stepExecution;
-
-
-  public StepExecutionData(StepExecution stepExecution) {
-    this.stepExecution = stepExecution;
-    this.jobExecution = stepExecution.getJobExecution();
-  }
-
-  @JsonIgnore
-  public JobExecution getJobExecution() {
-    return jobExecution;
-  }
-
-  @JsonIgnore
-  public StepExecution getStepExecution() {
-    return stepExecution;
-  }
-
-  public String getStepName() {
-    return stepExecution.getStepName();
-  }
-
-  public int getReadCount() {
-    return stepExecution.getReadCount();
-  }
-
-  public BatchStatus getStatus() {
-    return stepExecution.getStatus();
-  }
-
-  public int getWriteCount() {
-    return stepExecution.getWriteCount();
-  }
-
-  public int getCommitCount() {
-    return stepExecution.getCommitCount();
-  }
-
-  public int getRollbackCount() {
-    return stepExecution.getRollbackCount();
-  }
-
-  public int getReadSkipCount() {
-    return stepExecution.getReadSkipCount();
-  }
-
-  public int getProcessSkipCount() {
-    return stepExecution.getProcessSkipCount();
-  }
-
-  public Date getStartTime() {
-    return stepExecution.getStartTime();
-  }
-
-  public int getWriteSkipCount() {
-    return stepExecution.getWriteSkipCount();
-  }
-
-  public Date getEndTime() {
-    return stepExecution.getEndTime();
-  }
-
-  public Date getLastUpdated() {
-    return stepExecution.getLastUpdated();
-  }
-
-  public ExecutionContext getExecutionContext() {
-    return stepExecution.getExecutionContext();
-  }
-
-  public ExitStatus getExitStatus() {
-    return stepExecution.getExitStatus();
-  }
-
-  public boolean isTerminateOnly() {
-    return stepExecution.isTerminateOnly();
-  }
-
-  public int getFilterCount() {
-    return stepExecution.getFilterCount();
-  }
-
-  public List<Throwable> getFailureExceptions() {
-    return stepExecution.getFailureExceptions();
-  }
-
-  public Long getId() {
-    return stepExecution.getId();
-  }
-
-  public Long getJobExecutionId() {
-    return stepExecution.getJobExecutionId();
-  }
-}
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/rest/ApiDocResource.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/rest/ApiDocResource.java
deleted file mode 100644
index 18dfdd9..0000000
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/rest/ApiDocResource.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.ambari.infra.rest;
-
-import io.swagger.annotations.ApiOperation;
-import org.apache.ambari.infra.doc.InfraManagerApiDocStorage;
-import org.springframework.context.annotation.Scope;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Path("swagger.{type:json|yaml}")
-@Named
-@Scope("request")
-public class ApiDocResource {
-
-  @Inject
-  private InfraManagerApiDocStorage infraManagerApiDocStorage;
-
-  @GET
-  @Produces({MediaType.APPLICATION_JSON, "application/yaml"})
-  @ApiOperation(value = "The swagger definition in either JSON or YAML", 
hidden = true)
-  public Response swaggerDefinitionResponse(@PathParam("type") String type) {
-    Response response = Response.status(404).build();
-    if (infraManagerApiDocStorage.getSwagger() != null) {
-      if ("yaml".equalsIgnoreCase(type)) {
-        response = 
Response.ok().entity(infraManagerApiDocStorage.getSwaggerYaml()).type("application/yaml").build();
-      } else {
-        response = 
Response.ok().entity(infraManagerApiDocStorage.getSwagger()).build();
-      }
-    }
-    return response;
-  }
-}
diff --git 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/rest/JobResource.java
 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/rest/JobResource.java
index 43f7c41..f5de3c0 100644
--- 
a/ambari-infra-manager/src/main/java/org/apache/ambari/infra/rest/JobResource.java
+++ 
b/ambari-infra-manager/src/main/java/org/apache/ambari/infra/rest/JobResource.java
@@ -35,12 +35,12 @@ import javax.ws.rs.Produces;
 
 import org.apache.ambari.infra.manager.JobManager;
 import org.apache.ambari.infra.model.ExecutionContextResponse;
-import org.apache.ambari.infra.model.JobDetailsResponse;
 import org.apache.ambari.infra.model.JobExecutionDetailsResponse;
 import org.apache.ambari.infra.model.JobExecutionInfoResponse;
 import org.apache.ambari.infra.model.JobExecutionRequest;
 import org.apache.ambari.infra.model.JobExecutionRestartRequest;
 import org.apache.ambari.infra.model.JobExecutionStopRequest;
+import org.apache.ambari.infra.model.JobInstanceDetailsResponse;
 import org.apache.ambari.infra.model.JobInstanceStartRequest;
 import org.apache.ambari.infra.model.JobRequest;
 import org.apache.ambari.infra.model.PageRequest;
@@ -120,7 +120,7 @@ public class JobResource {
   @Produces({"application/json"})
   @Path("{jobName}/info")
   @ApiOperation("Get job details by job name.")
-  public JobDetailsResponse getJobDetails(@BeanParam @Valid JobRequest 
jobRequest) throws NoSuchJobException {
+  public List<JobInstanceDetailsResponse> getJobDetails(@BeanParam @Valid 
JobRequest jobRequest) throws NoSuchJobException {
     return jobManager.getJobDetails(jobRequest.getJobName(), 
jobRequest.getPage(), jobRequest.getSize());
   }
 
@@ -136,7 +136,7 @@ public class JobResource {
   @Produces({"application/json"})
   @Path("/executions/{jobExecutionId}")
   @ApiOperation("Get job and step details for job execution instance.")
-  public JobExecutionDetailsResponse 
getExectionInfo(@PathParam("jobExecutionId") @Valid Long jobExecutionId) throws 
NoSuchJobExecutionException {
+  public JobExecutionDetailsResponse 
getExecutionInfo(@PathParam("jobExecutionId") @Valid Long jobExecutionId) 
throws NoSuchJobExecutionException {
     return jobManager.getExecutionInfo(jobExecutionId);
   }
 
@@ -169,8 +169,8 @@ public class JobResource {
   @GET
   @Produces({"application/json"})
   @Path("/{jobName}/{jobInstanceId}/executions")
-  @ApiOperation("Get execution for job instance.")
-  public List<JobExecutionInfoResponse> getExecutionsForInstance(@BeanParam 
@Valid JobExecutionRequest request) throws
+  @ApiOperation("Get execution of job instance.")
+  public List<JobExecutionInfoResponse> getExecutionsOfInstance(@BeanParam 
@Valid JobExecutionRequest request) throws
           NoSuchJobException, NoSuchJobInstanceException {
     return jobManager.getExecutionsForJobInstance(request.getJobName(), 
request.getJobInstanceId());
   }
diff --git a/ambari-infra-manager/src/main/resources/infra-manager.properties 
b/ambari-infra-manager/src/main/resources/infra-manager.properties
index 8133905..c3ec9d0 100644
--- a/ambari-infra-manager/src/main/resources/infra-manager.properties
+++ b/ambari-infra-manager/src/main/resources/infra-manager.properties
@@ -18,6 +18,7 @@ infra-manager.batch.db.init=false
 infra-manager.batch.db.username=admin
 infra-manager.batch.db.password=admin
 infra-manager.server.data.folder=/tmp/ambariInfraManager
+infra-manager.admin-user.password=admin
 
 # Archive Service Logs
 infra-manager.jobs.solr_data_archiving.archive_service_logs.enabled=true
diff --git a/ambari-infra-manager/src/main/resources/swagger/swagger.html 
b/ambari-infra-manager/src/main/resources/swagger/swagger.html
index b24dd25..69478fd 100644
--- a/ambari-infra-manager/src/main/resources/swagger/swagger.html
+++ b/ambari-infra-manager/src/main/resources/swagger/swagger.html
@@ -57,7 +57,7 @@
       var urlPrefix = location.protocol +'//'+ 
location.hostname+(location.port ? ':'+location.port: '');
       // Build a system
       const ui = SwaggerUIBundle({
-        url: urlPrefix + "/api/v1/swagger.yaml",
+        url: urlPrefix + "/swagger.yaml",
         dom_id: '#swagger-ui',
         deepLinking: true,
         presets: [
diff --git 
a/ambari-infra-manager/src/test/java/org/apache/ambari/infra/job/archive/DocumentExporterTest.java
 
b/ambari-infra-manager/src/test/java/org/apache/ambari/infra/job/archive/DocumentExporterTest.java
index d2e7b04..fe2b037 100644
--- 
a/ambari-infra-manager/src/test/java/org/apache/ambari/infra/job/archive/DocumentExporterTest.java
+++ 
b/ambari-infra-manager/src/test/java/org/apache/ambari/infra/job/archive/DocumentExporterTest.java
@@ -36,8 +36,8 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.springframework.batch.core.BatchStatus;
 import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.StepContribution;
 import org.springframework.batch.core.StepExecution;
 import org.springframework.batch.core.scope.context.ChunkContext;
 import org.springframework.batch.core.scope.context.StepContext;
@@ -56,6 +56,8 @@ public class DocumentExporterTest extends EasyMockSupport {
   private static final Document DOCUMENT_3 = new Document(new HashMap<String, 
Object>() {{
     put("id", "3");
   }});
+  private static final StepContribution ANY_STEP_CONTRIBUTION = new 
StepContribution(new StepExecution("any", new JobExecution(1L)));
+
   private DocumentExporter documentExporter;
   @Mock
   private ItemStreamReader<Document> reader;
@@ -74,8 +76,8 @@ public class DocumentExporterTest extends EasyMockSupport {
   private static final Document DOCUMENT = new Document(new HashMap<String, 
Object>() {{ put("id", "1"); }});
 
   @Before
-  public void setUp() throws Exception {
-    chunkContext = chunkContext(BatchStatus.STARTED);
+  public void setUp() {
+    chunkContext = chunkContext(false);
     documentExporter = documentExporter(2);
   }
 
@@ -83,15 +85,16 @@ public class DocumentExporterTest extends EasyMockSupport {
     return new DocumentExporter(reader, documentDestination, writeBlockSize, 
jobContextRepository);
   }
 
-  private ChunkContext chunkContext(BatchStatus batchStatus) {
+  private ChunkContext chunkContext(boolean terminate) {
     StepExecution stepExecution = new StepExecution("exportDoc", new 
JobExecution(JOB_EXECUTION_ID));
     stepExecution.setId(STEP_EXECUTION_ID);
-    stepExecution.getJobExecution().setStatus(batchStatus);
+    if (terminate)
+      stepExecution.setTerminateOnly();
     return new ChunkContext(new StepContext(stepExecution));
   }
 
   @After
-  public void tearDown() throws Exception {
+  public void tearDown() {
     verifyAll();
   }
 
@@ -102,7 +105,7 @@ public class DocumentExporterTest extends EasyMockSupport {
     reader.close(); expectLastCall();
     replayAll();
 
-    documentExporter.execute(null, chunkContext);
+    documentExporter.execute(ANY_STEP_CONTRIBUTION, chunkContext);
   }
 
   private ExecutionContext executionContext(ChunkContext chunkContext) {
@@ -120,7 +123,7 @@ public class DocumentExporterTest extends EasyMockSupport {
     documentItemWriter.close(); expectLastCall();
     replayAll();
 
-    assertThat(documentExporter.execute(null, chunkContext), 
is(RepeatStatus.FINISHED));
+    assertThat(documentExporter.execute(ANY_STEP_CONTRIBUTION, chunkContext), 
is(RepeatStatus.FINISHED));
   }
 
   @Test
@@ -143,7 +146,7 @@ public class DocumentExporterTest extends EasyMockSupport {
     documentItemWriter2.close(); expectLastCall();
     replayAll();
 
-    assertThat(documentExporter.execute(null, chunkContext), 
is(RepeatStatus.FINISHED));
+    assertThat(documentExporter.execute(ANY_STEP_CONTRIBUTION, chunkContext), 
is(RepeatStatus.FINISHED));
   }
 
   @Test(expected = IOException.class)
@@ -157,7 +160,7 @@ public class DocumentExporterTest extends EasyMockSupport {
     reader.close(); expectLastCall();
     replayAll();
 
-    documentExporter.execute(null, chunkContext);
+    documentExporter.execute(ANY_STEP_CONTRIBUTION, chunkContext);
   }
 
   @Test(expected = UncheckedIOException.class)
@@ -170,12 +173,12 @@ public class DocumentExporterTest extends EasyMockSupport 
{
     reader.close(); expectLastCall();
     replayAll();
 
-    documentExporter.execute(null, chunkContext);
+    documentExporter.execute(ANY_STEP_CONTRIBUTION, chunkContext);
   }
 
   @Test
   public void testStopAndRestartExportsAllDocuments() throws Exception {
-    ChunkContext stoppingChunkContext = chunkContext(BatchStatus.STOPPING);
+    ChunkContext stoppingChunkContext = chunkContext(true);
     DocumentExporter documentExporter = documentExporter(1);
 
     reader.open(executionContext(chunkContext)); expectLastCall();
@@ -206,9 +209,9 @@ public class DocumentExporterTest extends EasyMockSupport {
     reader.close(); expectLastCall();
     replayAll();
 
-    RepeatStatus repeatStatus = documentExporter.execute(null, 
this.chunkContext);
+    RepeatStatus repeatStatus = 
documentExporter.execute(ANY_STEP_CONTRIBUTION, this.chunkContext);
     assertThat(repeatStatus, is(RepeatStatus.CONTINUABLE));
-    repeatStatus = documentExporter.execute(null, this.chunkContext);
+    repeatStatus = documentExporter.execute(ANY_STEP_CONTRIBUTION, 
this.chunkContext);
     assertThat(repeatStatus, is(RepeatStatus.FINISHED));
   }
 }
\ No newline at end of file
diff --git 
a/ambari-infra-manager/src/test/java/org/apache/ambari/infra/model/ISO8601DateFormatterTest.java
 
b/ambari-infra-manager/src/test/java/org/apache/ambari/infra/model/ISO8601DateFormatterTest.java
new file mode 100644
index 0000000..b2bb0e8
--- /dev/null
+++ 
b/ambari-infra-manager/src/test/java/org/apache/ambari/infra/model/ISO8601DateFormatterTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ambari.infra.model;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+import java.text.ParseException;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.util.Date;
+
+import org.junit.Test;
+
+public class ISO8601DateFormatterTest {
+
+  @Test
+  public void testFormat() {
+    OffsetDateTime offsetDateTime = OffsetDateTime.of(
+            2018, 11, 30,
+            2, 30, 11, 0,
+            ZoneOffset.ofHoursMinutes(1, 30));
+    String text = new 
ISO8601DateFormatter().format(Date.from(offsetDateTime.toInstant()));
+    assertThat(text, is("2018-11-30T01:00:11Z"));
+  }
+
+  @Test
+  public void testParse() throws ParseException {
+    Date now = new Date();
+    ISO8601DateFormatter iso8601DateFormatter = new ISO8601DateFormatter();
+    Date parsed = iso8601DateFormatter.parse(iso8601DateFormatter.format(now));
+    assertThat(parsed, is(now));
+  }
+}
\ No newline at end of file

Reply via email to