Repository: predictionio-sdk-java
Updated Branches:
  refs/heads/develop 2747475a0 -> 0780fcd55


http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/org/apache/predictionio/sdk/java/EngineClient.java
----------------------------------------------------------------------
diff --git 
a/client/src/main/java/org/apache/predictionio/sdk/java/EngineClient.java 
b/client/src/main/java/org/apache/predictionio/sdk/java/EngineClient.java
new file mode 100644
index 0000000..5534a7d
--- /dev/null
+++ b/client/src/main/java/org/apache/predictionio/sdk/java/EngineClient.java
@@ -0,0 +1,135 @@
+/*
+ * 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.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import com.ning.http.client.RequestBuilder;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import org.joda.time.DateTime;
+
+/**
+ * EngineClient contains generic methods sendQuery() and sendQueryAsFuture() 
for sending queries.
+ *
+ * @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 queueSize size of the queue
+   */
+  public EngineClient(String engineUrl, int threadLimit, int queueSize) {
+    super(engineUrl, threadLimit, queueSize);
+  }
+
+  /**
+   * 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 queueSize size of the queue
+   * @param timeout timeout in seconds for the connections
+   */
+  public EngineClient(String engineUrl, int threadLimit, int queueSize, int 
timeout) {
+    super(engineUrl, threadLimit, queueSize, 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 != 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/org/apache/predictionio/sdk/java/Event.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/predictionio/sdk/java/Event.java 
b/client/src/main/java/org/apache/predictionio/sdk/java/Event.java
new file mode 100644
index 0000000..9fe29db
--- /dev/null
+++ b/client/src/main/java/org/apache/predictionio/sdk/java/Event.java
@@ -0,0 +1,166 @@
+/*
+ * 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.common.collect.Maps;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import java.util.Map;
+import org.joda.time.DateTime;
+
+/**
+ * Event class for PredictionIO Event objects.
+ *
+ * @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/org/apache/predictionio/sdk/java/EventClient.java
----------------------------------------------------------------------
diff --git 
a/client/src/main/java/org/apache/predictionio/sdk/java/EventClient.java 
b/client/src/main/java/org/apache/predictionio/sdk/java/EventClient.java
new file mode 100644
index 0000000..b1e93ba
--- /dev/null
+++ b/client/src/main/java/org/apache/predictionio/sdk/java/EventClient.java
@@ -0,0 +1,663 @@
+/*
+ * 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.common.collect.Maps;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.ning.http.client.Request;
+import com.ning.http.client.RequestBuilder;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import org.joda.time.DateTime;
+
+/**
+ * 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>.
+ *
+ * @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 queueSize size of the queue
+   */
+  public EventClient(String accessKey, String eventUrl, int threadLimit, int 
queueSize) {
+    super(eventUrl, threadLimit, queueSize);
+    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 queueSize size of the queue
+   * @param timeout timeout in seconds for the connections
+   */
+  public EventClient(String accessKey, String eventUrl, int threadLimit, int 
queueSize,
+      int timeout) {
+    super(eventUrl, threadLimit, queueSize, 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 != 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> events)
+      throws ExecutionException, InterruptedException, IOException {
+    return createEvents(createEventsAsFuture(events));
+  }
+
+  /**
+   * 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 != 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 == 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/org/apache/predictionio/sdk/java/FileExporter.java
----------------------------------------------------------------------
diff --git 
a/client/src/main/java/org/apache/predictionio/sdk/java/FileExporter.java 
b/client/src/main/java/org/apache/predictionio/sdk/java/FileExporter.java
new file mode 100644
index 0000000..e309d01
--- /dev/null
+++ b/client/src/main/java/org/apache/predictionio/sdk/java/FileExporter.java
@@ -0,0 +1,80 @@
+/*
+ * 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 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).
+   */
+  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/org/apache/predictionio/sdk/java/FutureAPIResponse.java
----------------------------------------------------------------------
diff --git 
a/client/src/main/java/org/apache/predictionio/sdk/java/FutureAPIResponse.java 
b/client/src/main/java/org/apache/predictionio/sdk/java/FutureAPIResponse.java
new file mode 100644
index 0000000..cd6cb56
--- /dev/null
+++ 
b/client/src/main/java/org/apache/predictionio/sdk/java/FutureAPIResponse.java
@@ -0,0 +1,91 @@
+/*
+ * 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.common.util.concurrent.ListenableFuture;
+import com.ning.http.client.extra.ListenableFutureAdapter;
+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.
+ *
+ * @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 | ExecutionException e) {
+      return 0;
+    }
+  }
+
+  public String getMessage() {
+    try {
+      return this.apiResponse.get().getMessage();
+    } catch (InterruptedException | ExecutionException e) {
+      return e.getMessage();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/main/java/org/apache/predictionio/sdk/java/package-info.java
----------------------------------------------------------------------
diff --git 
a/client/src/main/java/org/apache/predictionio/sdk/java/package-info.java 
b/client/src/main/java/org/apache/predictionio/sdk/java/package-info.java
new file mode 100644
index 0000000..1b2bd67
--- /dev/null
+++ b/client/src/main/java/org/apache/predictionio/sdk/java/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains classes that provide convenient access of Apache 
PredictionIO RESTful API.
+ *
+ * To create an app and perform predictions, please download Apache 
PredictionIO from
+ * <a href="http://predictionio.apache.org"; 
target="_blank">http://predictionio.apache.org</a>.
+ *
+ * Most functionality is provided by the {@link 
org.apache.predictionio.sdk.java.EventClient} and
+ * {@link org.apache.predictionio.sdk.java.EngineClient} class.
+ */
+package org.apache.predictionio.sdk.java;

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/test/java/io/prediction/FileExporterTest.java
----------------------------------------------------------------------
diff --git a/client/src/test/java/io/prediction/FileExporterTest.java 
b/client/src/test/java/io/prediction/FileExporterTest.java
deleted file mode 100644
index a5c7759..0000000
--- a/client/src/test/java/io/prediction/FileExporterTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package io.prediction;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import org.joda.time.DateTime;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import static org.junit.Assert.*;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-public class FileExporterTest {
-
-    @Rule
-    public TemporaryFolder folder = new TemporaryFolder();
-
-    @Test
-    public void testIt() throws IOException {
-
-        String pathname = folder.getRoot().getCanonicalPath() + "/testIt.out";
-
-        FileExporter exporter = new FileExporter(pathname);
-
-        Map<String, Object> properties = new HashMap<>();
-        properties.put("birthday", new DateTime("1758-05-06T00:00:00+00:00"));
-
-        DateTime then = new DateTime("1794-07-27T00:00:00+00:00");
-
-        exporter.createEvent("event-1", "entity-type-1", "entity-id-1",
-                null, null, null, null);
-
-        exporter.createEvent("event-2", "entity-type-2", "entity-id-2",
-                "target-entity-type-2", null, null, null);
-
-        exporter.createEvent("event-3", "entity-type-3", "entity-id-3",
-                null, "target-entity-id-3", null, null);
-
-        exporter.createEvent("event-4", "entity-type-4", "entity-id-4",
-                null, null, properties, then);
-
-        exporter.createEvent("event-5", "entity-type-5", "entity-id-5",
-                "target-entity-type-5", "target-entity-id-5", properties, 
then);
-
-        exporter.close();
-
-        File out = new File(pathname);
-        assertTrue(pathname + " exists", out.exists());
-
-        BufferedReader reader = new BufferedReader(new FileReader(pathname));
-
-        GsonBuilder gsonBuilder = new GsonBuilder();
-        gsonBuilder.registerTypeAdapter(DateTime.class, new DateTimeAdapter());
-        Gson gson = gsonBuilder.create();
-
-        String json1 = reader.readLine();
-        Event event1 = gson.fromJson(json1, Event.class);
-        assertEquals("event-1", event1.getEvent());
-        assertEquals("entity-type-1", event1.getEntityType());
-        assertEquals("entity-id-1", event1.getEntityId());
-        assertNull(event1.getTargetEntityType());
-        assertNull(event1.getTargetEntityId());
-        assertTrue(event1.getProperties().isEmpty());
-        assertEquals(new DateTime().getMillis(), 
event1.getEventTime().getMillis(), 1000);
-
-        String json2 = reader.readLine();
-        Event event2 = gson.fromJson(json2, Event.class);
-        assertEquals("event-2", event2.getEvent());
-        assertEquals("entity-type-2", event2.getEntityType());
-        assertEquals("entity-id-2", event2.getEntityId());
-        assertEquals("target-entity-type-2", event2.getTargetEntityType());
-        assertNull(event2.getTargetEntityId());
-        assertTrue(event2.getProperties().isEmpty());
-        assertEquals(new DateTime().getMillis(), 
event2.getEventTime().getMillis(), 1000);
-
-        String json3 = reader.readLine();
-        Event event3 = gson.fromJson(json3, Event.class);
-        assertEquals("event-3", event3.getEvent());
-        assertEquals("entity-type-3", event3.getEntityType());
-        assertEquals("entity-id-3", event3.getEntityId());
-        assertNull(event3.getTargetEntityType());
-        assertEquals("target-entity-id-3", event3.getTargetEntityId());
-        assertTrue(event3.getProperties().isEmpty());
-        assertEquals(new DateTime().getMillis(), 
event3.getEventTime().getMillis(), 1000);
-
-        String json4 = reader.readLine();
-        Event event4 = gson.fromJson(json4, Event.class);
-        assertEquals("event-4", event4.getEvent());
-        assertEquals("entity-type-4", event4.getEntityType());
-        assertEquals("entity-id-4", event4.getEntityId());
-        assertNull(event4.getTargetEntityType());
-        assertNull(event4.getTargetEntityId());
-        assertEquals(1, event4.getProperties().size());
-        assertEquals(properties.get("birthday"), new 
DateTime(event4.getProperties().get("birthday")));
-        assertEquals(then.getMillis(), event4.getEventTime().getMillis());
-
-        String json5 = reader.readLine();
-        Event event5 = gson.fromJson(json5, Event.class);
-        assertEquals("event-5", event5.getEvent());
-        assertEquals("entity-type-5", event5.getEntityType());
-        assertEquals("entity-id-5", event5.getEntityId());
-        assertEquals("target-entity-type-5", event5.getTargetEntityType());
-        assertEquals("target-entity-id-5", event5.getTargetEntityId());
-        assertEquals(1, event5.getProperties().size());
-        assertEquals(properties.get("birthday"), new 
DateTime(event5.getProperties().get("birthday")));
-        assertEquals(then.getMillis(), event4.getEventTime().getMillis());
-
-        String empty = reader.readLine();
-        assertNull("no more data", empty);
-    }
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/client/src/test/java/org/apache/predictionio/sdk/java/FileExporterTest.java
----------------------------------------------------------------------
diff --git 
a/client/src/test/java/org/apache/predictionio/sdk/java/FileExporterTest.java 
b/client/src/test/java/org/apache/predictionio/sdk/java/FileExporterTest.java
new file mode 100644
index 0000000..076332c
--- /dev/null
+++ 
b/client/src/test/java/org/apache/predictionio/sdk/java/FileExporterTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import org.joda.time.DateTime;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class FileExporterTest {
+
+  @Rule
+  public TemporaryFolder folder = new TemporaryFolder();
+
+  @Test
+  public void testIt() throws IOException {
+
+    String pathname = folder.getRoot().getCanonicalPath() + "/testIt.out";
+
+    FileExporter exporter = new FileExporter(pathname);
+
+    Map<String, Object> properties = new HashMap<>();
+    properties.put("birthday", new DateTime("1758-05-06T00:00:00+00:00"));
+
+    DateTime then = new DateTime("1794-07-27T00:00:00+00:00");
+
+    exporter.createEvent("event-1", "entity-type-1", "entity-id-1",
+        null, null, null, null);
+
+    exporter.createEvent("event-2", "entity-type-2", "entity-id-2",
+        "target-entity-type-2", null, null, null);
+
+    exporter.createEvent("event-3", "entity-type-3", "entity-id-3",
+        null, "target-entity-id-3", null, null);
+
+    exporter.createEvent("event-4", "entity-type-4", "entity-id-4",
+        null, null, properties, then);
+
+    exporter.createEvent("event-5", "entity-type-5", "entity-id-5",
+        "target-entity-type-5", "target-entity-id-5", properties, then);
+
+    exporter.close();
+
+    File out = new File(pathname);
+    assertTrue(pathname + " exists", out.exists());
+
+    BufferedReader reader = new BufferedReader(new FileReader(pathname));
+
+    GsonBuilder gsonBuilder = new GsonBuilder();
+    gsonBuilder.registerTypeAdapter(DateTime.class, new DateTimeAdapter());
+    Gson gson = gsonBuilder.create();
+
+    String json1 = reader.readLine();
+    Event event1 = gson.fromJson(json1, Event.class);
+    assertEquals("event-1", event1.getEvent());
+    assertEquals("entity-type-1", event1.getEntityType());
+    assertEquals("entity-id-1", event1.getEntityId());
+    assertNull(event1.getTargetEntityType());
+    assertNull(event1.getTargetEntityId());
+    assertTrue(event1.getProperties().isEmpty());
+    assertEquals(new DateTime().getMillis(), 
event1.getEventTime().getMillis(), 1000);
+
+    String json2 = reader.readLine();
+    Event event2 = gson.fromJson(json2, Event.class);
+    assertEquals("event-2", event2.getEvent());
+    assertEquals("entity-type-2", event2.getEntityType());
+    assertEquals("entity-id-2", event2.getEntityId());
+    assertEquals("target-entity-type-2", event2.getTargetEntityType());
+    assertNull(event2.getTargetEntityId());
+    assertTrue(event2.getProperties().isEmpty());
+    assertEquals(new DateTime().getMillis(), 
event2.getEventTime().getMillis(), 1000);
+
+    String json3 = reader.readLine();
+    Event event3 = gson.fromJson(json3, Event.class);
+    assertEquals("event-3", event3.getEvent());
+    assertEquals("entity-type-3", event3.getEntityType());
+    assertEquals("entity-id-3", event3.getEntityId());
+    assertNull(event3.getTargetEntityType());
+    assertEquals("target-entity-id-3", event3.getTargetEntityId());
+    assertTrue(event3.getProperties().isEmpty());
+    assertEquals(new DateTime().getMillis(), 
event3.getEventTime().getMillis(), 1000);
+
+    String json4 = reader.readLine();
+    Event event4 = gson.fromJson(json4, Event.class);
+    assertEquals("event-4", event4.getEvent());
+    assertEquals("entity-type-4", event4.getEntityType());
+    assertEquals("entity-id-4", event4.getEntityId());
+    assertNull(event4.getTargetEntityType());
+    assertNull(event4.getTargetEntityId());
+    assertEquals(1, event4.getProperties().size());
+    assertEquals(properties.get("birthday"), new 
DateTime(event4.getProperties().get("birthday")));
+    assertEquals(then.getMillis(), event4.getEventTime().getMillis());
+
+    String json5 = reader.readLine();
+    Event event5 = gson.fromJson(json5, Event.class);
+    assertEquals("event-5", event5.getEvent());
+    assertEquals("entity-type-5", event5.getEntityType());
+    assertEquals("entity-id-5", event5.getEntityId());
+    assertEquals("target-entity-type-5", event5.getTargetEntityType());
+    assertEquals("target-entity-id-5", event5.getTargetEntityId());
+    assertEquals(1, event5.getProperties().size());
+    assertEquals(properties.get("birthday"), new 
DateTime(event5.getProperties().get("birthday")));
+    assertEquals(then.getMillis(), event4.getEventTime().getMillis());
+
+    String empty = reader.readLine();
+    assertNull("no more data", empty);
+  }
+}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/examples/import/pom.xml
----------------------------------------------------------------------
diff --git a/examples/import/pom.xml b/examples/import/pom.xml
index fef7ec1..5694070 100644
--- a/examples/import/pom.xml
+++ b/examples/import/pom.xml
@@ -1,17 +1,32 @@
+<!--
+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>
-    <groupId>io.prediction.samples</groupId>
+    <groupId>org.apache.predictionio.samples</groupId>
     <artifactId>sample-import</artifactId>
-    <version>0.9.5</version>
+    <version>0.13.0</version>
     <packaging>jar</packaging>
     <name>PredictionIO Java SDK Examples: Import</name>
 
     <dependencies>
         <dependency>
-            <groupId>io.prediction</groupId>
+            <groupId>org.apache.predictionio</groupId>
             <artifactId>client</artifactId>
-            <version>0.9.5</version>
+            <version>0.13.0</version>
         </dependency>
     </dependencies>
 
@@ -52,7 +67,7 @@
                 <configuration>
                     <archive>
                         <manifest>
-                            
<mainClass>io.prediction.samples.SampleImport</mainClass>
+                            
<mainClass>org.apache.predictionio.samples.SampleImport</mainClass>
                         </manifest>
                     </archive>
                     <descriptorRefs>

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/examples/import/src/main/java/io/prediction/samples/SampleImport.java
----------------------------------------------------------------------
diff --git 
a/examples/import/src/main/java/io/prediction/samples/SampleImport.java 
b/examples/import/src/main/java/io/prediction/samples/SampleImport.java
deleted file mode 100644
index f4a3eec..0000000
--- a/examples/import/src/main/java/io/prediction/samples/SampleImport.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package io.prediction.samples;
-
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
-import io.prediction.APIResponse;
-import io.prediction.EventClient;
-import io.prediction.FutureAPIResponse;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.TreeSet;
-import java.util.concurrent.ExecutionException;
-
-/**
- * Sample data import client using MovieLens data set.
- *
- * @author Cong Qin, Donald Szeto, Tom Chan
- */
-public class SampleImport {
-    private static final int HTTP_CREATED = 201;
-
-    public static void main(String[] args) {
-       /* set appurl to your API server */
-        String appurl = "http://localhost:7070";;
-        /* Handle command line arguments */
-        String accessKey = null;
-        String inputFile = null;
-        try {
-            accessKey = args[0];
-            inputFile = args[1];
-        } catch (ArrayIndexOutOfBoundsException e) {
-            System.err.println("You must provide access key (1st arg) and 
input file name (2nd arg)");
-            System.exit(1);
-        }
-
-        EventClient client = null;
-        Reader fileReader = null;
-
-        /* Read input MovieLens data and send requests to API */
-        List<FutureAPIResponse> listOfFutures = new ArrayList<>(); // keeping 
track of requests
-        try {
-            /* Create a client with the access key */
-            client = new EventClient(accessKey, appurl);
-
-            /* Data structure */
-            Set<String> uids = new TreeSet<String>();
-            Set<String> iids = new TreeSet<String>();
-
-            /* Get API status */
-            System.out.println(client.getStatus());
-
-            /* Open data file for reading */
-            fileReader = new FileReader(inputFile);
-            BufferedReader reader = new BufferedReader(fileReader);
-
-            /* Some local variables */
-            String line;
-            int i = 0;
-            FutureAPIResponse future;
-            Map<String, Object> userProperties = new HashMap<>(); // empty 
properties for user
-
-            while ((line = reader.readLine()) != null) {
-                /* Break the line up */
-                StringTokenizer st = new StringTokenizer(line);
-
-                /* The 1st field is User ID, the 2nd field is Item ID, and the 
3rd field is rating */
-                String uid = st.nextToken();
-                String iid = st.nextToken();
-                int rate = Integer.parseInt(st.nextToken());
-
-                /* Add user and item if they are not seen before */
-                if (uids.add(uid)) {
-                    // event time is omitted since we're not using it
-                    future = client.setUserAsFuture(uid, userProperties);
-                    listOfFutures.add(future);
-                    Futures.addCallback(future.getAPIResponse(), 
getFutureCallback("user " + uid));
-                }
-                if (iids.add(iid)) {
-                    Map<String, Object> itemProperties = new HashMap<>();
-                    List<String> genre = new ArrayList<>();
-                    genre.add("comedy");
-                    itemProperties.put("genre", genre);
-                    future = client.setItemAsFuture(iid, itemProperties);
-                    listOfFutures.add(future);
-                    Futures.addCallback(future.getAPIResponse(), 
getFutureCallback("item " + iid));
-                }
-
-                /* User rates the movie. We do this asynchronously */
-                Map<String, Object> properties = new HashMap<>(); // 
properties with rating
-                properties.put("rating", rate);
-                future = client.userActionItemAsFuture("rate", uid, iid, 
properties);
-                listOfFutures.add(future);
-                Futures.addCallback(future.getAPIResponse(), 
getFutureCallback("event " + uid + " rates " + iid + " with " + rate));
-            }
-        } catch (Exception e) {
-            System.err.println("Error: " + e.getMessage());
-            e.printStackTrace();
-        } finally {
-            if (fileReader != null) {
-                try {
-                    fileReader.close();
-                } catch (IOException e) {
-                    System.err.println("Error: " + e.getMessage());
-                }
-            }
-            // wait for the import result
-            ListenableFuture<List<APIResponse>> futures = 
Futures.allAsList(listOfFutures);
-            try {
-              List<APIResponse> responses = futures.get();
-              for (APIResponse response : responses) {
-                  if (response.getStatus() != HTTP_CREATED) {
-                      System.err.println("Error importing some record, first 
error message is: "
-                          + response.getMessage());
-                      // only print the first error
-                      break;
-                  }
-              }
-            } catch (InterruptedException | ExecutionException e) {
-              System.err.println("Error importing some record, error message: 
" + e.getStackTrace());
-            }
-            if (client != null) {
-                client.close();
-            }
-        }
-    }
-
-    private static FutureCallback<APIResponse> getFutureCallback(final String 
name) {
-        return new FutureCallback<APIResponse>() {
-            public void onSuccess(APIResponse response) {
-                System.out.println(name + " added: " + response.getMessage());
-            }
-            public void onFailure(Throwable thrown) {
-                System.out.println("failed to add " + name + ": " + 
thrown.getMessage());
-            }
-        };
-    }
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/examples/import/src/main/java/org/apache/predictionio/samples/SampleImport.java
----------------------------------------------------------------------
diff --git 
a/examples/import/src/main/java/org/apache/predictionio/samples/SampleImport.java
 
b/examples/import/src/main/java/org/apache/predictionio/samples/SampleImport.java
new file mode 100644
index 0000000..ba177ff
--- /dev/null
+++ 
b/examples/import/src/main/java/org/apache/predictionio/samples/SampleImport.java
@@ -0,0 +1,165 @@
+/*
+ * 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.samples;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+import java.util.concurrent.ExecutionException;
+import org.apache.predictionio.APIResponse;
+import org.apache.predictionio.EventClient;
+import org.apache.predictionio.FutureAPIResponse;
+
+/**
+ * Sample data import client using MovieLens data set.
+ *
+ * @author Cong Qin, Donald Szeto, Tom Chan
+ */
+public class SampleImport {
+
+  private static final int HTTP_CREATED = 201;
+
+  public static void main(String[] args) {
+    /* set appurl to your API server */
+    String appurl = "http://localhost:7070";;
+    /* Handle command line arguments */
+    String accessKey = null;
+    String inputFile = null;
+    try {
+      accessKey = args[0];
+      inputFile = args[1];
+    } catch (ArrayIndexOutOfBoundsException e) {
+      System.err.println("You must provide access key (1st arg) and input file 
name (2nd arg)");
+      System.exit(1);
+    }
+
+    EventClient client = null;
+    Reader fileReader = null;
+
+    /* Read input MovieLens data and send requests to API */
+    List<FutureAPIResponse> listOfFutures = new ArrayList<>(); // keeping 
track of requests
+    try {
+      /* Create a client with the access key */
+      client = new EventClient(accessKey, appurl);
+
+      /* Data structure */
+      Set<String> uids = new TreeSet<String>();
+      Set<String> iids = new TreeSet<String>();
+
+      /* Get API status */
+      System.out.println(client.getStatus());
+
+      /* Open data file for reading */
+      fileReader = new FileReader(inputFile);
+      BufferedReader reader = new BufferedReader(fileReader);
+
+      /* Some local variables */
+      String line;
+      int i = 0;
+      FutureAPIResponse future;
+      Map<String, Object> userProperties = new HashMap<>(); // empty 
properties for user
+
+      while ((line = reader.readLine()) != null) {
+        /* Break the line up */
+        StringTokenizer st = new StringTokenizer(line);
+
+        /* The 1st field is User ID, the 2nd field is Item ID, and the 3rd 
field is rating */
+        String uid = st.nextToken();
+        String iid = st.nextToken();
+        int rate = Integer.parseInt(st.nextToken());
+
+        /* Add user and item if they are not seen before */
+        if (uids.add(uid)) {
+          // event time is omitted since we're not using it
+          future = client.setUserAsFuture(uid, userProperties);
+          listOfFutures.add(future);
+          Futures.addCallback(future.getAPIResponse(), getFutureCallback("user 
" + uid));
+        }
+        if (iids.add(iid)) {
+          Map<String, Object> itemProperties = new HashMap<>();
+          List<String> genre = new ArrayList<>();
+          genre.add("comedy");
+          itemProperties.put("genre", genre);
+          future = client.setItemAsFuture(iid, itemProperties);
+          listOfFutures.add(future);
+          Futures.addCallback(future.getAPIResponse(), getFutureCallback("item 
" + iid));
+        }
+
+        /* User rates the movie. We do this asynchronously */
+        Map<String, Object> properties = new HashMap<>(); // properties with 
rating
+        properties.put("rating", rate);
+        future = client.userActionItemAsFuture("rate", uid, iid, properties);
+        listOfFutures.add(future);
+        Futures.addCallback(future.getAPIResponse(),
+            getFutureCallback("event " + uid + " rates " + iid + " with " + 
rate));
+      }
+    } catch (Exception e) {
+      System.err.println("Error: " + e.getMessage());
+      e.printStackTrace();
+    } finally {
+      if (fileReader != null) {
+        try {
+          fileReader.close();
+        } catch (IOException e) {
+          System.err.println("Error: " + e.getMessage());
+        }
+      }
+      // wait for the import result
+      ListenableFuture<List<APIResponse>> futures = 
Futures.allAsList(listOfFutures);
+      try {
+        List<APIResponse> responses = futures.get();
+        for (APIResponse response : responses) {
+          if (response.getStatus() != HTTP_CREATED) {
+            System.err.println("Error importing some record, first error 
message is: "
+                + response.getMessage());
+            // only print the first error
+            break;
+          }
+        }
+      } catch (InterruptedException | ExecutionException e) {
+        System.err.println("Error importing some record, error message: " + 
e.getStackTrace());
+      }
+      if (client != null) {
+        client.close();
+      }
+    }
+  }
+
+  private static FutureCallback<APIResponse> getFutureCallback(final String 
name) {
+    return new FutureCallback<APIResponse>() {
+      public void onSuccess(APIResponse response) {
+        System.out.println(name + " added: " + response.getMessage());
+      }
+
+      public void onFailure(Throwable thrown) {
+        System.out.println("failed to add " + name + ": " + 
thrown.getMessage());
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/examples/quickstart_import/pom.xml
----------------------------------------------------------------------
diff --git a/examples/quickstart_import/pom.xml 
b/examples/quickstart_import/pom.xml
index 67595f6..d168c72 100644
--- a/examples/quickstart_import/pom.xml
+++ b/examples/quickstart_import/pom.xml
@@ -1,17 +1,32 @@
+<!--
+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>
-    <groupId>io.prediction.samples</groupId>
+    <groupId>org.apache.predictionio.samples</groupId>
     <artifactId>quickstart-import</artifactId>
-    <version>0.9.5</version>
+    <version>0.13.0</version>
     <packaging>jar</packaging>
     <name>PredictionIO Java SDK Examples: Quickstart Import</name>
 
     <dependencies>
         <dependency>
-            <groupId>io.prediction</groupId>
+            <groupId>org.apache.predictionio</groupId>
             <artifactId>client</artifactId>
-            <version>0.9.5</version>
+            <version>0.13.0</version>
         </dependency>
     </dependencies>
 
@@ -52,7 +67,7 @@
                 <configuration>
                     <archive>
                         <manifest>
-                            
<mainClass>io.prediction.samples.QuickstartImport</mainClass>
+                            
<mainClass>org.apache.predictionio.samples.QuickstartImport</mainClass>
                         </manifest>
                     </archive>
                     <descriptorRefs>

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/examples/quickstart_import/src/main/java/io/prediction/samples/QuickstartImport.java
----------------------------------------------------------------------
diff --git 
a/examples/quickstart_import/src/main/java/io/prediction/samples/QuickstartImport.java
 
b/examples/quickstart_import/src/main/java/io/prediction/samples/QuickstartImport.java
deleted file mode 100644
index 257e0ae..0000000
--- 
a/examples/quickstart_import/src/main/java/io/prediction/samples/QuickstartImport.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package io.prediction.samples;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-import io.prediction.EventClient;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.ExecutionException;
-import java.util.List;
-import java.util.LinkedList;
-import org.joda.time.DateTime;
-
-import io.prediction.Event;
-
-
-public class QuickstartImport {
-    public static void main(String[] args)
-            throws ExecutionException, InterruptedException, IOException {
-        String accessKey = null;
-        try {
-            accessKey = args[0];
-        } catch (ArrayIndexOutOfBoundsException e) {
-            System.err.println("You must provide access key as the parameter");
-            System.exit(1);
-        }
-        EventClient client = new EventClient(accessKey);
-        Random rand = new Random();
-        Map<String, Object> emptyProperty = ImmutableMap.of();
-
-        // generate 10 users, with user ids 1 to 10
-        for (int user = 1; user <= 10; user++) {
-            System.out.println("Add user " + user);
-            client.setUser(""+user, emptyProperty);
-        }
-
-        // generate 50 items, with item ids 1 to 50
-        for (int item = 1; item <= 50; item++) {
-            System.out.println("Add item " + item);
-            client.setItem(""+item, emptyProperty);
-        }
-
-        // each user randomly views 10 items
-        for (int user = 1; user <= 10; user++) {
-            for (int i = 1; i <= 10; i++) {
-                int item = rand.nextInt(50) + 1;
-                System.out.println("User " + user + " views item " + item);
-                client.userActionItem("view", ""+user, ""+item, emptyProperty);
-            }
-        }
-
-        List<Event> events = new LinkedList<Event>();
-     
-        // Use only 5 users because max batch size is 50
-        // Throws IOException w/ details inside if this is exceeded
-        for (int user = 1; user <= 5; user++) {
-            for (int i = 1; i <= 10; i++) {
-                int item = rand.nextInt(50) + 1;
-                System.out.println("User " + user + " views item " + item);
-                events.add(new Event()
-            .event("view")
-            .entityType("user")
-            .entityId(""+user)
-            .targetEntityType("item")
-            .targetEntityId(""+item)
-            .properties(emptyProperty)
-            .eventTime(new DateTime()));
-            }
-        }
-    
-        client.createEvents(events);
-
-        client.close();
-    }
-}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/examples/quickstart_import/src/main/java/org/apache/predictionio/samples/QuickstartImport.java
----------------------------------------------------------------------
diff --git 
a/examples/quickstart_import/src/main/java/org/apache/predictionio/samples/QuickstartImport.java
 
b/examples/quickstart_import/src/main/java/org/apache/predictionio/samples/QuickstartImport.java
new file mode 100644
index 0000000..a0cea4c
--- /dev/null
+++ 
b/examples/quickstart_import/src/main/java/org/apache/predictionio/samples/QuickstartImport.java
@@ -0,0 +1,91 @@
+/*
+ * 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.samples;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ExecutionException;
+import org.apache.predictionio.Event;
+import org.apache.predictionio.EventClient;
+import org.joda.time.DateTime;
+
+
+public class QuickstartImport {
+
+  public static void main(String[] args)
+      throws ExecutionException, InterruptedException, IOException {
+    String accessKey = null;
+    try {
+      accessKey = args[0];
+    } catch (ArrayIndexOutOfBoundsException e) {
+      System.err.println("You must provide access key as the parameter");
+      System.exit(1);
+    }
+    EventClient client = new EventClient(accessKey);
+    Random rand = new Random();
+    Map<String, Object> emptyProperty = ImmutableMap.of();
+
+    // generate 10 users, with user ids 1 to 10
+    for (int user = 1; user <= 10; user++) {
+      System.out.println("Add user " + user);
+      client.setUser("" + user, emptyProperty);
+    }
+
+    // generate 50 items, with item ids 1 to 50
+    for (int item = 1; item <= 50; item++) {
+      System.out.println("Add item " + item);
+      client.setItem("" + item, emptyProperty);
+    }
+
+    // each user randomly views 10 items
+    for (int user = 1; user <= 10; user++) {
+      for (int i = 1; i <= 10; i++) {
+        int item = rand.nextInt(50) + 1;
+        System.out.println("User " + user + " views item " + item);
+        client.userActionItem("view", "" + user, "" + item, emptyProperty);
+      }
+    }
+
+    List<Event> events = new LinkedList<Event>();
+
+    // Use only 5 users because max batch size is 50
+    // Throws IOException w/ details inside if this is exceeded
+    for (int user = 1; user <= 5; user++) {
+      for (int i = 1; i <= 10; i++) {
+        int item = rand.nextInt(50) + 1;
+        System.out.println("User " + user + " views item " + item);
+        events.add(new Event()
+            .event("view")
+            .entityType("user")
+            .entityId("" + user)
+            .targetEntityType("item")
+            .targetEntityId("" + item)
+            .properties(emptyProperty)
+            .eventTime(new DateTime()));
+      }
+    }
+
+    client.createEvents(events);
+
+    client.close();
+  }
+}

http://git-wip-us.apache.org/repos/asf/predictionio-sdk-java/blob/0780fcd5/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 1500ed8..d2f4938 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,20 +1,42 @@
 <?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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>
-  <groupId>io.prediction</groupId>
-  <artifactId>sdk</artifactId>
-  <version>0.9.6-SNAPSHOT</version>
-  <url>http://prediction.io</url>
+  <groupId>org.apache.predictionio</groupId>
+  <artifactId>predictionio-sdk-java</artifactId>
+  <version>0.13.0-SNAPSHOT</version>
+  <url>http://predictionio.apache.org</url>
   <packaging>pom</packaging>
-  <name>PredictionIO Java SDK</name>
-  <description>The PredictionIO Java SDK includes an API client and sample 
code.</description>
+  <name>Apache PredictionIO Java SDK</name>
+  <description>The Apache PredictionIO Java SDK includes an API client and 
sample code.</description>
 
   <parent>
-    <groupId>org.sonatype.oss</groupId>
-    <artifactId>oss-parent</artifactId>
-    <version>7</version>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>21</version>
   </parent>
 
+  <scm>
+    
<connection>scm:git:https://github.com/apache/predictionio-sdk-java</connection>
+    
<developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/predictionio-sdk-java.git</developerConnection>
+    <url>https://github.com/apache/predictionio-sdk-java</url>
+  </scm>
+
   <dependencies>
     <dependency>
       <groupId>com.google.guava</groupId>
@@ -23,22 +45,6 @@
     </dependency>
   </dependencies>
 
-  <licenses>
-    <license>
-      <name>The Apache Software License, Version 2.0</name>
-      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
-      <distribution>repo</distribution>
-    </license>
-  </licenses>
-
-  <developers>
-    <developer>
-      <id>predictionio</id>
-      <name>The PredictionIO Team</name>
-      <email>[email protected]</email>
-    </developer>
-  </developers>
-
   <contributors>
     <contributor>
       <name>Cong Qin</name>
@@ -46,69 +52,71 @@
     </contributor>
   </contributors>
 
-  <scm>
-    
<connection>scm:git:[email protected]:PredictionIO/PredictionIO-Java-SDK.git</connection>
-    
<developerConnection>scm:git:[email protected]:PredictionIO/PredictionIO-Java-SDK.git</developerConnection>
-    <url>[email protected]:PredictionIO/PredictionIO-Java-SDK.git</url>
-  </scm>
-
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
     <outputDirectory>${project.build.directory}</outputDirectory>
+    <project.root>${project.basedir}</project.root>
   </properties>
 
   <modules>
     <module>client</module>
   </modules>
 
-  <distributionManagement>
-    <snapshotRepository>
-      <id>ossrh</id>
-      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
-    </snapshotRepository>
-    <repository>
-      <id>ossrh</id>
-      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
-    </repository>
-  </distributionManagement>
-
   <build>
     <plugins>
       <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>
-          <target>1.7</target>
-        </configuration>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>3.0.0</version>
+        <executions>
+          <execution>
+            <id>validate</id>
+            <phase>validate</phase>
+            <configuration>
+              <configLocation>google_checks.xml</configLocation>
+              <encoding>UTF-8</encoding>
+              <consoleOutput>true</consoleOutput>
+              <failsOnError>true</failsOnError>
+              <linkXRef>false</linkXRef>
+            </configuration>
+            <goals>
+              <goal>check</goal>
+            </goals>
+          </execution>
+        </executions>
       </plugin>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-gpg-plugin</artifactId>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>findbugs-maven-plugin</artifactId>
+        <version>3.0.5</version>
         <executions>
           <execution>
-            <id>sign-artifacts</id>
-            <phase>verify</phase>
+            <id>validate</id>
+            <phase>validate</phase>
             <goals>
-              <goal>sign</goal>
+              <goal>check</goal>
             </goals>
           </execution>
         </executions>
       </plugin>
       <plugin>
-        <groupId>org.sonatype.plugins</groupId>
-        <artifactId>nexus-staging-maven-plugin</artifactId>
-        <version>1.6</version>
-        <extensions>true</extensions>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <version>0.12</version>
         <configuration>
-          <serverId>ossrh</serverId>
-          <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+          <excludesFile>${project.root}/.rat-excludes</excludesFile>
         </configuration>
+        <executions>
+          <execution>
+            <id>validate</id>
+            <phase>validate</phase>
+            <goals>
+              <goal>check</goal>
+            </goals>
+          </execution>
+        </executions>
       </plugin>
     </plugins>
   </build>
-
 </project>

Reply via email to