You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@predictionio.apache.org by do...@apache.org on 2018/09/11 17:54:43 UTC

[2/2] predictionio-sdk-java git commit: [PIO-162] Make Java SDK compliant to ASF standards

[PIO-162] Make Java SDK compliant to ASF standards

Closes #6


Project: http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/commit/0780fcd5
Tree: http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/tree/0780fcd5
Diff: http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/diff/0780fcd5

Branch: refs/heads/develop
Commit: 0780fcd55a47eceb2e2a4964d821523f8b1647ad
Parents: 2747475
Author: Donald Szeto <do...@apache.org>
Authored: Tue Sep 11 10:53:35 2018 -0700
Committer: Donald Szeto <ds...@salesforce.com>
Committed: Tue Sep 11 10:54:20 2018 -0700

----------------------------------------------------------------------
 .rat-excludes                                   |   2 +
 .travis.yml                                     |  25 +-
 LICENSE                                         | 209 +++++-
 README.md                                       | 123 ++--
 client/.rat-excludes                            |   1 +
 client/pom.xml                                  |  29 +-
 .../main/java/io/prediction/APIResponse.java    |  35 -
 .../src/main/java/io/prediction/BaseClient.java | 135 ----
 .../java/io/prediction/DateTimeAdapter.java     |  33 -
 .../main/java/io/prediction/EngineClient.java   | 122 ----
 client/src/main/java/io/prediction/Event.java   | 154 -----
 .../main/java/io/prediction/EventClient.java    | 659 ------------------
 .../main/java/io/prediction/FileExporter.java   |  64 --
 .../java/io/prediction/FutureAPIResponse.java   |  80 ---
 .../main/java/io/prediction/package-info.java   |  10 -
 .../predictionio/sdk/java/APIResponse.java      |  52 ++
 .../predictionio/sdk/java/BaseClient.java       | 151 +++++
 .../predictionio/sdk/java/DateTimeAdapter.java  |  48 ++
 .../predictionio/sdk/java/EngineClient.java     | 135 ++++
 .../org/apache/predictionio/sdk/java/Event.java | 166 +++++
 .../predictionio/sdk/java/EventClient.java      | 663 +++++++++++++++++++
 .../predictionio/sdk/java/FileExporter.java     |  80 +++
 .../sdk/java/FutureAPIResponse.java             |  91 +++
 .../predictionio/sdk/java/package-info.java     |  27 +
 .../java/io/prediction/FileExporterTest.java    | 116 ----
 .../predictionio/sdk/java/FileExporterTest.java | 135 ++++
 examples/import/pom.xml                         |  25 +-
 .../io/prediction/samples/SampleImport.java     | 147 ----
 .../predictionio/samples/SampleImport.java      | 165 +++++
 examples/quickstart_import/pom.xml              |  25 +-
 .../io/prediction/samples/QuickstartImport.java |  77 ---
 .../predictionio/samples/QuickstartImport.java  |  91 +++
 pom.xml                                         | 130 ++--
 33 files changed, 2205 insertions(+), 1800 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/.rat-excludes
----------------------------------------------------------------------
diff --git a/.rat-excludes b/.rat-excludes
new file mode 100644
index 0000000..b3331b5
--- /dev/null
+++ b/.rat-excludes
@@ -0,0 +1,2 @@
+.rat-excludes
+examples/import/sampledata/sample1.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index af8bd9e..597ca52 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,21 @@
+# 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.
+
 language: java
 jdk:
-  - oraclejdk7
   - openjdk7
-  - openjdk6
-env:
-  - JAVA_OPTS=-Xmx1024m
-before_script:
-  - ulimit -n 64000
-  - ulimit -u 64000
+  - openjdk8
+  - oraclejdk8
+  - oraclejdk9

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
index 11c8530..d645695 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,13 +1,202 @@
-Copyright 2013 TappingStone Inc.
 
-Licensed 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
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
 
-    http://www.apache.org/licenses/LICENSE-2.0
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-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.
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 8fadd34..0b2e0af 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,11 @@
-PredictionIO Java SDK
-=====================
+# Apache PredictionIO Java SDK
 
-This bulk of this README is divided into two sections: Using the SDK and Developing the SDK.
-Choose the one the suits you. For Support please see the bottom of this README.
+This bulk of this README is divided into two sections: Using the SDK and developing the SDK.
+Choose the one the suits you. For support please see the bottom of this README.
 
-Using the SDK
-=============
+# Using the SDK
 
-
-With Maven
-----------
+## With Maven
 
 If you have a Maven project, simply add the dependency to your `pom.xml`.
 
@@ -18,17 +14,16 @@ If you have a Maven project, simply add the dependency to your `pom.xml`.
     ...
     <dependencies>
         <dependency>
-            <groupId>io.prediction</groupId>
-            <artifactId>client</artifactId>
-            <version>0.9.5</version>
+            <groupId>org.apache.predictionio</groupId>
+            <artifactId>predictionio-sdk-java-client</artifactId>
+            <version>0.13.0</version>
         </dependency>
     </dependencies>
     ...
 ```
 
 
-With Ivy
---------
+## With Ivy
 
 If you use Ivy, simply add the dependency to your `ivy.xml`.
 
@@ -36,105 +31,81 @@ If you use Ivy, simply add the dependency to your `ivy.xml`.
 <ivy-module ...>
     ...
     <dependencies>
-        <dependency org="io.prediction" name="client" rev="0.9.5" />
+        <dependency org="org.apache.predictionio" name="predictionio-sdk-java-client" rev="0.13.0" />
         ...
     </dependencies>
     ...
 ```
 
 
-With sbt
---------
+## With sbt
 
 If you have an sbt project, add the library dependency to your build definition.
 
 ```Scala
-libraryDependencies += "io.prediction" % "client" % "0.9.5"
+libraryDependencies += "org.apache.predictionio" % "predictionio-sdk-java-client" % "0.13.0"
 ```
 
 
-Examples
---------
+## Examples
 
 Please check out the examples under `examples/`.
 
 
-Developing SDK - Building from Source
-=====================================
+# Developing SDK - Building from Source
 
-Assuming you are cloning to your home directory.
+Fork and clone from GitHub. The following assumes you are cloning to your home directory.
 
 ```sh
 cd ~
-git clone git://github.com/PredictionIO/PredictionIO-Java-SDK.git
+git clone https://github.com/<your_github_handle>/predictionio-sdk-java.git
 ```
 
-To build this SDK you will need Maven 3+. Run the following to publish the module to your local Maven repository.
+To build this SDK you will need Maven 3+. Run the following to publish the module to your local
+Maven repository.
 
 ```sh
-cd ~/PredictionIO-Java-SDK
+cd ~/predictionio-sdk-java
 mvn clean install
 ```
 
 Run the following to generate API documentation.
 
 ```sh
-cd ~/PredictionIO-Java-SDK
-mvn clean javadoc:javadoc
+mvn javadoc:javadoc
 ```
 
-Using the Published Module with Maven
--------------------------------------
 
-Simply add the dependency to your `pom.xml`.
+# Running CLI Examples
 
-```XML
-<project ...>
-    ...
-    <dependencies>
-        <dependency>
-            <groupId>io.prediction</groupId>
-            <artifactId>client</artifactId>
-            <version>0.9.6-SNAPSHOT</version>
-        </dependency>
-    </dependencies>
-    ...
-```
 
+## Building
 
