JCLOUDS-457: Added initiateJob

Now the Glacier client supports the initiateJob operation.
diff --git a/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java b/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
index 7517f56..72520aa 100644
--- a/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
+++ b/glacier/src/main/java/org/jclouds/glacier/GlacierAsyncClient.java
@@ -36,8 +36,10 @@
 import org.jclouds.glacier.binders.BindContentRangeToHeaders;
 import org.jclouds.glacier.binders.BindDescriptionToHeaders;
 import org.jclouds.glacier.binders.BindHashesToHeaders;
+import org.jclouds.glacier.binders.BindJobRequestToJsonPayload;
 import org.jclouds.glacier.binders.BindMultipartTreeHashToHeaders;
 import org.jclouds.glacier.binders.BindPartSizeToHeaders;
+import org.jclouds.glacier.domain.JobRequest;
 import org.jclouds.glacier.domain.MultipartUploadMetadata;
 import org.jclouds.glacier.domain.PaginatedMultipartUploadCollection;
 import org.jclouds.glacier.domain.PaginatedVaultCollection;
@@ -45,6 +47,7 @@
 import org.jclouds.glacier.fallbacks.FalseOnIllegalArgumentException;
 import org.jclouds.glacier.filters.RequestAuthorizeSignature;
 import org.jclouds.glacier.functions.ParseArchiveIdHeader;
+import org.jclouds.glacier.functions.ParseJobIdHeader;
 import org.jclouds.glacier.functions.ParseMultipartUploadIdHeader;
 import org.jclouds.glacier.functions.ParseMultipartUploadListFromHttpContent;
 import org.jclouds.glacier.functions.ParseMultipartUploadPartListFromHttpContent;
@@ -262,4 +265,15 @@
    @ResponseParser(ParseMultipartUploadListFromHttpContent.class)
    ListenableFuture<PaginatedMultipartUploadCollection> listMultipartUploads(
          @ParamValidators(VaultNameValidator.class) @PathParam("vault") String vaultName);
+
+   /**
+    * @see GlacierClient#initiateJob
+    */
+   @Named("InitiateJob")
+   @POST
+   @Path("/-/vaults/{vault}/jobs")
+   @ResponseParser(ParseJobIdHeader.class)
+   ListenableFuture<String> initiateJob(
+         @ParamValidators(VaultNameValidator.class) @PathParam("vault") String vaultName,
+         @BinderParam(BindJobRequestToJsonPayload.class) JobRequest job);
 }
diff --git a/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java b/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
index 162ec91..a392ca2 100644
--- a/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
+++ b/glacier/src/main/java/org/jclouds/glacier/GlacierClient.java
@@ -20,6 +20,7 @@
 import java.net.URI;
 import java.util.Map;
 
+import org.jclouds.glacier.domain.JobRequest;
 import org.jclouds.glacier.domain.MultipartUploadMetadata;
 import org.jclouds.glacier.domain.PaginatedMultipartUploadCollection;
 import org.jclouds.glacier.domain.PaginatedVaultCollection;
@@ -218,4 +219,16 @@
     * Lists the multipart uploads in a vault.
     */
    PaginatedMultipartUploadCollection listMultipartUploads(String vaultName);
+
+   /**
+    * Initiates a job.
+    *
+    * @param vaultName
+    *           Name of the target Vault for the job.
+    * @param job
+    *          JobRequest instance with the concrete request.
+    * @return The job identifier.
+    * @see <a href="http://docs.aws.amazon.com/amazonglacier/latest/dev/api-initiate-job-post.html" />
+    */
+   String initiateJob(String vaultName, JobRequest job);
 }
