Merge tag 'v0.6.1'

[maven-release-plugin]  copy for tag v0.6.1
diff --git a/README.md b/README.md
index 4d5a46c..a915768 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
             <dependency>
                 <groupId>io.prediction</groupId>
                 <artifactId>client</artifactId>
-                <version>0.6.0</version>
+                <version>0.6.1</version>
             </dependency>
         </dependencies>
         ...
@@ -26,7 +26,7 @@
     <ivy-module ...>
         ...
         <dependencies>
-            <dependency org="io.prediction" name="client" rev="0.6.0" />
+            <dependency org="io.prediction" name="client" rev="0.6.1" />
             ...
         </dependencies>
         ...
@@ -35,7 +35,7 @@
 
 If you have an sbt project, add the library dependency to your build definition.
 
-    libraryDependencies += "io.prediction" % "client" % "0.6.0"
+    libraryDependencies += "io.prediction" % "client" % "0.6.1"
 
 ### Building from Source
 
@@ -66,7 +66,7 @@
 
 ### Running the Sample Android Client
 
-Detailed instructions can be found at our [main documentation site](http://docs.prediction.io/tutorials/android-client.html).
+Detailed instructions can be found at our [main documentation site](http://docs.prediction.io/current/tutorials/android-client.html).
 
 ### Running CLI Examples
 
diff --git a/client/pom.xml b/client/pom.xml
index 3210304..99673ce 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -5,7 +5,7 @@
         <groupId>io.prediction</groupId>
         <artifactId>sdk</artifactId>
         <relativePath>../pom.xml</relativePath>
-        <version>0.6.0</version>
+        <version>0.6.1</version>
     </parent>
 
     <artifactId>client</artifactId>
@@ -21,17 +21,35 @@
         <dependency>
             <groupId>com.ning</groupId>
             <artifactId>async-http-client</artifactId>
-            <version>1.7.12</version>
+            <version>1.7.21</version>
         </dependency>
         <dependency>
             <groupId>com.google.code.gson</groupId>
             <artifactId>gson</artifactId>
-            <version>2.2.2</version>
+            <version>2.2.4</version>
         </dependency>
         <dependency>
             <groupId>joda-time</groupId>
             <artifactId>joda-time</artifactId>
-            <version>2.2</version>
+            <version>2.3</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.11</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.tomakehurst</groupId>
+            <artifactId>wiremock</artifactId>
+            <version>1.33</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-all</artifactId>
+            <version>1.3</version>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 
@@ -71,6 +89,11 @@
                     </execution>
                 </executions>
             </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>emma-maven-plugin</artifactId>
+                <version>1.0-alpha-3</version>
+            </plugin>
         </plugins>
     </build>
 </project>
diff --git a/client/src/main/java/io/prediction/Client.java b/client/src/main/java/io/prediction/Client.java
index 06a5abc..52e3d79 100644
--- a/client/src/main/java/io/prediction/Client.java
+++ b/client/src/main/java/io/prediction/Client.java
@@ -26,7 +26,7 @@
  * Multiple simultaneous asynchronous requests is made possible by the high performance backend provided by the <a href="https://github.com/AsyncHttpClient/async-http-client">Async Http Client</a>.
  *
  * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.6.0
+ * @version 0.6.1
  * @since 0.1
  */
 public class Client {
@@ -539,13 +539,13 @@
 
     /**
      * Get a get top-n recommendations request builder that can be used to add additional request parameters.
-     * @deprecated Use {@link Client#getItemRecGetTopNRequestBuilder(String engine, int n)} instead.
+     *
+     * Using this method overrides the user ID set by {@link Client#identify}.
      *
      * @param engine engine name
      * @param uid ID of the User whose recommendations will be gotten
-     * @param n number of top recommendations to get 
+     * @param n number of top recommendations to get
      */
-    @Deprecated
     public ItemRecGetTopNRequestBuilder getItemRecGetTopNRequestBuilder(String engine, String uid, int n) {
         return new ItemRecGetTopNRequestBuilder(this.apiUrl, this.apiFormat, this.appkey, engine, uid, n);
     }
@@ -568,14 +568,14 @@
 
     /**
      * Get a get top-n recommendations request builder that can be used to add additional request parameters.
-     * @deprecated Use {@link Client#getItemRecGetTopNRequestBuilder(String engine, int n, String[] attributes)} instead.
+     *
+     * Using this method overrides the user ID set by {@link Client#identify}.
      *
      * @param engine engine name
      * @param uid ID of the User whose recommendations will be gotten
      * @param n number of top recommendations to get
      * @param attributes array of item attribute names to be returned with the result
      */
-    @Deprecated
     public ItemRecGetTopNRequestBuilder getItemRecGetTopNRequestBuilder(String engine, String uid, int n, String[] attributes) {
         return (new ItemRecGetTopNRequestBuilder(this.apiUrl, this.apiFormat, this.appkey, engine, uid, n)).attributes(attributes);
     }
@@ -608,7 +608,8 @@
 
     /**
      * Sends a synchronous get recommendations request to the API.
-     * @deprecated Use {@link Client#getItemRecTopN(String engine, int n)} instead.
+     *
+     * Using this method overrides the user ID set by {@link Client#identify}.
      *
      * @param engine engine name
      * @param uid ID of the User whose recommendations will be gotten
@@ -618,7 +619,6 @@
      * @throws InterruptedException indicates an interruption during the HTTP operation
      * @throws IOException indicates an error from the API response
      */
-    @Deprecated
     public String[] getItemRecTopN(String engine, String uid, int n) throws ExecutionException, InterruptedException, IOException {
         return this.getItemRecTopN(this.getItemRecTopNAsFuture(this.getItemRecGetTopNRequestBuilder(engine, uid, n)));
     }
@@ -677,7 +677,8 @@
 
     /**
      * Sends a synchronous get recommendations request to the API.
-     * @deprecated Use {@link Client#getItemRecTopNWithAttributes(String engine, int n, String[] attributes)} instead.
+     *
+     * Using this method overrides the user ID set by {@link Client#identify}.
      *
      * @param engine engine name
      * @param uid ID of the User whose recommendations will be gotten
@@ -686,9 +687,8 @@
      *
      * @throws ExecutionException indicates an error in the HTTP backend
      * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response 
+     * @throws IOException indicates an error from the API response
      */
-    @Deprecated
     public Map<String, String[]> getItemRecTopNWithAttributes(String engine, String uid, int n, String[] attributes) throws ExecutionException, InterruptedException, IOException {
         return this.getItemRecTopNWithAttributes(this.getItemRecTopNAsFuture(this.getItemRecGetTopNRequestBuilder(engine, uid, n, attributes)));
     }
@@ -754,7 +754,7 @@
      *
      * @param engine engine name
      * @param iid ID of the Item
-     * @param n number of top similar items to get 
+     * @param n number of top similar items to get
      */
     public ItemSimGetTopNRequestBuilder getItemSimGetTopNRequestBuilder(String engine, String iid, int n) {
         return new ItemSimGetTopNRequestBuilder(this.apiUrl, this.apiFormat, this.appkey, engine, iid, n);
@@ -834,7 +834,7 @@
 
     /**
      * Sends a synchronous get similar items request to the API.
-     * 
+     *
      * @param engine engine name
      * @param iid ID of the Item
      * @param n number of top recommendations to get
@@ -842,7 +842,7 @@
      *
      * @throws ExecutionException indicates an error in the HTTP backend
      * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response 
+     * @throws IOException indicates an error from the API response
      */
     public Map<String, String[]> getItemSimTopNWithAttributes(String engine, String iid, int n, String[] attributes) throws ExecutionException, InterruptedException, IOException {
         return this.getItemSimTopNWithAttributes(this.getItemSimTopNAsFuture(this.getItemSimGetTopNRequestBuilder(engine, iid, n, attributes)));
@@ -889,6 +889,20 @@
 
     /**
      * Get a user-action-on-item request builder that can be used to add additional request parameters.
+     *
+     * Using this method overrides the user ID set by {@link Client#identify}.
+     *
+     * @param uid ID of the User of this action
+     * @param action action name
+     * @param iid ID of the Item of this action
+     */
+    public UserActionItemRequestBuilder getUserActionItemRequestBuilder(String uid, String action, String iid) {
+        UserActionItemRequestBuilder builder = new UserActionItemRequestBuilder(this.apiUrl, this.apiFormat, this.appkey, action, uid, iid);
+        return builder;
+    }
+
+    /**
+     * Get a user-action-on-item request builder that can be used to add additional request parameters.
      * Identified user ID will be used. See {@link Client#identify}.
      *
      * @param action action name
@@ -906,6 +920,19 @@
 
     /**
      * Sends an asynchronous user-action-on-item request to the API.
+     *
+     * Using this method overrides the user ID set by {@link Client#identify}.
+     *
+     * @param uid ID of the User of this action
+     * @param action action name
+     * @param iid ID of the Item of this action
+     */
+    public FutureAPIResponse userActionItemAsFuture(String uid, String action, String iid) throws IOException {
+        return this.userActionItemAsFuture(this.getUserActionItemRequestBuilder(uid, action, iid));
+    }
+
+    /**
+     * Sends an asynchronous user-action-on-item request to the API.
      * Identified user ID will be used. See {@link Client#identify}.
      *
      * @param action action name
@@ -928,6 +955,23 @@
 
     /**
      * Sends a synchronous user-action-on-item request to the API.
+     *
+     * Using this method overrides the user ID set by {@link Client#identify}.
+     *
+     * @param uid ID of the User of this action
+     * @param action action name
+     * @param iid ID of the Item of this action
+     *
+     * @throws ExecutionException indicates an error in the HTTP backend
+     * @throws InterruptedException indicates an interruption during the HTTP operation
+     * @throws IOException indicates an error from the API response
+     */
+    public void userActionItem(String uid, String action, String iid) throws ExecutionException, InterruptedException, IOException {
+        this.userActionItem(this.userActionItemAsFuture(this.getUserActionItemRequestBuilder(uid, action, iid)));
+    }
+
+    /**
+     * Sends a synchronous user-action-on-item request to the API.
      * Identified user ID will be used. See {@link Client#identify}.
      *
      * @param action action name
@@ -972,354 +1016,4 @@
             throw new IOException(message);
         }
     }
-
-    /**
-     * Get a user-rate-item action request builder that can be used to add additional request parameters.
-     * @deprecated Use {@link Client#getUserActionItemRequestBuilder(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     * @param rate the rating of this action
-     */
-    @Deprecated
-    public UserActionItemRequestBuilder getUserRateItemRequestBuilder(String uid, String iid, int rate) {
-        UserActionItemRequestBuilder builder = new UserActionItemRequestBuilder(this.apiUrl, this.apiFormat, this.appkey, UserActionItemRequestBuilder.RATE, uid, iid);
-        builder.rate(rate);
-        return builder;
-    }
-
-    /**
-     * Sends an asynchronous user-rate-item action request to the API.
-     * @deprecated Use {@link Client#userActionItemAsFuture(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     */
-    @Deprecated
-    public FutureAPIResponse userRateItemAsFuture(UserActionItemRequestBuilder builder) throws IOException {
-        return new FutureAPIResponse(this.client.executeRequest(builder.build(), this.getHandler()));
-    }
-
-    /**
-     * Sends a synchronous user-rate-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     * @param rate the rating of this action
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userRateItem(String uid, String iid, int rate) throws ExecutionException, InterruptedException, IOException {
-        this.userRateItem(this.userRateItemAsFuture(this.getUserRateItemRequestBuilder(uid, iid, rate)));
-    }
-
-    /**
-     * Sends a synchronous user-rate-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userRateItem(UserActionItemRequestBuilder builder) throws ExecutionException, InterruptedException, IOException {
-        this.userRateItem(this.userRateItemAsFuture(builder));
-    }
-
-    /**
-     * Synchronize a previously sent asynchronous user-rate-item action request.
-     * @deprecated Use {@link Client#userActionItem(FutureAPIResponse response)} instead.
-     *
-     * @param response an instance of {@link FutureAPIResponse} returned from {@link Client#userRateItemAsFuture}
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userRateItem(FutureAPIResponse response) throws ExecutionException, InterruptedException, IOException {
-        this.userActionItem(response);
-    }
-
-    /**
-     * Get a user-like-item action request builder that can be used to add additional request parameters.
-     * @deprecated Use {@link Client#getUserActionItemRequestBuilder(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     */
-    @Deprecated
-    public UserActionItemRequestBuilder getUserLikeItemRequestBuilder(String uid, String iid) {
-        return new UserActionItemRequestBuilder(this.apiUrl, this.apiFormat, this.appkey, UserActionItemRequestBuilder.LIKE, uid, iid);
-    }
-
-    /**
-     * Sends an asynchronous user-like-item action request to the API.
-     * @deprecated Use {@link Client#userActionItemAsFuture(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     */
-    @Deprecated
-    public FutureAPIResponse userLikeItemAsFuture(UserActionItemRequestBuilder builder) throws IOException {
-        return new FutureAPIResponse(this.client.executeRequest(builder.build(), this.getHandler()));
-    }
-
-    /**
-     * Sends a synchronous user-like-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userLikeItem(String uid, String iid) throws ExecutionException, InterruptedException, IOException {
-        this.userLikeItem(this.userLikeItemAsFuture(this.getUserLikeItemRequestBuilder(uid, iid)));
-    }
-
-    /**
-     * Sends a synchronous user-like-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userLikeItem(UserActionItemRequestBuilder builder) throws ExecutionException, InterruptedException, IOException {
-        this.userLikeItem(this.userLikeItemAsFuture(builder));
-    }
-
-    /**
-     * Synchronize a previously sent asynchronous user-like-item action request.
-     * @deprecated Use {@link Client#userActionItem(FutureAPIResponse response)} instead.
-     *
-     * @param response an instance of {@link FutureAPIResponse} returned from {@link Client#userLikeItemAsFuture}
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userLikeItem(FutureAPIResponse response) throws ExecutionException, InterruptedException, IOException {
-        this.userActionItem(response);
-    }
-
-    /**
-     * Get a user-dislike-item action request builder that can be used to add additional request parameters.
-     * @deprecated Use {@link Client#getUserActionItemRequestBuilder(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     * 
-     */
-    @Deprecated
-    public UserActionItemRequestBuilder getUserDislikeItemRequestBuilder(String uid, String iid) {
-        return new UserActionItemRequestBuilder(this.apiUrl, this.apiFormat, this.appkey, UserActionItemRequestBuilder.DISLIKE, uid, iid);
-    }
-
-    /**
-     * Sends an asynchronous user-dislike-item action request to the API.
-     * @deprecated Use {@link Client#userActionItemAsFuture(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     */
-    @Deprecated
-    public FutureAPIResponse userDislikeItemAsFuture(UserActionItemRequestBuilder builder) throws IOException {
-        return new FutureAPIResponse(this.client.executeRequest(builder.build(), this.getHandler()));
-    }
-
-    /**
-     * Sends a synchronous user-dislike-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userDislikeItem(String uid, String iid) throws ExecutionException, InterruptedException, IOException {
-        this.userDislikeItem(this.userDislikeItemAsFuture(this.getUserDislikeItemRequestBuilder(uid, iid)));
-    }
-
-    /**
-     * Sends a synchronous user-dislike-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userDislikeItem(UserActionItemRequestBuilder builder) throws ExecutionException, InterruptedException, IOException {
-        this.userDislikeItem(this.userDislikeItemAsFuture(builder));
-    }
-
-    /**
-     * Synchronize a previously sent asynchronous user-dislike-item action request.
-     * @deprecated Use {@link Client#userActionItem(FutureAPIResponse response)} instead.
-     *
-     * @param response an instance of {@link FutureAPIResponse} returned from {@link Client#userDislikeItemAsFuture}
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userDislikeItem(FutureAPIResponse response) throws ExecutionException, InterruptedException, IOException {
-        this.userActionItem(response);
-    }
-
-    /**
-     * Get a user-view-item action request builder that can be used to add additional request parameters.
-     * @deprecated Use {@link Client#getUserActionItemRequestBuilder(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     */
-    @Deprecated
-    public UserActionItemRequestBuilder getUserViewItemRequestBuilder(String uid, String iid) {
-        return new UserActionItemRequestBuilder(this.apiUrl, this.apiFormat, this.appkey, UserActionItemRequestBuilder.VIEW, uid, iid);
-    }
-
-    /**
-     * Sends an asynchronous user-view-item action request to the API.
-     * @deprecated Use {@link Client#userActionItemAsFuture(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     */
-    @Deprecated
-    public FutureAPIResponse userViewItemAsFuture(UserActionItemRequestBuilder builder) throws IOException {
-        return new FutureAPIResponse(this.client.executeRequest(builder.build(), this.getHandler()));
-    }
-
-    /**
-     * Sends a synchronous user-view-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userViewItem(String uid, String iid) throws ExecutionException, InterruptedException, IOException {
-        this.userViewItem(this.userViewItemAsFuture(this.getUserViewItemRequestBuilder(uid, iid)));
-    }
-
-    /**
-     * Sends a synchronous user-view-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userViewItem(UserActionItemRequestBuilder builder) throws ExecutionException, InterruptedException, IOException {
-        this.userViewItem(this.userViewItemAsFuture(builder));
-    }
-
-    /**
-     * Synchronize a previously sent asynchronous user-view-item action request.
-     * @deprecated Use {@link Client#userActionItem(FutureAPIResponse response)} instead.
-     *
-     * @param response an instance of {@link FutureAPIResponse} returned from {@link Client#userViewItemAsFuture}
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userViewItem(FutureAPIResponse response) throws ExecutionException, InterruptedException, IOException {
-        this.userActionItem(response);
-    }
-
-    /**
-     * Get a user-conversion-item action request builder that can be used to add additional request parameters.
-     * @deprecated Use {@link Client#getUserActionItemRequestBuilder(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     */
-    @Deprecated
-    public UserActionItemRequestBuilder getUserConversionItemRequestBuilder(String uid, String iid) {
-        return new UserActionItemRequestBuilder(this.apiUrl, this.apiFormat, this.appkey, UserActionItemRequestBuilder.CONVERSION, uid, iid);
-    }
-
-    /**
-     * Sends an asynchronous user-conversion-item action request to the API.
-     * @deprecated Use {@link Client#userActionItemAsFuture(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     */
-    @Deprecated
-    public FutureAPIResponse userConversionItemAsFuture(UserActionItemRequestBuilder builder) throws IOException {
-        return new FutureAPIResponse(this.client.executeRequest(builder.build(), this.getHandler()));
-    }
-
-    /**
-     * Sends a synchronous user-conversion-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(String action, String iid)} instead.
-     *
-     * @param uid ID of the User of this action
-     * @param iid ID of the Item of this action
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userConversionItem(String uid, String iid) throws ExecutionException, InterruptedException, IOException {
-        this.userConversionItem(this.userConversionItemAsFuture(this.getUserConversionItemRequestBuilder(uid, iid)));
-    }
-
-    /**
-     * Sends a synchronous user-conversion-item action request to the API.
-     * @deprecated Use {@link Client#userActionItem(UserActionItemRequestBuilder builder)} instead.
-     *
-     * @param builder an instance of {@link UserActionItemRequestBuilder} that will be turned into a request
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userConversionItem(UserActionItemRequestBuilder builder) throws ExecutionException, InterruptedException, IOException {
-        this.userConversionItem(this.userConversionItemAsFuture(builder));
-    }
-
-    /**
-     * Synchronize a previously sent asynchronous user-conversion-item action request.
-     * @deprecated Use {@link Client#userActionItem(FutureAPIResponse response)} instead.
-     *
-     * @param response an instance of {@link FutureAPIResponse} returned from {@link Client#userConversionItemAsFuture}
-     *
-     * @throws ExecutionException indicates an error in the HTTP backend
-     * @throws InterruptedException indicates an interruption during the HTTP operation
-     * @throws IOException indicates an error from the API response
-     */
-    @Deprecated
-    public void userConversionItem(FutureAPIResponse response) throws ExecutionException, InterruptedException, IOException {
-        this.userActionItem(response);
-    }
 }
diff --git a/client/src/main/java/io/prediction/CreateItemRequestBuilder.java b/client/src/main/java/io/prediction/CreateItemRequestBuilder.java
index aabb8e8..3671d92 100644
--- a/client/src/main/java/io/prediction/CreateItemRequestBuilder.java
+++ b/client/src/main/java/io/prediction/CreateItemRequestBuilder.java
@@ -1,8 +1,9 @@
 package io.prediction;
 
+import com.google.gson.JsonObject;
+import org.joda.time.DateTime;
 import com.ning.http.client.Request;
 import com.ning.http.client.RequestBuilder;
-import org.joda.time.DateTime;
 
 import java.util.Arrays;
 import java.util.HashMap;
@@ -15,7 +16,7 @@
  * Class to build Item requests
  *
  * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.4.2
+ * @version 0.6.1
  * @since 0.2
  */
 
@@ -133,23 +134,33 @@
     public Request build() {
         RequestBuilder builder = new RequestBuilder("POST");
         builder.setUrl(this.apiUrl + "/items." + this.apiFormat);
-        builder.addQueryParameter("pio_appkey", this.appkey);
-        builder.addQueryParameter("pio_iid", this.iid);
-        builder.addQueryParameter("pio_itypes", Utils.arrayToString(this.itypes));
+
+        JsonObject requestJson = new JsonObject();
+
+        requestJson.addProperty("pio_appkey", this.appkey);
+        requestJson.addProperty("pio_iid", this.iid);
+        requestJson.addProperty("pio_itypes", Utils.arrayToString(this.itypes));
         if (this.latitude != null && this.longitude != null) {
-            builder.addQueryParameter("pio_latlng", this.latitude.toString() + "," + this.longitude.toString());
+            requestJson.addProperty("pio_latlng", this.latitude.toString() + "," + this.longitude.toString());
         }
         if (this.startT != null) {
-            builder.addQueryParameter("pio_startT", startT.toString());
+            requestJson.addProperty("pio_startT", startT.toString());
         }
         if (this.endT != null) {
-            builder.addQueryParameter("pio_endT", endT.toString());
+            requestJson.addProperty("pio_endT", endT.toString());
         }
         for (Map.Entry<String, String> attribute : this.attributes.entrySet()) {
             if (attribute.getValue() != null) {
-                builder.addQueryParameter(attribute.getKey(), attribute.getValue());
+                requestJson.addProperty(attribute.getKey(), attribute.getValue());
             }
         }
+
+        String requestJsonString = requestJson.toString();
+
+        builder.setBody(requestJsonString);
+        builder.setHeader("Content-Type","application/json");
+        builder.setHeader("Content-Length", ""+requestJsonString.length());
+
         return builder.build();
     }
 }
diff --git a/client/src/main/java/io/prediction/CreateUserRequestBuilder.java b/client/src/main/java/io/prediction/CreateUserRequestBuilder.java
index a0928c0..570c69e 100644
--- a/client/src/main/java/io/prediction/CreateUserRequestBuilder.java
+++ b/client/src/main/java/io/prediction/CreateUserRequestBuilder.java
@@ -1,14 +1,14 @@
 package io.prediction;
 
+import com.google.gson.JsonObject;
 import com.ning.http.client.Request;
 import com.ning.http.client.RequestBuilder;
 
-
 /**
  * Class to build User requests
  *
  * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.3
+ * @version 0.6.1
  * @since 0.2
  */
 
@@ -76,11 +76,21 @@
     public Request build() {
         RequestBuilder builder = new RequestBuilder("POST");
         builder.setUrl(this.apiUrl + "/users." + this.apiFormat);
-        builder.addQueryParameter("pio_appkey", this.appkey);
-        builder.addQueryParameter("pio_uid", this.uid);
+
+        JsonObject requestJson = new JsonObject();
+
+        requestJson.addProperty("pio_appkey", this.appkey);
+        requestJson.addProperty("pio_uid", this.uid);
         if (this.latitude != null && this.longitude != null) {
-            builder.addQueryParameter("pio_latlng", this.latitude.toString() + "," + this.longitude.toString());
+            requestJson.addProperty("pio_latlng", this.latitude.toString() + "," + this.longitude.toString());
         }
+
+        String requestJsonString = requestJson.toString();
+
+        builder.setBody(requestJsonString);
+        builder.setHeader("Content-Type","application/json");
+        builder.setHeader("Content-Length", ""+requestJsonString.length());
+
         return builder.build();
     }
 }
diff --git a/client/src/main/java/io/prediction/UserActionItemRequestBuilder.java b/client/src/main/java/io/prediction/UserActionItemRequestBuilder.java
index afad562..0cddd25 100644
--- a/client/src/main/java/io/prediction/UserActionItemRequestBuilder.java
+++ b/client/src/main/java/io/prediction/UserActionItemRequestBuilder.java
@@ -1,14 +1,15 @@
 package io.prediction;
 
+import com.google.gson.JsonObject;
+import org.joda.time.DateTime;
 import com.ning.http.client.Request;
 import com.ning.http.client.RequestBuilder;
-import org.joda.time.DateTime;
 
 /**
  * UserActionItem request builder
  *
  * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.2
+ * @version 0.6.1
  * @since 0.2
  */
 
@@ -138,23 +139,33 @@
      */
     public Request build() {
         RequestBuilder builder = new RequestBuilder("POST");
-        builder.addQueryParameter("pio_appkey", this.appkey);
-        builder.addQueryParameter("pio_uid", this.uid);
-        builder.addQueryParameter("pio_iid", this.iid);
+
+        JsonObject requestJson = new JsonObject();
+
+        requestJson.addProperty("pio_appkey", this.appkey);
+        requestJson.addProperty("pio_uid", this.uid);
+        requestJson.addProperty("pio_iid", this.iid);
         if (this.latitude != null && this.longitude != null) {
-            builder.addQueryParameter("pio_latlng", this.latitude.toString() + "," + this.longitude.toString());
+            requestJson.addProperty("pio_latlng", this.latitude.toString() + "," + this.longitude.toString());
         }
         if (this.t != null) {
-            builder.addQueryParameter("pio_t", t.toString());
+            requestJson.addProperty("pio_t", t.toString());
         }
 
         String actionUrl = "/actions/u2i.";
-        builder.addQueryParameter("pio_action", this.action);
+        requestJson.addProperty("pio_action", this.action);
         if (this.action == RATE) {
-            builder.addQueryParameter("pio_rate", Integer.toString(this.rate));
+            requestJson.addProperty("pio_rate", Integer.toString(this.rate));
         }
 
         builder.setUrl(this.apiUrl + actionUrl + this.apiFormat);
+
+        String requestJsonString = requestJson.toString();
+
+        builder.setBody(requestJsonString);
+        builder.setHeader("Content-Type","application/json");
+        builder.setHeader("Content-Length", ""+requestJsonString.length());
+
         return builder.build();
     }
 }
diff --git a/client/src/test/java/com/tappingstone/predictionio/PredictionIOTest.java b/client/src/test/java/com/tappingstone/predictionio/PredictionIOTest.java
deleted file mode 100644
index 4393bba..0000000
--- a/client/src/test/java/com/tappingstone/predictionio/PredictionIOTest.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.tappingstone.predictionio;
-
-/**
- * Created with IntelliJ IDEA.
- * User: cqin
- * Date: 2/13/13
- * Time: 10:25 PM
- */
-public class PredictionIOTest {
-}
diff --git a/client/src/test/java/io/prediction/ClientTest.java b/client/src/test/java/io/prediction/ClientTest.java
new file mode 100644
index 0000000..ea2ce6f
--- /dev/null
+++ b/client/src/test/java/io/prediction/ClientTest.java
@@ -0,0 +1,452 @@
+package io.prediction;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.collection.IsArray.array;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.*;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+
+/**
+ * Tests for {@link Client}.
+ *
+ * @author support@prediction.io (The PredictionIO Team)
+ */
+@RunWith(JUnit4.class)
+public class ClientTest {
+
+    String appkey = "validkey";
+    int apiPort = 5784;
+    String apiURL = "http://localhost:" + apiPort;
+    Client client = new Client(appkey, apiURL);
+
+    @Rule
+    public WireMockRule wireMockRule = new WireMockRule(apiPort);
+
+    @Test
+    public void getStatus() {
+        stubFor(get(urlEqualTo("/"))
+            .willReturn(aResponse()
+                .withStatus(200)
+                .withHeader("Content-Type", "text/plain")
+                .withBody("online")));
+
+        try {
+            assertThat(client.getStatus(), is("online"));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void createUser() {
+        String url = "/users.json";
+        stubFor(post(urlEqualTo(url))
+              .willReturn(aResponse().withStatus(201)));
+
+        try {
+            client.createUser("foo");
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        verify(postRequestedFor(urlMatching(url))
+               .withRequestBody(containing("\"pio_appkey\":\"validkey\""))
+               .withRequestBody(containing("\"pio_uid\":\"foo\"")));
+
+        try {
+            client.createUser(client.getCreateUserRequestBuilder("bar"));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        verify(postRequestedFor(urlMatching(url))
+               .withRequestBody(containing("\"pio_appkey\":\"validkey\""))
+               .withRequestBody(containing("\"pio_uid\":\"bar\"")));
+    }
+
+    @Test
+    public void getUser() {
+        try {
+            User fooUser = client.getUser("baz");
+            assertThat(fooUser.getUid(), is("baz"));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    /**
+    @Test
+    public void deleteUser() {
+        stubFor(delete(urlEqualTo("/users/beef.json"))
+                .willReturn(aResponse().withStatus(200)));
+
+        try {
+            client.deleteUser("beef");
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            System.err.println("yo");
+            System.err.println(e);
+            fail(e.getMessage());
+        }
+    }
+    */
+
+    @Test
+    public void createItem() {
+        String url = "/items.json";
+        stubFor(post(urlEqualTo(url))
+                .willReturn(aResponse().withStatus(201)));
+
+        try {
+            client.createItem("foo", new String[]{"bar", "baz"});
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        verify(postRequestedFor(urlMatching(url))
+               .withRequestBody(containing("\"pio_appkey\":\"validkey\""))
+               .withRequestBody(containing("\"pio_iid\":\"foo\""))
+               .withRequestBody(containing("\"pio_itypes\":\"bar,baz\"")));
+
+        try {
+            client.createItem(client.getCreateItemRequestBuilder("bar", new String[]{"dead", "beef"}));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        verify(postRequestedFor(urlMatching(url))
+               .withRequestBody(containing("\"pio_appkey\":\"validkey\""))
+               .withRequestBody(containing("\"pio_iid\":\"bar\""))
+               .withRequestBody(containing("\"pio_itypes\":\"dead,beef\"")));
+    }
+
+    @Test
+    public void getItem() {
+        try {
+            Item item = client.getItem("beef");
+            assertThat(item.getIid(), is("beef"));
+            assertThat(item.getItypes(), is(array(equalTo("foo"), equalTo("bar"))));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void getItemRecTopN() {
+        try {
+            client.identify("foo");
+            String[] items = client.getItemRecTopN("greatengine", 5);
+            assertThat(items.length, is(5));
+            assertThat(items, is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+        } catch (UnidentifiedUserException e) {
+            fail(e.getMessage());
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        try {
+            String[] items = client.getItemRecTopN("greatengine", "foo", 5);
+            assertThat(items.length, is(5));
+            assertThat(items, is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        try {
+            client.identify("foo");
+            String[] items = client.getItemRecTopN(client.getItemRecGetTopNRequestBuilder("greatengine", 5));
+            assertThat(items.length, is(5));
+            assertThat(items, is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+        } catch (UnidentifiedUserException e) {
+            fail(e.getMessage());
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        try {
+            String[] items = client.getItemRecTopN(client.getItemRecGetTopNRequestBuilder("greatengine", "foo", 5));
+            assertThat(items.length, is(5));
+            assertThat(items, is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void getItemRecTopNWithAttributes() {
+        try {
+            client.identify("foo");
+            Map<String, String[]> items = client.getItemRecTopNWithAttributes("greatengineattr", 5, new String[]{"cost", "price"});
+            assertThat(items.size(), is(3));
+            assertThat(items.get("pio_iids").length, is(5));
+            assertThat(items.get("cost").length, is(5));
+            assertThat(items.get("price").length, is(5));
+            assertThat(items.get("pio_iids"), is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+            assertThat(items.get("cost"), is(array(equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"), equalTo("1"))));
+            assertThat(items.get("price"), is(array(equalTo("6"), equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"))));
+        } catch (UnidentifiedUserException e) {
+            fail(e.getMessage());
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        try {
+            Map<String, String[]> items = client.getItemRecTopNWithAttributes("greatengineattr", "foo", 5, new String[]{"cost", "price"});
+            assertThat(items.size(), is(3));
+            assertThat(items.get("pio_iids").length, is(5));
+            assertThat(items.get("cost").length, is(5));
+            assertThat(items.get("price").length, is(5));
+            assertThat(items.get("pio_iids"), is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+            assertThat(items.get("cost"), is(array(equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"), equalTo("1"))));
+            assertThat(items.get("price"), is(array(equalTo("6"), equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"))));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        try {
+            Map<String, String[]> items = client.getItemRecTopNWithAttributes(client.getItemRecGetTopNRequestBuilder("greatengineattr", "foo", 5, new String[]{"cost", "price"}));
+            assertThat(items.size(), is(3));
+            assertThat(items.get("pio_iids").length, is(5));
+            assertThat(items.get("cost").length, is(5));
+            assertThat(items.get("price").length, is(5));
+            assertThat(items.get("pio_iids"), is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+            assertThat(items.get("cost"), is(array(equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"), equalTo("1"))));
+            assertThat(items.get("price"), is(array(equalTo("6"), equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"))));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void getItemSimTopN() {
+        try {
+            String[] items = client.getItemSimTopN("anothergreatengine", "foo", 5);
+            assertThat(items.length, is(5));
+            assertThat(items, is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        try {
+            String[] items = client.getItemSimTopN(client.getItemSimGetTopNRequestBuilder("anothergreatengine", "foo", 5));
+            assertThat(items.length, is(5));
+            assertThat(items, is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void getItemSimTopNWithAttributes() {
+        try {
+            Map<String, String[]> items = client.getItemSimTopNWithAttributes("anothergreatengineattr", "foo", 5, new String[]{"cost", "price"});
+            assertThat(items.size(), is(3));
+            assertThat(items.get("pio_iids").length, is(5));
+            assertThat(items.get("cost").length, is(5));
+            assertThat(items.get("price").length, is(5));
+            assertThat(items.get("pio_iids"), is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+            assertThat(items.get("cost"), is(array(equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"), equalTo("1"))));
+            assertThat(items.get("price"), is(array(equalTo("6"), equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"))));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        try {
+            Map<String, String[]> items = client.getItemSimTopNWithAttributes(client.getItemSimGetTopNRequestBuilder("anothergreatengineattr", "foo", 5, new String[]{"cost", "price"}));
+            assertThat(items.size(), is(3));
+            assertThat(items.get("pio_iids").length, is(5));
+            assertThat(items.get("cost").length, is(5));
+            assertThat(items.get("price").length, is(5));
+            assertThat(items.get("pio_iids"), is(array(equalTo("baz"), equalTo("bar"), equalTo("foo"), equalTo("beef"), equalTo("dead"))));
+            assertThat(items.get("cost"), is(array(equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"), equalTo("1"))));
+            assertThat(items.get("price"), is(array(equalTo("6"), equalTo("5"), equalTo("4"), equalTo("3"), equalTo("2"))));
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void userActionItem() {
+        String url = "/actions/u2i.json";
+        stubFor(post(urlEqualTo(url))
+                .willReturn(aResponse().withStatus(201)));
+
+        try {
+            client.identify("foo");
+            client.userActionItem("view", "bar");
+        } catch (UnidentifiedUserException e) {
+            fail(e.getMessage());
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        verify(postRequestedFor(urlMatching(url))
+               .withRequestBody(containing("\"pio_appkey\":\"validkey\""))
+               .withRequestBody(containing("\"pio_uid\":\"foo\""))
+               .withRequestBody(containing("\"pio_iid\":\"bar\""))
+               .withRequestBody(containing("\"pio_action\":\"view\"")));
+
+        try {
+            client.userActionItem("foo", "view", "bar");
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        verify(postRequestedFor(urlMatching(url))
+               .withRequestBody(containing("\"pio_appkey\":\"validkey\""))
+               .withRequestBody(containing("\"pio_uid\":\"foo\""))
+               .withRequestBody(containing("\"pio_iid\":\"bar\""))
+               .withRequestBody(containing("\"pio_action\":\"view\"")));
+
+        try {
+            client.identify("foo");
+            FutureAPIResponse r = client.userActionItemAsFuture("like", "bar");
+            client.userActionItem(r);
+        } catch (UnidentifiedUserException e) {
+            fail(e.getMessage());
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        verify(postRequestedFor(urlMatching(url))
+               .withRequestBody(containing("\"pio_appkey\":\"validkey\""))
+               .withRequestBody(containing("\"pio_uid\":\"foo\""))
+               .withRequestBody(containing("\"pio_iid\":\"bar\""))
+               .withRequestBody(containing("\"pio_action\":\"like\"")));
+
+        try {
+            FutureAPIResponse r = client.userActionItemAsFuture("foo", "like", "bar");
+            client.userActionItem(r);
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        verify(postRequestedFor(urlMatching(url))
+               .withRequestBody(containing("\"pio_appkey\":\"validkey\""))
+               .withRequestBody(containing("\"pio_uid\":\"foo\""))
+               .withRequestBody(containing("\"pio_iid\":\"bar\""))
+               .withRequestBody(containing("\"pio_action\":\"like\"")));
+
+        try {
+            UserActionItemRequestBuilder builder = client.getUserActionItemRequestBuilder("foo", "rate", "bar");
+            builder.rate(4);
+            client.userActionItem(builder);
+        } catch (ExecutionException e) {
+            fail(e.getMessage());
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+
+        verify(postRequestedFor(urlMatching(url))
+               .withRequestBody(containing("\"pio_appkey\":\"validkey\""))
+               .withRequestBody(containing("\"pio_uid\":\"foo\""))
+               .withRequestBody(containing("\"pio_iid\":\"bar\""))
+               .withRequestBody(containing("\"pio_action\":\"rate\""))
+               .withRequestBody(containing("\"pio_rate\":\"4\"")));
+    }
+
+}
diff --git a/client/src/test/resources/__files/engines/itemrec/greatengine/topn.json b/client/src/test/resources/__files/engines/itemrec/greatengine/topn.json
new file mode 100644
index 0000000..26e270d
--- /dev/null
+++ b/client/src/test/resources/__files/engines/itemrec/greatengine/topn.json
@@ -0,0 +1,9 @@
+{
+    "pio_iids": [
+        "baz",
+        "bar",
+        "foo",
+        "beef",
+        "dead"
+    ]
+}
\ No newline at end of file
diff --git a/client/src/test/resources/__files/engines/itemrec/greatengineattr/topn.json b/client/src/test/resources/__files/engines/itemrec/greatengineattr/topn.json
new file mode 100644
index 0000000..287e22c
--- /dev/null
+++ b/client/src/test/resources/__files/engines/itemrec/greatengineattr/topn.json
@@ -0,0 +1,23 @@
+{
+    "pio_iids": [
+        "baz",
+        "bar",
+        "foo",
+        "beef",
+        "dead"
+    ],
+    "cost": [
+        5,
+        4,
+        3,
+        2,
+        1
+    ],
+    "price": [
+        6,
+        5,
+        4,
+        3,
+        2
+    ]
+}
\ No newline at end of file
diff --git a/client/src/test/resources/__files/engines/itemsim/anothergreatengine/topn.json b/client/src/test/resources/__files/engines/itemsim/anothergreatengine/topn.json
new file mode 100644
index 0000000..26e270d
--- /dev/null
+++ b/client/src/test/resources/__files/engines/itemsim/anothergreatengine/topn.json
@@ -0,0 +1,9 @@
+{
+    "pio_iids": [
+        "baz",
+        "bar",
+        "foo",
+        "beef",
+        "dead"
+    ]
+}
\ No newline at end of file
diff --git a/client/src/test/resources/__files/engines/itemsim/anothergreatengineattr/topn.json b/client/src/test/resources/__files/engines/itemsim/anothergreatengineattr/topn.json
new file mode 100644
index 0000000..287e22c
--- /dev/null
+++ b/client/src/test/resources/__files/engines/itemsim/anothergreatengineattr/topn.json
@@ -0,0 +1,23 @@
+{
+    "pio_iids": [
+        "baz",
+        "bar",
+        "foo",
+        "beef",
+        "dead"
+    ],
+    "cost": [
+        5,
+        4,
+        3,
+        2,
+        1
+    ],
+    "price": [
+        6,
+        5,
+        4,
+        3,
+        2
+    ]
+}
\ No newline at end of file
diff --git a/client/src/test/resources/__files/items/beef.json b/client/src/test/resources/__files/items/beef.json
new file mode 100644
index 0000000..7fce6c2
--- /dev/null
+++ b/client/src/test/resources/__files/items/beef.json
@@ -0,0 +1,7 @@
+{
+    "pio_iid": "beef",
+    "pio_itypes": [
+        "foo",
+        "bar"
+    ]
+}
\ No newline at end of file
diff --git a/client/src/test/resources/__files/users/baz.json b/client/src/test/resources/__files/users/baz.json
new file mode 100644
index 0000000..3ab5f27
--- /dev/null
+++ b/client/src/test/resources/__files/users/baz.json
@@ -0,0 +1,3 @@
+{
+    "pio_uid": "baz"
+}
diff --git a/examples/import/pom.xml b/examples/import/pom.xml
index 601ec44..ea5d18d 100644
--- a/examples/import/pom.xml
+++ b/examples/import/pom.xml
@@ -3,7 +3,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>io.prediction.samples</groupId>
     <artifactId>sample-import</artifactId>
-    <version>0.6.0</version>
+    <version>0.6.1</version>
     <packaging>jar</packaging>
     <name>PredictionIO Java SDK Examples: Import</name>
 
@@ -11,7 +11,7 @@
         <dependency>
             <groupId>io.prediction</groupId>
             <artifactId>client</artifactId>
-            <version>0.6.0</version>
+            <version>0.6.1</version>
         </dependency>
     </dependencies>
 
diff --git a/examples/import_deprecated/pom.xml b/examples/import_deprecated/pom.xml
index 601ec44..ea5d18d 100644
--- a/examples/import_deprecated/pom.xml
+++ b/examples/import_deprecated/pom.xml
@@ -3,7 +3,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>io.prediction.samples</groupId>
     <artifactId>sample-import</artifactId>
-    <version>0.6.0</version>
+    <version>0.6.1</version>
     <packaging>jar</packaging>
     <name>PredictionIO Java SDK Examples: Import</name>
 
@@ -11,7 +11,7 @@
         <dependency>
             <groupId>io.prediction</groupId>
             <artifactId>client</artifactId>
-            <version>0.6.0</version>
+            <version>0.6.1</version>
         </dependency>
     </dependencies>
 
diff --git a/examples/simpletasks1/pom.xml b/examples/simpletasks1/pom.xml
index 1f42f23..1fd1bc9 100644
--- a/examples/simpletasks1/pom.xml
+++ b/examples/simpletasks1/pom.xml
@@ -3,7 +3,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>io.prediction.samples</groupId>
     <artifactId>sample-client</artifactId>
-    <version>0.6.0</version>
+    <version>0.6.1</version>
     <packaging>jar</packaging>
     <name>PredictionIO Java SDK Examples: Client</name>
 
@@ -11,7 +11,7 @@
         <dependency>
             <groupId>io.prediction</groupId>
             <artifactId>client</artifactId>
-            <version>0.6.0</version>
+            <version>0.6.1</version>
         </dependency>
     </dependencies>
 
diff --git a/examples/simpletasks1_deprecated/pom.xml b/examples/simpletasks1_deprecated/pom.xml
index 1f42f23..1fd1bc9 100644
--- a/examples/simpletasks1_deprecated/pom.xml
+++ b/examples/simpletasks1_deprecated/pom.xml
@@ -3,7 +3,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>io.prediction.samples</groupId>
     <artifactId>sample-client</artifactId>
-    <version>0.6.0</version>
+    <version>0.6.1</version>
     <packaging>jar</packaging>
     <name>PredictionIO Java SDK Examples: Client</name>
 
@@ -11,7 +11,7 @@
         <dependency>
             <groupId>io.prediction</groupId>
             <artifactId>client</artifactId>
-            <version>0.6.0</version>
+            <version>0.6.1</version>
         </dependency>
     </dependencies>
 
diff --git a/examples/simpletasks2/pom.xml b/examples/simpletasks2/pom.xml
index 1f42f23..1fd1bc9 100644
--- a/examples/simpletasks2/pom.xml
+++ b/examples/simpletasks2/pom.xml
@@ -3,7 +3,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>io.prediction.samples</groupId>
     <artifactId>sample-client</artifactId>
-    <version>0.6.0</version>
+    <version>0.6.1</version>
     <packaging>jar</packaging>
     <name>PredictionIO Java SDK Examples: Client</name>
 
@@ -11,7 +11,7 @@
         <dependency>
             <groupId>io.prediction</groupId>
             <artifactId>client</artifactId>
-            <version>0.6.0</version>
+            <version>0.6.1</version>
         </dependency>
     </dependencies>
 
diff --git a/pom.xml b/pom.xml
index 2b92f48..5cf8636 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>io.prediction</groupId>
     <artifactId>sdk</artifactId>
-    <version>0.6.0</version>
+    <version>0.6.1</version>
     <url>http://prediction.io</url>
     <packaging>pom</packaging>
     <name>PredictionIO Java SDK</name>