-Running CLI Examples
---------------------
+If your PredictionIO server is not at `localhost`, edit the source and replace API URLs with your 
+redictionIO server host.
 
-
-### Building
-
-If your PredictionIO server is not at localhost, edit the source and replace
-API URLs with your PredictionIO server host.
-
-To build these examples you will need Maven 3+.
-Run the following in each example's directory, e.g.
+To build these examples you will need Maven 3+. Run the following in each example's directory, e.g.
 
 ```sh
-cd ~/PredictionIO-Java-SDK/examples/quickstart_import
+cd ~/predictionio-sdk-java/examples/quickstart_import
 mvn clean compile assembly:single
-cd ~/PredictionIO-Java-SDK/examples/import
+cd ~/predictionio-sdk-java/examples/import
 mvn clean compile assembly:single
 ```
 
 These will create JAR files with all dependencies built in.
 
 
-### Try It Now
+## Try It Now
 
-For running the quick start example (quickstart_import),
-please refer to the "Quick Start" page of the PredictionIO documentation.
-Most importantly, create an App with `pio new app MyApp` and take note of the
-`Access Key` produced, which will be `<your accessKey here>` in the following.
+For running the quick start example (`quickstart_import`), please refer to the "Quick Start" page of
+the PredictionIO documentation. Most importantly, create an App with `pio new app MyApp` and take
+note of the `Access Key` produced, which will be `<your accessKey here>` in the following.
 
 For `quickstart_import`,
 
 ```sh
-cd ~/PredictionIO-Java-SDK/examples/quickstart_import
+cd ~/predictionio-sdk-java/examples/quickstart_import
 java -jar target/quickstart-import-<latest version>-jar-with-dependencies.jar <your accessKey here>
 ```
 
@@ -146,7 +117,7 @@ curl -i -X GET http://localhost:7070/events.json?accessKey=<your accessKey here>
 To import the provided small sample data for the import example using asynchronous calls:
 
 ```sh
-cd ~/PredictionIO-Java-SDK/examples/import
+cd ~/predictionio-sdk-java/examples/import
 java -jar target/sample-import-<latest version>-jar-with-dependencies.jar <your accessKey here> sampledata/sample1.txt
 ```
 
@@ -158,19 +129,29 @@ curl -i -X GET http://localhost:7070/events.json?accessKey=<your accessKey here>
 Enjoy!
 
 