diff --git a/glacier/src/main/java/org/jclouds/glacier/binders/BindJobRequestToJsonPayload.java b/glacier/src/main/java/org/jclouds/glacier/binders/BindJobRequestToJsonPayload.java
new file mode 100644
index 0000000..0526244
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/binders/BindJobRequestToJsonPayload.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     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.jclouds.glacier.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.glacier.domain.JobRequest;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import org.jclouds.rest.Binder;
+
+import com.google.inject.Inject;
+
+public class BindJobRequestToJsonPayload implements Binder {
+   @Inject
+   private Json json;
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      checkArgument(checkNotNull(input, "input") instanceof JobRequest,
+            "This binder is only valid for JobRequest");
+      checkNotNull(request, "request");
+      request.setPayload(json.toJson(input));
+      return request;
+   }
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/domain/ArchiveRetrievalJobRequest.java b/glacier/src/main/java/org/jclouds/glacier/domain/ArchiveRetrievalJobRequest.java
new file mode 100644
index 0000000..fec774e
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/domain/ArchiveRetrievalJobRequest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.jclouds.glacier.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+
+import org.jclouds.glacier.util.ContentRange;
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.base.Objects;
+import com.google.gson.annotations.SerializedName;
+
+public class ArchiveRetrievalJobRequest extends JobRequest {
+   private static final String TYPE = "archive-retrieval";
+
+   @SerializedName("ArchiveId")
+   private final String archiveId;
+   @SerializedName("Description")
+   private final String description;
+   @SerializedName("RetrievalByteRange")
+   private final ContentRange range;
+
+   private ArchiveRetrievalJobRequest(String archiveId, @Nullable String description, @Nullable ContentRange range) {
+      super(TYPE);
+      this.archiveId = checkNotNull(archiveId, "archiveId");
+      this.description = description;
+      this.range = range;
+   }
+
+   @ConstructorProperties({ "ArchiveId", "Description", "RetrievalByteRange" })
+   private ArchiveRetrievalJobRequest(String archiveId, @Nullable String description, @Nullable String range) {
+      this(archiveId, description, range == null ? null : ContentRange.fromString(range));
+   }
+
+   public String getDescription() {
+      return description;
+   }
+
+   public ContentRange getRange() {
+      return range;
+   }
+
+   public String getArchiveId() {
+      return archiveId;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(this.archiveId, this.description, this.range);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      ArchiveRetrievalJobRequest other = (ArchiveRetrievalJobRequest) obj;
+
+      return Objects.equal(this.archiveId, other.archiveId) && Objects.equal(this.description, other.description)
+            && Objects.equal(this.range, other.range);
+   }
+
+   @Override
+   public String toString() {
+      return "InventoryRetrievalParameters [archiveId=" + archiveId + ", description=" + description + ", range="
+            + range + "]";
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static class Builder {
+      private String archiveId;
+      private String description;
+      private ContentRange range;
+
+      Builder() {
+      }
+
+      public Builder archiveId(String archiveId) {
+         this.archiveId = archiveId;
+         return this;
+      }
+
+      public Builder description(String description) {
+         this.description = description;
+         return this;
+      }
+
+      public Builder range(ContentRange range) {
+         this.range = range;
+         return this;
+      }
+
+      public ArchiveRetrievalJobRequest build() {
+         return new ArchiveRetrievalJobRequest(archiveId, description, range);
+      }
+   }
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/domain/InventoryRetrievalJobRequest.java b/glacier/src/main/java/org/jclouds/glacier/domain/InventoryRetrievalJobRequest.java
new file mode 100644
index 0000000..fb4bb28
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/domain/InventoryRetrievalJobRequest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.jclouds.glacier.domain;
+
+import java.beans.ConstructorProperties;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.base.Objects;
+import com.google.gson.annotations.SerializedName;
+
+public class InventoryRetrievalJobRequest extends JobRequest {
+   private static final String TYPE = "inventory-retrieval";
+
+   @SerializedName("Description")
+   private final String description;
+   @SerializedName("Format")
+   private final String format;
+   @SerializedName("InventoryRetrievalParameters")
+   private final InventoryRetrievalParameters parameters;
+
+   @ConstructorProperties({ "Description", "Format" })
+   private InventoryRetrievalJobRequest(@Nullable String description, @Nullable String format) {
+      super(TYPE);
+      this.description = description;
+      this.format = format;
+      this.parameters = new InventoryRetrievalParameters();
+   }
+
+   public String getDescription() {
+      return description;
+   }
+
+   public String getFormat() {
+      return format;
+   }
+
+   public InventoryRetrievalParameters getParameters() {
+      return this.parameters;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(this.description, this.format, this.parameters);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      InventoryRetrievalJobRequest other = (InventoryRetrievalJobRequest) obj;
+
+      return Objects.equal(this.description, other.description) && Objects.equal(this.format, other.format)
+            && Objects.equal(this.parameters, other.parameters);
+   }
+
+   @Override
+   public String toString() {
+      return "InventoryRetrievalJobRequest [description=" + description + ", format=" + format + "," +
+            "parameters=" + parameters + "]";
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static class Builder {
+      private String description;
+      private String format;
+      private String startDate;
+      private String endDate;
+      private Integer limit;
+      private String marker;
+
+      Builder() {
+      }
+
+      public Builder description(String description) {
+         this.description = description;
+         return this;
+      }
+
+      public Builder format(String format) {
+         this.format = format;
+         return this;
+      }
+
+      public Builder startDate(String startDate) {
+         this.startDate = startDate;
+         return this;
+      }
+
+      public Builder endDate(String endDate) {
+         this.endDate = endDate;
+         return this;
+      }
+
+      public Builder limit(Integer limit) {
+         this.limit = limit;
+         return this;
+      }
+
+      public Builder marker(String marker) {
+         this.marker = marker;
+         return this;
+      }
+
+      public InventoryRetrievalJobRequest build() {
+         InventoryRetrievalJobRequest request = new InventoryRetrievalJobRequest(description, format);
+         request.getParameters().setEndDate(endDate);
+         request.getParameters().setStartDate(startDate);
+         request.getParameters().setLimit(limit);
+         request.getParameters().setMarker(marker);
+         return request;
+      }
+   }
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/domain/InventoryRetrievalParameters.java b/glacier/src/main/java/org/jclouds/glacier/domain/InventoryRetrievalParameters.java
new file mode 100644
index 0000000..c6d7376
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/domain/InventoryRetrievalParameters.java
@@ -0,0 +1,90 @@
+/*
+ * 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.jclouds.glacier.domain;
+
+import com.google.common.base.Objects;
+import com.google.gson.annotations.SerializedName;
+
+public class InventoryRetrievalParameters {
+      @SerializedName("StartDate")
+      private String startDate;
+      @SerializedName("EndDate")
+      private String endDate;
+      @SerializedName("Limit")
+      private Integer limit;
+      @SerializedName("Marker")
+      private String marker;
+
+      public InventoryRetrievalParameters() {
+      }
+
+      public String getStartDate() {
+         return startDate;
+      }
+
+      public void setStartDate(String startDate) {
+         this.startDate = startDate;
+      }
+
+      public String getEndDate() {
+         return endDate;
+      }
+
+      public void setEndDate(String endDate) {
+         this.endDate = endDate;
+      }
+
+      public Integer getLimit() {
+         return limit;
+      }
+
+      public void setLimit(Integer limit) {
+         this.limit = limit;
+      }
+
+      public String getMarker() {
+         return marker;
+      }
+
+      public void setMarker(String marker) {
+         this.marker = marker;
+      }
+
+      @Override
+      public int hashCode() {
+         return Objects.hashCode(this.startDate, this.endDate, this.limit, this.marker);
+      }
+
+      @Override
+      public boolean equals(Object obj) {
+         if (obj == null)
+            return false;
+         if (getClass() != obj.getClass())
+            return false;
+         InventoryRetrievalParameters other = (InventoryRetrievalParameters) obj;
+
+         return Objects.equal(this.startDate, other.startDate) && Objects.equal(this.endDate, other.endDate)
+               && Objects.equal(this.limit, other.limit)
+               && Objects.equal(this.marker, other.marker);
+      }
+
+      @Override
+      public String toString() {
+         return "InventoryRetrievalParameters [startDate=" + startDate + ", endDate=" + endDate + ", limit=" + limit
+               + ", marker=" + marker + "]";
+      }
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/domain/JobRequest.java b/glacier/src/main/java/org/jclouds/glacier/domain/JobRequest.java
new file mode 100644
index 0000000..c2342eb
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/domain/JobRequest.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.glacier.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.gson.annotations.SerializedName;
+
+
+public abstract class JobRequest {
+   @SerializedName("Type")
+   protected final String type;
+
+   public JobRequest(String type) {
+      this.type = checkNotNull(type, "type");
+   }
+
+   public String getType() {
+      return type;
+   }
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/functions/ParseJobIdHeader.java b/glacier/src/main/java/org/jclouds/glacier/functions/ParseJobIdHeader.java
new file mode 100644
index 0000000..871f9ea
--- /dev/null
+++ b/glacier/src/main/java/org/jclouds/glacier/functions/ParseJobIdHeader.java
@@ -0,0 +1,38 @@
+/*
+ * 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.jclouds.glacier.functions;
+
+import org.jclouds.glacier.reference.GlacierHeaders;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpResponse;
+
+import com.google.common.base.Function;
+
+/**
+ * Parses the jobId from the HttpResponse.
+ */
+public class ParseJobIdHeader implements Function<HttpResponse, String> {
+
+   @Override
+   public String apply(HttpResponse from) {
+      String id = from.getFirstHeaderOrNull(GlacierHeaders.JOB_ID);
+      if (id == null) {
+         throw new HttpException("Did not receive JobId");
+      }
+      return id;
+   }
+}
diff --git a/glacier/src/main/java/org/jclouds/glacier/reference/GlacierHeaders.java b/glacier/src/main/java/org/jclouds/glacier/reference/GlacierHeaders.java
index 4162580..9acdd65 100644
--- a/glacier/src/main/java/org/jclouds/glacier/reference/GlacierHeaders.java
+++ b/glacier/src/main/java/org/jclouds/glacier/reference/GlacierHeaders.java
@@ -33,6 +33,7 @@
    public static final String MULTIPART_UPLOAD_ID = HEADER_PREFIX + "multipart-upload-id";
    public static final String PART_SIZE = HEADER_PREFIX + "part-size";
    public static final String ARCHIVE_SIZE = HEADER_PREFIX + "archive-size";
+   public static final String JOB_ID = HEADER_PREFIX + "job-id";
 
    private GlacierHeaders() {
    }
diff --git a/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java b/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
index 1876320..acc6a39 100644
--- a/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
+++ b/glacier/src/test/java/org/jclouds/glacier/GlacierClientMockTest.java
@@ -37,6 +37,8 @@
 
 import org.jclouds.ContextBuilder;
 import org.jclouds.concurrent.config.ExecutorServiceModule;
+import org.jclouds.glacier.domain.ArchiveRetrievalJobRequest;
+import org.jclouds.glacier.domain.InventoryRetrievalJobRequest;
 import org.jclouds.glacier.domain.MultipartUploadMetadata;
 import org.jclouds.glacier.domain.PaginatedMultipartUploadCollection;
 import org.jclouds.glacier.domain.PaginatedVaultCollection;
@@ -47,6 +49,8 @@
 import org.jclouds.glacier.util.ContentRange;
 import org.jclouds.http.HttpResponseException;
 import org.jclouds.io.Payload;
+import org.jclouds.json.Json;
+import org.jclouds.json.internal.GsonWrapper;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
@@ -58,6 +62,7 @@
 import com.google.common.io.Resources;
 import com.google.common.net.HttpHeaders;
 import com.google.common.net.MediaType;
+import com.google.gson.Gson;
 import com.google.inject.Module;
 import com.squareup.okhttp.mockwebserver.MockResponse;
 import com.squareup.okhttp.mockwebserver.MockWebServer;
@@ -89,6 +94,7 @@
    private static final String MULTIPART_UPLOAD_LOCATION = VAULT_LOCATION + "/multipart-uploads/" + ARCHIVE_ID;
    private static final String MULTIPART_UPLOAD_ID = "OW2fM5iVylEpFEMM9_HpKowRapC3vn5sSL39_396UW9zLFUWVrnRHaPjUJddQ5OxSHVXjYtrN47NBZ-khxOjyEXAMPLE";
    private static final String MARKER = "xsQdFIRsfJr20CW2AbZBKpRZAFTZSJIMtL2hYf8mvp8dM0m4RUzlaqoEye6g3h3ecqB_zqwB7zLDMeSWhwo65re4C4Ev";
+   private static final String JOB_ID = "HkF9p6o7yjhFx-K3CGl6fuSm6VzW9T7esGQfco8nUXVYwS0jlb5gq1JZ55yHgt5vP54ZShjoQzQVVh7vEXAMPLEjobID";
    private static final Set<Module> modules = ImmutableSet.<Module> of(new ExecutorServiceModule(sameThreadExecutor(),
          sameThreadExecutor()));
 
@@ -364,4 +370,60 @@
       assertEquals(server.takeRequest().getRequestLine(),
             "GET /-/vaults/examplevault/multipart-uploads?limit=1&marker=" + MARKER + " " + HTTP);
    }
+
+   @Test
+   public void testInitiateArchiveRetrievalJob() throws IOException, InterruptedException {
+      MockResponse mr = buildBaseResponse(202);
+      mr.addHeader(HttpHeaders.LOCATION, VAULT_LOCATION + "/jobs/" + JOB_ID);
+      mr.addHeader(GlacierHeaders.JOB_ID, JOB_ID);
+      server.enqueue(mr);
+
+      ContentRange range = ContentRange.fromString("2097152-4194303");
+      ArchiveRetrievalJobRequest retrieval = ArchiveRetrievalJobRequest.builder()
+            .archiveId(ARCHIVE_ID)
+            .description(DESCRIPTION)
+            .range(range)
+            .build();
+      assertEquals(client.initiateJob(VAULT_NAME, retrieval), JOB_ID);
+      RecordedRequest request = server.takeRequest();
+      Json json = new GsonWrapper(new Gson());
+      ArchiveRetrievalJobRequest job = json.fromJson(new String(request.getBody()), ArchiveRetrievalJobRequest.class);
+      assertEquals(request.getRequestLine(), "POST /-/vaults/" + VAULT_NAME + "/jobs " + HTTP);
+      assertEquals(job.getDescription(), DESCRIPTION);
+      assertEquals(job.getRange(), range);
+      assertEquals(job.getArchiveId(), ARCHIVE_ID);
+      assertEquals(job.getType(), "archive-retrieval");
+   }
+
+   @Test
+   public void testInitiateInventoryRetrievalJob() throws IOException, InterruptedException {
+      MockResponse mr = buildBaseResponse(202);
+      mr.addHeader(HttpHeaders.LOCATION, VAULT_LOCATION + "/jobs/" + JOB_ID);
+      mr.addHeader(GlacierHeaders.JOB_ID, JOB_ID);
+      server.enqueue(mr);
+
+      String marker = "vyS0t2jHQe5qbcDggIeD50chS1SXwYMrkVKo0KHiTUjEYxBGCqRLKaiySzdN7QXGVVV5XZpNVG67pCZ_uykQXFMLaxOSu2hO_-5C0AtWMDrfo7LgVOyfnveDRuOSecUo3Ueq7K0";
+      int limit = 10000;
+      String startDate = "2013-12-04T21:25:42Z";
+      String endDate = "2013-12-05T21:25:42Z";
+      String format = "CSV";
+      InventoryRetrievalJobRequest job = InventoryRetrievalJobRequest.builder()
+            .format(format)
+            .endDate(endDate)
+            .startDate(startDate)
+            .limit(limit)
+            .marker(marker)
+            .build();
+      assertEquals(client.initiateJob(VAULT_NAME, job), JOB_ID);
+      RecordedRequest request = server.takeRequest();
+      assertEquals(request.getRequestLine(), "POST /-/vaults/examplevault/jobs HTTP/1.1");
+      Json json = new GsonWrapper(new Gson());
+      job = json.fromJson(new String(request.getBody()), InventoryRetrievalJobRequest.class);
+      assertEquals(job.getFormat(), format);
+      assertEquals(job.getParameters().getMarker(), marker);
+      assertEquals(job.getParameters().getLimit(), new Integer(limit));
+      assertEquals(job.getParameters().getStartDate(), startDate);
+      assertEquals(job.getParameters().getEndDate(), endDate);
+      assertEquals(job.getType(), "inventory-retrieval");
+   }
 }