-Support
-=======
+# Support
+
+
+## Bugs and Feature Requests
+
+Use [Apache JIRA](https://issues.apache.org/jira/browse/PIO) to report bugs or request new features.
+
+
+## Community
+
+Keep track of development and community news.
 
+*   Subscribe to the user mailing list <ma...@predictionio.apache.org>
+    and the dev mailing list <ma...@predictionio.apache.org>
+*   Follow [@predictionio](https://twitter.com/predictionio) on Twitter.
 
-Forum
------
 
-https://groups.google.com/group/predictionio-user
+## Contributing
 
+Read the [Contribute Code](http://predictionio.apache.org/community/contribute-code/) page.
 
-Issue Tracker
--------------
 
-https://predictionio.atlassian.net
+## License
 
-If you are unsure whether a behavior is an issue, bringing it up in the forum is highly encouraged.
+Apache PredictionIO is under [Apache 2
+license](http://www.apache.org/licenses/LICENSE-2.0.html).
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/.rat-excludes
----------------------------------------------------------------------
diff --git a/client/.rat-excludes b/client/.rat-excludes
new file mode 100644
index 0000000..1ff53dc
--- /dev/null
+++ b/client/.rat-excludes
@@ -0,0 +1 @@
+.rat-excludes

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/pom.xml
----------------------------------------------------------------------
diff --git a/client/pom.xml b/client/pom.xml
index 4b0d89d..080e2bf 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -1,17 +1,31 @@
+<!--
+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.
+-->
+
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
 
   <parent>
-    <groupId>io.prediction</groupId>
-    <artifactId>sdk</artifactId>
-    <relativePath>../pom.xml</relativePath>
-    <version>0.9.6-SNAPSHOT</version>
+    <groupId>org.apache.predictionio</groupId>
+    <artifactId>predictionio-sdk-java</artifactId>
+    <version>0.13.0-SNAPSHOT</version>
   </parent>
 
-  <artifactId>client</artifactId>
+  <artifactId>predictionio-sdk-java-client</artifactId>
   <packaging>jar</packaging>
 
-  <name>PredictionIO Java SDK: Client</name>
+  <name>Apache PredictionIO Java SDK: Client</name>
 
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -58,7 +72,6 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.0</version>
         <configuration>
           <encoding>UTF-8</encoding>
           <source>1.7</source>
@@ -68,7 +81,6 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-source-plugin</artifactId>
-        <version>2.2.1</version>
         <executions>
           <execution>
             <id>attach-sources</id>
@@ -81,7 +93,6 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
-        <version>2.9</version>
         <executions>
           <execution>
             <id>attach-javadocs</id>

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/io/prediction/APIResponse.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/io/prediction/APIResponse.java b/client/src/main/java/io/prediction/APIResponse.java
deleted file mode 100644
index 380b6d4..0000000
--- a/client/src/main/java/io/prediction/APIResponse.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package io.prediction;
-
-/**
- * API Response class for wrapping responses.
- *
- * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.8.3
- * @since 0.2
- */
-
-public class APIResponse {
-    private int status;
-    private String message;
-
-    public APIResponse(int status, String message) {
-        this.status = status;
-        this.message = message;
-    }
-
-    public int getStatus() {
-        return this.status;
-    }
-
-    public void setStatus(int status) {
-        this.status = status;
-    }
-
-    public String getMessage() {
-        return this.message;
-    }
-
-    public void setMessage(String message) {
-        this.message = message;
-    }
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/io/prediction/BaseClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/io/prediction/BaseClient.java b/client/src/main/java/io/prediction/BaseClient.java
deleted file mode 100644
index 3e350f9..0000000
--- a/client/src/main/java/io/prediction/BaseClient.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package io.prediction;
-
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.ning.http.client.*;
-import com.ning.http.client.extra.ThrottleRequestFilter;
-import com.ning.http.client.providers.netty.NettyAsyncHttpProvider;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-/**
- * BaseClient contains code common to both {@link EventClient} and {@link EngineClient}.
- *
- * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.8.3
- * @since 0.1
- */
-public abstract class BaseClient implements Closeable {
-    private static final int defaultThreadLimit = 1;
-    private static final String defaultApiVersion = "";
-    private static final int defaultQSize = 0;
-    private static final int defaultTimeout = 5;
-
-    // HTTP status code
-    static final int HTTP_OK = 200;
-    static final int HTTP_CREATED = 201;
-
-    // API Url
-    final String apiUrl;
-
-    final AsyncHttpClient client;
-
-    final JsonParser parser = new JsonParser();
-
-    /**
-     * @param apiURL the URL of the PredictionIO API
-     */
-    public BaseClient(String apiURL) {
-        this(apiURL, BaseClient.defaultThreadLimit);
-    }
-
-    /**
-     * @param apiURL the URL of the PredictionIO API
-     * @param threadLimit maximum number of simultaneous threads (connections) to the API
-     */
-    public BaseClient(String apiURL, int threadLimit) {
-        this(apiURL, threadLimit, defaultQSize);
-    }
-
-    /**
-     * @param apiURL the URL of the PredictionIO API
-     * @param threadLimit maximum number of simultaneous threads (connections) to the API
-     * @param qSize size of the queue
-     */
-    public BaseClient(String apiURL, int threadLimit, int qSize) {
-        this(apiURL, threadLimit, qSize, defaultTimeout);
-    }
-
-    /**
-     * @param apiURL the URL of the PredictionIO API
-     * @param threadLimit maximum number of simultaneous threads (connections) to the API
-     * @param qSize size of the queue
-     * @param timeout timeout in seconds for the connections
-     */
-    public BaseClient(String apiURL, int threadLimit, int qSize, int timeout) {
-        this.apiUrl = apiURL;
-        // Async HTTP client config
-        AsyncHttpClientConfig config = (new AsyncHttpClientConfig.Builder())
-                .setAllowPoolingConnections(true)
-                .setAllowPoolingSslConnections(true)
-                .addRequestFilter(new ThrottleRequestFilter(threadLimit))
-                .setMaxConnectionsPerHost(threadLimit)
-                .setRequestTimeout(timeout * 1000)
-                .setIOThreadMultiplier(threadLimit)
-                .build();
-        this.client = new AsyncHttpClient(new NettyAsyncHttpProvider(config), config);
-    }
-
-    /**
-     * Close all connections associated with this client.
-     * It is a good practice to always close the client after use.
-     */
-    @Override
-    public void close() {
-        client.close();
-    }
-
-    AsyncHandler<APIResponse> getHandler() {
-        return new AsyncHandler<APIResponse>() {
-            private final Response.ResponseBuilder builder = new Response.ResponseBuilder();
-
-            public void onThrowable(Throwable t) {
-            }
-
-            public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception {
-                builder.accumulate(content);
-                return STATE.CONTINUE;
-            }
-
-            public STATE onStatusReceived(HttpResponseStatus status) throws Exception {
-                builder.accumulate(status);
-                return STATE.CONTINUE;
-            }
-
-            public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception {
-                builder.accumulate(headers);
-                return STATE.CONTINUE;
-            }
-
-            public APIResponse onCompleted() throws Exception {
-                Response r = builder.build();
-                return new APIResponse(r.getStatusCode(), r.getResponseBody());
-            }
-        };
-    }
-
-    /**
-     * Get status of the API.
-     *
-     * @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 String getStatus() throws ExecutionException, InterruptedException, IOException {
-        return (new FutureAPIResponse(client.prepareGet(apiUrl).execute(getHandler()))).get().getMessage();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/io/prediction/DateTimeAdapter.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/io/prediction/DateTimeAdapter.java b/client/src/main/java/io/prediction/DateTimeAdapter.java
deleted file mode 100644
index 12eb1f3..0000000
--- a/client/src/main/java/io/prediction/DateTimeAdapter.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package io.prediction;
-
-import com.google.gson.JsonDeserializationContext;
-import com.google.gson.JsonDeserializer;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParseException;
-import com.google.gson.JsonPrimitive;
-import com.google.gson.JsonSerializer;
-import com.google.gson.JsonSerializationContext;
-
-import org.joda.time.DateTime;
-
-import java.lang.reflect.Type;
-
-/**
- * DateTimeAdapter turns a String in ISO 8601 format into a DateTime object, and vice versa.
- *
- * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.8.3
- * @since 0.8.0
- */
-public class DateTimeAdapter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {
-    @Override
-    public JsonElement serialize(DateTime src, Type type, JsonSerializationContext context) {
-        return new JsonPrimitive(src.toString());
-    }
-
-    @Override
-    public DateTime deserialize(final JsonElement json, final Type type,
-            final JsonDeserializationContext context) throws JsonParseException {
-        return new DateTime(json.getAsJsonPrimitive().getAsString());
-    }
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/io/prediction/EngineClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/io/prediction/EngineClient.java b/client/src/main/java/io/prediction/EngineClient.java
deleted file mode 100644
index dd1d625..0000000
--- a/client/src/main/java/io/prediction/EngineClient.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package io.prediction;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonObject;
-import com.ning.http.client.Request;
-import com.ning.http.client.RequestBuilder;
-
-import org.joda.time.DateTime;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-/**
- * EngineClient contains generic methods sendQuery() and sendQueryAsFuture()
- * for sending queries.
- *
- * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.8.3
- * @since 0.8.0
- */
-public class EngineClient extends BaseClient {
-    private static final String defaultEngineUrl = "http://localhost:8000";
-
-    /**
-     * Instantiates a PredictionIO RESTful API Engine Client using default values for API URL
-     * and default values in BaseClient.
-     * <p>
-     * The default API URL is http://localhost:8000.
-     */
-    public EngineClient() {
-        super(defaultEngineUrl);
-    }
-
-    /**
-     * Instantiates a PredictionIO RESTful API Engine Client using default values in BaseClient.
-     *
-     * @param engineURL the URL of the PredictionIO API
-     */
-    public EngineClient(String engineURL) {
-        super(engineURL);
-    }
-
-    /**
-     * Instantiates a PredictionIO RESTful API Engine Client using default values in BaseClient for
-     * parameters that are not specified.
-     *
-     * @param engineURL the URL of the PredictionIO API
-     * @param threadLimit maximum number of simultaneous threads (connections) to the API
-     */
-    public EngineClient(String engineURL, int threadLimit) {
-        super(engineURL, threadLimit);
-    }
-
-    /**
-     * Instantiates a PredictionIO RESTful API Engine Client using default values in BaseClient for
-     * parameters that are not specified.
-     *
-     * @param engineURL the URL of the PredictionIO API
-     * @param threadLimit maximum number of simultaneous threads (connections) to the API
-     * @param qSize size of the queue
-     */
-    public EngineClient(String engineURL, int threadLimit, int qSize) {
-        super(engineURL, threadLimit, qSize);
-    }
-
-    /**
-     * Instantiates a PredictionIO RESTful API Engine Client.
-     *
-     * @param engineURL the URL of the PredictionIO API
-     * @param threadLimit maximum number of simultaneous threads (connections) to the API
-     * @param qSize size of the queue
-     * @param timeout timeout in seconds for the connections
-     */
-    public EngineClient(String engineURL, int threadLimit, int qSize, int timeout) {
-        super(engineURL, threadLimit, qSize, timeout);
-    }
-
-    /**
-     * Sends a query asynchronously.
-     */
-    public FutureAPIResponse sendQueryAsFuture(Map<String, Object> query)
-            throws ExecutionException, InterruptedException, IOException {
-        RequestBuilder builder = new RequestBuilder("POST");
-        builder.setUrl(apiUrl + "/queries.json");
-
-        // handle DateTime separately
-        GsonBuilder gsonBuilder = new GsonBuilder();
-        gsonBuilder.registerTypeAdapter(DateTime.class, new DateTimeAdapter());
-        Gson gson = gsonBuilder.create();
-
-        String requestJsonString = gson.toJson(query);
-        builder.setBody(requestJsonString);
-        builder.setHeader("Content-Type","application/json");
-        builder.setHeader("Content-Length", ""+requestJsonString.length());
-        return new FutureAPIResponse(client.executeRequest(builder.build(), getHandler()));
-    }
-
-    /**
-     * Sends a query synchronously.
-     */
-    public JsonObject sendQuery(Map<String, Object> query)
-            throws ExecutionException, InterruptedException, IOException {
-        return sendQuery(sendQueryAsFuture(query));
-    }
-
-    /**
-     * Gets query result from a previously sent asynchronous request.
-     */
-    public JsonObject sendQuery(FutureAPIResponse response)
-            throws ExecutionException, InterruptedException, IOException {
-        int status = response.get().getStatus();
-        String message = response.get().getMessage();
-
-        if (status != BaseClient.HTTP_OK) {
-            throw new IOException(status + " " + message);
-        }
-        return ((JsonObject) parser.parse(message));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/io/prediction/Event.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/io/prediction/Event.java b/client/src/main/java/io/prediction/Event.java
deleted file mode 100644
index cf16151..0000000
--- a/client/src/main/java/io/prediction/Event.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package io.prediction;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
-import org.joda.time.DateTime;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Event class for PredictionIO Event objects.
- *
- * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.8.3
- * @since 0.8.0
- */
-
-public class Event {
-
-    // mandatory fields
-    private String event;
-    private String entityType;
-    private String entityId;
-
-    // optional fields
-    private String targetEntityType;
-    private String targetEntityId;
-    private Map<String, Object> properties = Maps.newHashMap();
-    private DateTime eventTime;
-
-    /**
-     * Instantiate an event object.
-     */
-    public Event() {
-    }
-
-    /**
-     * Returns the name of the event.
-     */
-    public String getEvent() {
-        return event;
-    }
-
-    /**
-     * Returns the entity type. entityType-entityId forms the unique identifier of the entity.
-     */
-    public String getEntityType() {
-        return entityType;
-    }
-
-    /**
-     * Returns the entity id. entityType-entityId forms the unique identifier of the entity.
-     */
-    public String getEntityId() {
-        return entityId;
-    }
-
-    /**
-     * Returns the target entity type, or null if the field is not set.
-     */
-    public String getTargetEntityType() {
-        return targetEntityType;
-    }
-
-    /**
-     * Returns the target entity id, or null if the field is not set.
-     */
-    public String getTargetEntityId() {
-        return targetEntityId;
-    }
-
-    /**
-     * Returns the set of properties as a map.
-     */
-    public Map<String, Object> getProperties() {
-        return properties;
-    }
-
-    /**
-     * Returns the event time, or null if the field is not set.
-     */
-    public DateTime getEventTime() {
-        return eventTime;
-    }
-
-    // builder methods for convenience
-
-    /**
-     * Sets the name of the event.
-     */
-    public Event event(String event) {
-        this.event = event;
-        return this;
-    }
-
-    /**
-     * Sets the entity type. entityType-entityId forms the unique identifier of the entity.
-     */
-    public Event entityType(String entityType) {
-        this.entityType = entityType;
-        return this;
-    }
-
-    /**
-     * Sets the entity id. entityType-entityId forms the unique identifier of the entity.
-     */
-    public Event entityId(String entityId) {
-        this.entityId = entityId;
-        return this;
-    }
-
-    public Event targetEntityType(String targetEntityType) {
-        this.targetEntityType = targetEntityType;
-        return this;
-    }
-
-    public Event targetEntityId(String targetEntityId) {
-        this.targetEntityId = targetEntityId;
-        return this;
-    }
-
-    public Event property(String key, Object value) {
-        this.properties.put(key, value);
-        return this;
-    }
-
-    public Event properties(Map<String, Object> properties) {
-        this.properties.putAll(properties);
-        return this;
-    }
-
-    public Event eventTime(DateTime eventTime) {
-        this.eventTime = eventTime;
-        return this;
-    }
-
-    // toJsonString and toString methods
-
-    public String toJsonString() {
-        return toString();
-    }
-
-    @Override
-    public String toString() {
-        // handle DateTime separately
-        GsonBuilder gsonBuilder = new GsonBuilder();
-        gsonBuilder.registerTypeAdapter(DateTime.class, new DateTimeAdapter());
-        Gson gson = gsonBuilder.create();
-        return gson.toJson(this); // works when there are no generic types
-    }
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/io/prediction/EventClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/io/prediction/EventClient.java b/client/src/main/java/io/prediction/EventClient.java
deleted file mode 100644
index 1f42926..0000000
--- a/client/src/main/java/io/prediction/EventClient.java
+++ /dev/null
@@ -1,659 +0,0 @@
-package io.prediction;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonArray;
-import com.ning.http.client.Request;
-import com.ning.http.client.RequestBuilder;
-
-import org.joda.time.DateTime;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-/**
- * EventClient contains the generic methods createEvent() and getEvent() for importing and
- * accessing events, as well as helper methods such as setUser(), unsetItem() and userActionItem()
- * for convenience. Methods with an "AsFuture" suffix are asynchronous.
- * <p>
- * 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.8.3
- * @since 0.8.0
- */
-public class EventClient extends BaseClient {
-    private static final String defaultEventUrl = "http://localhost:7070";
-
-    private final String accessKey;
-
-    /**
-     * Instantiate a PredictionIO RESTful API Event Client using default values for API URL
-     * and default values in {@link BaseClient}.
-     * <p>
-     * The default API URL is http://localhost:7070.
-     *
-     * @param accessKey the access key that this client will use to communicate with the API
-     */
-    public EventClient(String accessKey) {
-      this(accessKey, defaultEventUrl);
-    }
-
-    /**
-     * Instantiate a PredictionIO RESTful API Event Client using default values in
-     * {@link BaseClient}.
-     *
-     * @param accessKey the access key that this client will use to communicate with the API
-     * @param eventURL the URL of the PredictionIO API
-     */
-    public EventClient(String accessKey, String eventURL) {
-        super(eventURL);
-        this.accessKey = accessKey;
-    }
-
-    /**
-     * Instantiate a PredictionIO RESTful API Event Client using default values in
-     * {@link BaseClient} for parameters that are not specified.
-     *
-     * @param accessKey the access key that this client will use to communicate with the API
-     * @param eventURL the URL of the PredictionIO API
-     * @param threadLimit maximum number of simultaneous threads (connections) to the API
-     */
-    public EventClient(String accessKey, String eventURL, int threadLimit) {
-        super(eventURL, threadLimit);
-        this.accessKey = accessKey;
-    }
-
-    /**
-     * Instantiate a PredictionIO RESTful API Event Client using default values in
-     * {@link BaseClient} for parameters that are not specified.
-     *
-     * @param accessKey the access key that this client will use to communicate with the API
-     * @param eventURL the URL of the PredictionIO API
-     * @param threadLimit maximum number of simultaneous threads (connections) to the API
-     * @param qSize size of the queue
-     */
-    public EventClient(String accessKey, String eventURL, int threadLimit, int qSize) {
-        super(eventURL, threadLimit, qSize);
-        this.accessKey = accessKey;
-    }
-
-    /**
-     * Instantiate a PredictionIO RESTful API Event Client.
-     *
-     * @param accessKey the access key that this client will use to communicate with the API
-     * @param eventURL the URL of the PredictionIO API
-     * @param threadLimit maximum number of simultaneous threads (connections) to the API
-     * @param qSize size of the queue
-     * @param timeout timeout in seconds for the connections
-     */
-    public EventClient(String accessKey, String eventURL, int threadLimit, int qSize, int timeout) {
-        super(eventURL, threadLimit, qSize, timeout);
-        this.accessKey = accessKey;
-    }
-
-    /**
-     * Sends an asynchronous create event request to the API.
-     *
-     * @param event an instance of {@link Event} that will be turned into a request
-     */
-    public FutureAPIResponse createEventAsFuture(Event event) throws IOException {
-        RequestBuilder builder = new RequestBuilder("POST");
-        builder.setUrl(apiUrl + "/events.json?accessKey=" + accessKey);
-        String requestJsonString = event.toJsonString();
-        builder.setBody(requestJsonString);
-        builder.setHeader("Content-Type","application/json");
-        builder.setHeader("Content-Length", ""+requestJsonString.length());
-        return new FutureAPIResponse(client.executeRequest(builder.build(), getHandler()));
-    }
-
-    /**
-     * Sends a synchronous create event request to the API.
-     *
-     * @param event an instance of {@link Event} that will be turned into a request
-     * @return event ID from the server
-     *
-     * @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 String createEvent(Event event)
-            throws ExecutionException, InterruptedException, IOException {
-        return createEvent(createEventAsFuture(event));
-    }
-
-    /**
-     * Synchronize a previously sent asynchronous create event request.
-     *
-     * @param response an instance of {@link FutureAPIResponse} returned from
-     * {@link #createEventAsFuture}
-     * @return event ID from the server
-     *
-     * @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 String createEvent(FutureAPIResponse response)
-            throws ExecutionException, InterruptedException, IOException {
-        int status = response.get().getStatus();
-        String message = response.get().getMessage();
-
-        if (status != BaseClient.HTTP_CREATED) {
-            throw new IOException(status + " " + message);
-        }
-        return ((JsonObject) parser.parse(message)).get("eventId").getAsString();
-    }
-
-    /**
-     * Sends an asynchronous create events (batch) request to the API.
-     *
-     * @param events a List of {@link Event} that will be turned into a request
-     */
-    public FutureAPIResponse createEventsAsFuture(List<Event> events) throws IOException {
-        RequestBuilder builder = new RequestBuilder("POST");
-        builder.setUrl(apiUrl + "/batch/events.json?accessKey=" + accessKey);
-
-        GsonBuilder gsonBuilder = new GsonBuilder();
-        gsonBuilder.registerTypeAdapter(DateTime.class, new DateTimeAdapter());
-        Gson gson = gsonBuilder.create();
-        String requestJsonString = gson.toJson(events);
-
-        builder.setBody(requestJsonString);
-        builder.setHeader("Content-Type","application/json");
-        builder.setHeader("Content-Length", ""+requestJsonString.length());
-        return new FutureAPIResponse(client.executeRequest(builder.build(), getHandler()));
-    }
-
-    /**
-     * Sends a synchronous create events (batch) request to the API.
-     *
-     * @param events a List of {@link Event} that will be turned into a request
-     * @return event ID from the server
-     *
-     * @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 List<String> createEvents(List<Event> event)
-            throws ExecutionException, InterruptedException, IOException {
-        return createEvents(createEventsAsFuture(event));
-    }
-
-    /**
-     * Synchronize a previously sent asynchronous create events (batch) request.
-     *
-     * @param response an instance of {@link FutureAPIResponse} returned from
-     * {@link #createEventAsFuture}
-     * @return List of event IDs from the server
-     *
-     * @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 List<String> createEvents(FutureAPIResponse response)
-            throws ExecutionException, InterruptedException, IOException {
-        int status = response.get().getStatus();
-        String message = response.get().getMessage();
-
-        if (status != BaseClient.HTTP_OK) {
-            throw new IOException(status + " " + message);
-        }
-       List<String> eventIds = new LinkedList<String>();
- 
-       for(JsonElement elem: (JsonArray)parser.parse(message) ){
-           eventIds.add(((JsonObject)elem).get("eventId").getAsString());
-       }
-       return eventIds;
-    }
-
-    /**
-     * Sends an asynchronous get event request to the API.
-     *
-     * @param eid ID of the event to get
-     */
-    public FutureAPIResponse getEventAsFuture(String eid) throws IOException {
-        Request request = (new RequestBuilder("GET"))
-            .setUrl(apiUrl + "/events/" + eid + ".json?accessKey=" + accessKey)
-            .build();
-        return new FutureAPIResponse(client.executeRequest(request, getHandler()));
-    }
-
-    /**
-     * Sends a synchronous get event request to the API.
-     *
-     * @param eid ID of the event to get
-     *
-     * @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 Event getEvent(String eid)
-            throws ExecutionException, InterruptedException, IOException {
-        return getEvent(getEventAsFuture(eid));
-    }
-
-    /**
-     * Synchronize a previously sent asynchronous get item request.
-     *
-     * @param response an instance of {@link FutureAPIResponse} returned from
-     * {@link #getEventAsFuture}
-     *
-     * @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 Event getEvent(FutureAPIResponse response)
-            throws ExecutionException, InterruptedException, IOException {
-        int status = response.get().getStatus();
-        String message = response.get().getMessage();
-
-        if (status == BaseClient.HTTP_OK) {
-            // handle DateTime separately
-            GsonBuilder gsonBuilder = new GsonBuilder();
-            gsonBuilder.registerTypeAdapter(DateTime.class, new DateTimeAdapter());
-            Gson gson = gsonBuilder.create();
-
-            return gson.fromJson(message, Event.class);
-        } else {
-            throw new IOException(message);
-        }
-    }
-
-    ////////////////////////////////////
-    //
-    //  helper methods for convenience
-    //
-    ////////////////////////////////////
-
-    /**
-     * Sends a set user properties request. Implicitly creates the user if it's not already there.
-     * Properties could be empty.
-     *
-     * @param uid ID of the user
-     * @param properties a map of all the properties to be associated with the user, could be empty
-     * @param eventTime timestamp of the event
-     * @return ID of this event
-     */
-    public FutureAPIResponse setUserAsFuture(String uid, Map<String, Object> properties,
-            DateTime eventTime) throws IOException {
-        return createEventAsFuture(new Event()
-            .event("$set")
-            .entityType("user")
-            .entityId(uid)
-            .eventTime(eventTime)
-            .properties(properties));
-    }
-
-    /**
-     * Sends a set user properties request. Same as
-     * {@link #setUserAsFuture(String, Map, DateTime)
-     * setUserAsFuture(String, Map&lt;String, Object&gt;, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public FutureAPIResponse setUserAsFuture(String uid, Map<String, Object> properties)
-            throws IOException {
-        return setUserAsFuture(uid, properties, new DateTime());
-    }
-
-    /**
-     * Sets properties of a user. Implicitly creates the user if it's not already there.
-     * Properties could be empty.
-     *
-     * @param uid ID of the user
-     * @param properties a map of all the properties to be associated with the user, could be empty
-     * @param eventTime timestamp of the event
-     * @return ID of this event
-     */
-    public String setUser(String uid, Map<String, Object> properties, DateTime eventTime)
-            throws ExecutionException, InterruptedException, IOException {
-        return createEvent(setUserAsFuture(uid, properties, eventTime));
-    }
-
-    /**
-     * Sets properties of a user. Same as {@link #setUser(String, Map, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public String setUser(String uid, Map<String, Object> properties)
-            throws ExecutionException, InterruptedException, IOException {
-        return setUser(uid, properties, new DateTime());
-    }
-
-    /**
-     * Sends an unset user properties request. The list must not be empty.
-     *
-     * @param uid ID of the user
-     * @param properties a list of all the properties to unset
-     * @param eventTime timestamp of the event
-     */
-    public FutureAPIResponse unsetUserAsFuture(String uid, List<String> properties,
-            DateTime eventTime) throws IOException {
-        if (properties.isEmpty()) {
-            throw new IllegalStateException("property list cannot be empty");
-        }
-        // converts the list into a map (to empty string) before creating the event object
-        Map<String, Object> propertiesMap = Maps.newHashMap();
-        for (String property : properties) {
-            propertiesMap.put(property, "");
-        }
-        return createEventAsFuture(new Event()
-            .event("$unset")
-            .entityType("user")
-            .entityId(uid)
-            .eventTime(eventTime)
-            .properties(propertiesMap));
-    }
-
-    /**
-     * Sends an unset user properties request. Same as
-     * {@link #unsetUserAsFuture(String, List, DateTime)
-     * unsetUserAsFuture(String, List&lt;String&gt;, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public FutureAPIResponse unsetUserAsFuture(String uid, List<String> properties)
-            throws IOException {
-        return unsetUserAsFuture(uid, properties, new DateTime());
-    }
-
-    /**
-     * Unsets properties of a user. The list must not be empty.
-     *
-     * @param uid ID of the user
-     * @param properties a list of all the properties to unset
-     * @param eventTime timestamp of the event
-     * @return ID of this event
-     */
-    public String unsetUser(String uid, List<String> properties, DateTime eventTime)
-            throws ExecutionException, InterruptedException, IOException {
-        return createEvent(unsetUserAsFuture(uid, properties, eventTime));
-    }
-
-    /**
-     * Unsets properties of a user. Same as {@link #unsetUser(String, List, DateTime)
-     * unsetUser(String, List&lt;String&gt;, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public String unsetUser(String uid, List<String> properties)
-            throws ExecutionException, InterruptedException, IOException {
-        return unsetUser(uid, properties, new DateTime());
-    }
-
-    /**
-     * Sends a delete user request.
-     *
-     * @param uid ID of the user
-     * @param eventTime timestamp of the event
-     */
-    public FutureAPIResponse deleteUserAsFuture(String uid, DateTime eventTime)
-            throws IOException {
-        return createEventAsFuture(new Event()
-            .event("$delete")
-            .entityType("user")
-            .entityId(uid)
-            .eventTime(eventTime));
-    }
-
-    /**
-     * Sends a delete user request. Event time is recorded as the time when the function is called.
-     *
-     * @param uid ID of the user
-     */
-    public FutureAPIResponse deleteUserAsFuture(String uid)
-            throws IOException {
-        return deleteUserAsFuture(uid, new DateTime());
-    }
-
-    /**
-     * Deletes a user.
-     *
-     * @param uid ID of the user
-     * @param eventTime timestamp of the event
-     * @return ID of this event
-     */
-    public String deleteUser(String uid, DateTime eventTime)
-            throws ExecutionException, InterruptedException, IOException {
-        return createEvent(deleteUserAsFuture(uid, eventTime));
-    }
-
-    /**
-     * Deletes a user. Event time is recorded as the time when the function is called.
-     *
-     * @param uid ID of the user
-     * @return ID of this event
-     */
-    public String deleteUser(String uid)
-            throws ExecutionException, InterruptedException, IOException {
-        return deleteUser(uid, new DateTime());
-    }
-
-
-    /**
-     * Sends a set item properties request. Implicitly creates the item if it's not already there.
-     * Properties could be empty.
-     *
-     * @param iid ID of the item
-     * @param properties a map of all the properties to be associated with the item, could be empty
-     * @param eventTime timestamp of the event
-     * @return ID of this event
-     */
-    public FutureAPIResponse setItemAsFuture(String iid, Map<String, Object> properties,
-            DateTime eventTime) throws IOException {
-        return createEventAsFuture(new Event()
-            .event("$set")
-            .entityType("item")
-            .entityId(iid)
-            .eventTime(eventTime)
-            .properties(properties));
-    }
-
-    /**
-     * Sends a set item properties request. Same as
-     * {@link #setItemAsFuture(String, Map, DateTime)
-     * setItemAsFuture(String, Map&lt;String, Object&gt;, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public FutureAPIResponse setItemAsFuture(String iid, Map<String, Object> properties)
-            throws IOException {
-        return setItemAsFuture(iid, properties, new DateTime());
-    }
-
-    /**
-     * Sets properties of a item. Implicitly creates the item if it's not already there.
-     * Properties could be empty.
-     *
-     * @param iid ID of the item
-     * @param properties a map of all the properties to be associated with the item, could be empty
-     * @param eventTime timestamp of the event
-     * @return ID of this event
-     */
-    public String setItem(String iid, Map<String, Object> properties, DateTime eventTime)
-            throws ExecutionException, InterruptedException, IOException {
-        return createEvent(setItemAsFuture(iid, properties, eventTime));
-    }
-
-    /**
-     * Sets properties of a item. Same as {@link #setItem(String, Map, DateTime)
-     * setItem(String, Map&lt;String, Object&gt;, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public String setItem(String iid, Map<String, Object> properties)
-            throws ExecutionException, InterruptedException, IOException {
-        return setItem(iid, properties, new DateTime());
-    }
-
-    /**
-     * Sends an unset item properties request. The list must not be empty.
-     *
-     * @param iid ID of the item
-     * @param properties a list of all the properties to unset
-     * @param eventTime timestamp of the event
-     */
-    public FutureAPIResponse unsetItemAsFuture(String iid, List<String> properties,
-            DateTime eventTime) throws IOException {
-        if (properties.isEmpty()) {
-            throw new IllegalStateException("property list cannot be empty");
-        }
-        // converts the list into a map (to empty string) before creating the event object
-        Map<String, Object> propertiesMap = Maps.newHashMap();
-        for (String property : properties) {
-            propertiesMap.put(property, "");
-        }
-        return createEventAsFuture(new Event()
-            .event("$unset")
-            .entityType("item")
-            .entityId(iid)
-            .eventTime(eventTime)
-            .properties(propertiesMap));
-    }
-
-    /**
-     * Sends an unset item properties request. Same as
-     * {@link #unsetItemAsFuture(String, List, DateTime)
-     * unsetItemAsFuture(String, List&lt;String&gt;, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public FutureAPIResponse unsetItemAsFuture(String iid, List<String> properties)
-            throws IOException {
-        return unsetItemAsFuture(iid, properties, new DateTime());
-    }
-
-    /**
-     * Unsets properties of a item. The list must not be empty.
-     *
-     * @param iid ID of the item
-     * @param properties a list of all the properties to unset
-     * @param eventTime timestamp of the event
-     * @return ID of this event
-     */
-    public String unsetItem(String iid, List<String> properties, DateTime eventTime)
-            throws ExecutionException, InterruptedException, IOException {
-        return createEvent(unsetItemAsFuture(iid, properties, eventTime));
-    }
-
-    /**
-     * Unsets properties of a item. Same as {@link #unsetItem(String, List, DateTime)
-     * unsetItem(String, List&lt;String&gt;, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public String unsetItem(String iid, List<String> properties)
-            throws ExecutionException, InterruptedException, IOException {
-        return unsetItem(iid, properties, new DateTime());
-    }
-
-    /**
-     * Sends a delete item request.
-     *
-     * @param iid ID of the item
-     * @param eventTime timestamp of the event
-     */
-    public FutureAPIResponse deleteItemAsFuture(String iid, DateTime eventTime)
-            throws IOException {
-        return createEventAsFuture(new Event()
-            .event("$delete")
-            .entityType("item")
-            .entityId(iid)
-            .eventTime(eventTime));
-    }
-
-    /**
-     * Sends a delete item request. Event time is recorded as the time when the function is called.
-     *
-     * @param iid ID of the item
-     */
-    public FutureAPIResponse deleteItemAsFuture(String iid)
-            throws IOException {
-        return deleteItemAsFuture(iid, new DateTime());
-    }
-
-    /**
-     * Deletes a item.
-     *
-     * @param iid ID of the item
-     * @param eventTime timestamp of the event
-     * @return ID of this event
-     */
-    public String deleteItem(String iid, DateTime eventTime)
-            throws ExecutionException, InterruptedException, IOException {
-        return createEvent(deleteItemAsFuture(iid, eventTime));
-    }
-
-    /**
-     * Deletes a item. Event time is recorded as the time when the function is called.
-     *
-     * @param iid ID of the item
-     * @return ID of this event
-     */
-    public String deleteItem(String iid)
-            throws ExecutionException, InterruptedException, IOException {
-        return deleteItem(iid, new DateTime());
-    }
-
-    /**
-     * Sends a user-action-on-item request.
-     *
-     * @param action name of the action performed
-     * @param uid ID of the user
-     * @param iid ID of the item
-     * @param properties a map of properties associated with this action
-     * @param eventTime timestamp of the event
-     */
-    public FutureAPIResponse userActionItemAsFuture(String action, String uid, String iid,
-            Map<String, Object> properties, DateTime eventTime) throws IOException {
-        return createEventAsFuture(new Event()
-            .event(action)
-            .entityType("user")
-            .entityId(uid)
-            .targetEntityType("item")
-            .targetEntityId(iid)
-            .properties(properties)
-            .eventTime(eventTime));
-    }
-
-    /**
-     * Sends a user-action-on-item request. Similar to
-     * {@link #userActionItemAsFuture(String, String, String, Map, DateTime)
-     * #userActionItemAsFuture(String, String, String, Map&lt;String, Object\gt;, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public FutureAPIResponse userActionItemAsFuture(String action, String uid, String iid,
-            Map<String, Object> properties) throws IOException {
-        return userActionItemAsFuture(action, uid, iid, properties, new DateTime());
-    }
-
-    /**
-     * Records a user-action-on-item event.
-     *
-     * @param action name of the action performed
-     * @param uid ID of the user
-     * @param iid ID of the item
-     * @param properties a map of properties associated with this action
-     * @param eventTime timestamp of the event
-     * @return ID of this event
-     */
-    public String userActionItem(String action, String uid, String iid,
-            Map<String, Object> properties, DateTime eventTime)
-            throws ExecutionException, InterruptedException, IOException {
-        return createEvent(userActionItemAsFuture(action, uid, iid, properties, eventTime));
-    }
-
-    /**
-     * Records a user-action-on-item event. Similar to
-     * {@link #userActionItem(String, String, String, Map, DateTime)
-     * userActionItem(String, String, String, Map&lt;String, Object&gt;, DateTime)}
-     * except event time is not specified and recorded as the time when the function is called.
-     */
-    public String userActionItem(String action, String uid, String iid,
-            Map<String, Object> properties)
-            throws ExecutionException, InterruptedException, IOException {
-        return userActionItem(action, uid, iid, properties, new DateTime());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/io/prediction/FileExporter.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/io/prediction/FileExporter.java b/client/src/main/java/io/prediction/FileExporter.java
deleted file mode 100644
index 7919ee9..0000000
--- a/client/src/main/java/io/prediction/FileExporter.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package io.prediction;
-
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Map;
-import org.joda.time.DateTime;
-
-public class FileExporter {
-
-    private FileOutputStream out;
-
-    public FileExporter(String pathname) throws FileNotFoundException {
-        out = new FileOutputStream(pathname);
-    }
-
-    /**
-     * Create and write a json-encoded event to the underlying file.
-     *
-     * @param eventName        Name of the event.
-     * @param entityType       The entity type.
-     * @param entityId         The entity ID.
-     * @param targetEntityType The target entity type (optional).
-     * @param targetEntityId   The target entity ID (optional).
-     * @param properties       Properties (optional).
-     * @param eventTime        The time of the event (optional).
-     * @throws IOException
-     */
-    public void createEvent(String eventName, String entityType, String entityId,
-                            String targetEntityType, String targetEntityId, Map<String, Object> properties,
-                            DateTime eventTime) throws IOException {
-
-        if (eventTime == null) {
-            eventTime = new DateTime();
-        }
-
-        Event event = new Event()
-                .event(eventName)
-                .entityType(entityType)
-                .entityId(entityId)
-                .eventTime(eventTime);
-
-        if (targetEntityType != null) {
-            event.targetEntityType(targetEntityType);
-        }
-
-        if (targetEntityId != null) {
-            event.targetEntityId(targetEntityId);
-        }
-
-        if (properties != null) {
-            event.properties(properties);
-        }
-
-        out.write(event.toJsonString().getBytes("UTF8"));
-        out.write('\n');
-    }
-
-    public void close() throws IOException {
-        out.close();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/io/prediction/FutureAPIResponse.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/io/prediction/FutureAPIResponse.java b/client/src/main/java/io/prediction/FutureAPIResponse.java
deleted file mode 100644
index cdd48c6..0000000
--- a/client/src/main/java/io/prediction/FutureAPIResponse.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package io.prediction;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.ning.http.client.extra.ListenableFutureAdapter;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/**
- * APIResponse as a listenable future.
- *
- * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- * @version 0.8.3
- * @since 0.2
- */
-
-public class FutureAPIResponse implements ListenableFuture<APIResponse> {
-
-    private ListenableFuture<APIResponse> apiResponse;
-
-    public FutureAPIResponse(com.ning.http.client.ListenableFuture<APIResponse> apiResponse) {
-        this.apiResponse = ListenableFutureAdapter.asGuavaFuture(apiResponse);
-    }
-
-    // implements ListenableFuture<APIResponse>
-
-    public void addListener(Runnable listener, Executor executor) {
-        this.apiResponse.addListener(listener, executor);
-    }
-
-    // implements Future<APIResponse>
-
-    public boolean cancel(boolean mayInterruptIfRunning) {
-        return this.apiResponse.cancel(mayInterruptIfRunning);
-    }
-
-    public APIResponse get() throws ExecutionException, InterruptedException {
-        return this.apiResponse.get();
-    }
-
-    public APIResponse get(long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException {
-        return this.apiResponse.get(timeout, unit);
-    }
-
-    public boolean isCancelled() {
-        return this.apiResponse.isCancelled();
-    }
-
-    public boolean isDone() {
-        return this.apiResponse.isDone();
-    }
-
-    public ListenableFuture<APIResponse> getAPIResponse() {
-        // get the underlying APIResponse
-        return this.apiResponse;
-    }
-
-    public int getStatus() {
-        try {
-            return this.apiResponse.get().getStatus();
-        } catch (InterruptedException e) {
-            return 0;
-        } catch (ExecutionException e) {
-            return 0;
-        }
-    }
-
-    public String getMessage() {
-        try {
-            return this.apiResponse.get().getMessage();
-        } catch (InterruptedException e) {
-            return e.getMessage();
-        } catch (ExecutionException e) {
-            return e.getMessage();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/io/prediction/package-info.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/io/prediction/package-info.java b/client/src/main/java/io/prediction/package-info.java
deleted file mode 100644
index eafd022..0000000
--- a/client/src/main/java/io/prediction/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * This package contains classes that provide convenient access of the PredictionIO RESTful API.
- *
- * To create an app and perform predictions, please download the PredictionIO suite from http://prediction.io.
- *
- * Most functionality is provided by the DataClient and EngineClient class.
- *
- * @author The PredictionIO Team (<a href="http://prediction.io">http://prediction.io</a>)
- */
-package io.prediction;

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/org/apache/predictionio/sdk/java/APIResponse.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/predictionio/sdk/java/APIResponse.java b/client/src/main/java/org/apache/predictionio/sdk/java/APIResponse.java
new file mode 100644
index 0000000..bb14613
--- /dev/null
+++ b/client/src/main/java/org/apache/predictionio/sdk/java/APIResponse.java
@@ -0,0 +1,52 @@
+/*
+ * 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.predictionio.sdk.java;
+
+/**
+ * API Response class for wrapping responses.
+ *
+ * @version 0.8.3
+ * @since 0.2
+ */
+
+public class APIResponse {
+
+  private int status;
+  private String message;
+
+  public APIResponse(int status, String message) {
+    this.status = status;
+    this.message = message;
+  }
+
+  public int getStatus() {
+    return this.status;
+  }
+
+  public void setStatus(int status) {
+    this.status = status;
+  }
+
+  public String getMessage() {
+    return this.message;
+  }
+
+  public void setMessage(String message) {
+    this.message = message;
+  }
+}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/org/apache/predictionio/sdk/java/BaseClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/predictionio/sdk/java/BaseClient.java b/client/src/main/java/org/apache/predictionio/sdk/java/BaseClient.java
new file mode 100644
index 0000000..7737bec
--- /dev/null
+++ b/client/src/main/java/org/apache/predictionio/sdk/java/BaseClient.java
@@ -0,0 +1,151 @@
+/*
+ * 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.predictionio.sdk.java;
+
+import com.google.gson.JsonParser;
+import com.ning.http.client.AsyncHandler;
+import com.ning.http.client.AsyncHttpClient;
+import com.ning.http.client.AsyncHttpClientConfig;
+import com.ning.http.client.HttpResponseBodyPart;
+import com.ning.http.client.HttpResponseHeaders;
+import com.ning.http.client.HttpResponseStatus;
+import com.ning.http.client.Response;
+import com.ning.http.client.extra.ThrottleRequestFilter;
+import com.ning.http.client.providers.netty.NettyAsyncHttpProvider;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * BaseClient contains code common to both {@link EventClient} and {@link EngineClient}.
+ *
+ * @version 0.8.3
+ * @since 0.1
+ */
+public abstract class BaseClient implements Closeable {
+
+  private static final int defaultThreadLimit = 1;
+  private static final int defaultQSize = 0;
+  private static final int defaultTimeout = 5;
+
+  // HTTP status code
+  static final int HTTP_OK = 200;
+  static final int HTTP_CREATED = 201;
+
+  // API Url
+  final String apiUrl;
+
+  final AsyncHttpClient client;
+
+  final JsonParser parser = new JsonParser();
+
+  /**
+   * @param apiUrl the URL of the PredictionIO API
+   */
+  public BaseClient(String apiUrl) {
+    this(apiUrl, BaseClient.defaultThreadLimit);
+  }
+
+  /**
+   * @param apiUrl the URL of the PredictionIO API
+   * @param threadLimit maximum number of simultaneous threads (connections) to the API
+   */
+  public BaseClient(String apiUrl, int threadLimit) {
+    this(apiUrl, threadLimit, defaultQSize);
+  }
+
+  /**
+   * @param apiUrl the URL of the PredictionIO API
+   * @param threadLimit maximum number of simultaneous threads (connections) to the API
+   * @param queueSize size of the queue
+   */
+  public BaseClient(String apiUrl, int threadLimit, int queueSize) {
+    this(apiUrl, threadLimit, queueSize, defaultTimeout);
+  }
+
+  /**
+   * @param apiUrl the URL of the PredictionIO API
+   * @param threadLimit maximum number of simultaneous threads (connections) to the API
+   * @param queueSize size of the queue
+   * @param timeout timeout in seconds for the connections
+   */
+  public BaseClient(String apiUrl, int threadLimit, int queueSize, int timeout) {
+    this.apiUrl = apiUrl;
+    // Async HTTP client config
+    AsyncHttpClientConfig config = (new AsyncHttpClientConfig.Builder())
+        .setAllowPoolingConnections(true)
+        .setAllowPoolingSslConnections(true)
+        .addRequestFilter(new ThrottleRequestFilter(threadLimit))
+        .setMaxConnectionsPerHost(threadLimit)
+        .setRequestTimeout(timeout * 1000)
+        .setIOThreadMultiplier(threadLimit)
+        .build();
+    this.client = new AsyncHttpClient(new NettyAsyncHttpProvider(config), config);
+  }
+
+  /**
+   * Close all connections associated with this client. It is a good practice to always close the
+   * client after use.
+   */
+  @Override
+  public void close() {
+    client.close();
+  }
+
+  AsyncHandler<APIResponse> getHandler() {
+    return new AsyncHandler<APIResponse>() {
+      private final Response.ResponseBuilder builder = new Response.ResponseBuilder();
+
+      public void onThrowable(Throwable throwable) {
+      }
+
+      public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception {
+        builder.accumulate(content);
+        return STATE.CONTINUE;
+      }
+
+      public STATE onStatusReceived(HttpResponseStatus status) throws Exception {
+        builder.accumulate(status);
+        return STATE.CONTINUE;
+      }
+
+      public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception {
+        builder.accumulate(headers);
+        return STATE.CONTINUE;
+      }
+
+      public APIResponse onCompleted() throws Exception {
+        Response response = builder.build();
+        return new APIResponse(response.getStatusCode(), response.getResponseBody());
+      }
+    };
+  }
+
+  /**
+   * Get status of the API.
+   *
+   * @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 String getStatus() throws ExecutionException, InterruptedException, IOException {
+    return (new FutureAPIResponse(client.prepareGet(apiUrl).execute(getHandler()))).get()
+        .getMessage();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/org/apache/predictionio/sdk/java/DateTimeAdapter.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/predictionio/sdk/java/DateTimeAdapter.java b/client/src/main/java/org/apache/predictionio/sdk/java/DateTimeAdapter.java
new file mode 100644
index 0000000..76f1249
--- /dev/null
+++ b/client/src/main/java/org/apache/predictionio/sdk/java/DateTimeAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * 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.predictionio.sdk.java;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import java.lang.reflect.Type;
+import org.joda.time.DateTime;
+
+/**
+ * DateTimeAdapter turns a String in ISO 8601 format into a DateTime object, and vice versa.
+ *
+ * @version 0.8.3
+ * @since 0.8.0
+ */
+public class DateTimeAdapter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {
+
+  @Override
+  public JsonElement serialize(DateTime src, Type type, JsonSerializationContext context) {
+    return new JsonPrimitive(src.toString());
+  }
+
+  @Override
+  public DateTime deserialize(final JsonElement json, final Type type,
+      final JsonDeserializationContext context) throws JsonParseException {
+    return new DateTime(json.getAsJsonPrimitive().getAsString());
+  }
+}