You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/01/28 23:22:07 UTC

[57/96] [abbrv] USERGRID-2 package namespace to org.apache.usergrid

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/android/src/main/java/org/usergrid/android/client/Client.java
----------------------------------------------------------------------
diff --git a/sdks/android/src/main/java/org/usergrid/android/client/Client.java b/sdks/android/src/main/java/org/usergrid/android/client/Client.java
deleted file mode 100644
index 3effe73..0000000
--- a/sdks/android/src/main/java/org/usergrid/android/client/Client.java
+++ /dev/null
@@ -1,590 +0,0 @@
-package org.usergrid.android.client;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-import org.springframework.http.HttpMethod;
-import org.springframework.web.client.RestTemplate;
-import org.usergrid.android.client.callbacks.ApiResponseCallback;
-import org.usergrid.android.client.callbacks.ClientAsyncTask;
-import org.usergrid.android.client.callbacks.DeviceRegistrationCallback;
-import org.usergrid.android.client.callbacks.GroupsRetrievedCallback;
-import org.usergrid.android.client.callbacks.QueryResultsCallback;
-import org.usergrid.java.client.entities.Device;
-import org.usergrid.java.client.entities.Entity;
-import org.usergrid.java.client.entities.Group;
-import org.usergrid.java.client.entities.User;
-import org.usergrid.java.client.response.ApiResponse;
-import org.usergrid.android.client.utils.DeviceUuidFactory;
-
-import android.content.Context;
-import android.location.Location;
-
-/**
- * The Client class for accessing the Usergrid API. Start by instantiating this
- * class though the appropriate constructor.
- * 
- */
-public class Client extends org.usergrid.java.client.Client {
-
-	private static final String TAG = "UsergridClient";
-
-	public static boolean FORCE_PUBLIC_API = false;
-
-	// Public API
-	public static String PUBLIC_API_URL = "http://api.usergrid.com";
-
-	// Local API of standalone server
-	public static String LOCAL_STANDALONE_API_URL = "http://localhost:8080";
-
-	// Local API of Tomcat server in Eclipse
-	public static String LOCAL_TOMCAT_API_URL = "http://localhost:8080/ROOT";
-
-	// Local API
-	public static String LOCAL_API_URL = LOCAL_STANDALONE_API_URL;
-
-	
-	static RestTemplate restTemplate = new RestTemplate(true);
-
-	/**
-	 * Default constructor for instantiating a client.
-	 */
-	public Client() {
-		init();
-	}
-
-	/**
-	 * Instantiate client for a specific app
-	 * 
-	 * @param applicationId
-	 *            the application id or name
-	 */
-	public Client(String organizationId, String applicationId) {
-		super(organizationId, applicationId);
-	}
-
-
-	/**
-	 * Log the user in and get a valid access token. Executes asynchronously in
-	 * background and the callbacks are called in the UI thread.
-	 * 
-	 * @param email
-	 * @param password
-	 * @param callback
-	 */
-	public void authorizeAppUserAsync(final String email,
-			final String password, final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return authorizeAppUser(email, password);
-			}
-		}).execute();
-	}
-
-	
-
-	/**
-	 * Log the user in with their numeric pin-code and get a valid access token.
-	 * Executes asynchronously in background and the callbacks are called in the
-	 * UI thread.
-	 * 
-	 * @param email
-	 * @param pin
-	 * @param callback
-	 */
-	public void authorizeAppUserViaPinAsync(final String email,
-			final String pin, final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return authorizeAppUserViaPin(email, pin);
-			}
-		}).execute();
-	}
-
-
-	/**
-	 * Log the user in with their numeric pin-code and get a valid access token.
-	 * Executes asynchronously in background and the callbacks are called in the
-	 * UI thread.
-	 * 
-	 * @param email
-	 * @param pin
-	 * @param callback
-	 */
-	public void authorizeAppUserViaFacebookAsync(final String fb_access_token,
-			final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return authorizeAppUserViaFacebook(fb_access_token);
-			}
-		}).execute();
-	}
-
-	
-
-	/**
-	 * Log the app in with it's client id and client secret key. Not recommended
-	 * for production apps. Executes asynchronously in background and the
-	 * callbacks are called in the UI thread.
-	 * 
-	 * @param clientId
-	 * @param clientSecret
-	 * @param callback
-	 */
-	public void authorizeAppClientAsync(final String clientId,
-			final String clientSecret, final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-
-			@Override
-			public ApiResponse doTask() {
-				return authorizeAppClient(clientId, clientSecret);
-			}
-		}).execute();
-	}
-
-	
-	/**
-	 * Registers a device using the device's unique device ID. Executes
-	 * asynchronously in background and the callbacks are called in the UI
-	 * thread.
-	 * 
-	 * @param context
-	 * @param properties
-	 * @param callback
-	 */
-	public void registerDeviceAsync(final Context context,
-			final Map<String, Object> properties,
-			final DeviceRegistrationCallback callback) {
-		(new ClientAsyncTask<Device>(callback) {
-			@Override
-			public Device doTask() {
-			    UUID deviceId = new DeviceUuidFactory(context).getDeviceUuid();
-		        
-				return registerDevice(deviceId, properties);
-			}
-		}).execute();
-	}
-
-
-  /**
-   * Registers a device using the device's unique device ID. Executes
-   * asynchronously in background and the callbacks are called in the UI
-   * thread.
-   *
-   * @param context
-   * @param properties
-   * @param callback
-   */
-  public void registerDeviceForPushAsync(final Context context,
-                                         final String notifier,
-                                         final String token,
-                                         final Map<String, Object> properties,
-                                         final DeviceRegistrationCallback callback) {
-    (new ClientAsyncTask<Device>(callback) {
-      @Override
-      public Device doTask() {
-        UUID deviceId = new DeviceUuidFactory(context).getDeviceUuid();
-
-        return registerDeviceForPush(deviceId, notifier, token, properties);
-      }
-    }).execute();
-  }
-
-
-  /**
-	 * Create a new entity on the server. Executes asynchronously in background
-	 * and the callbacks are called in the UI thread.
-	 * 
-	 * @param entity
-	 * @param callback
-	 */
-	public void createEntityAsync(final Entity entity,
-			final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return createEntity(entity);
-			}
-		}).execute();
-	}
-
-	
-	/**
-	 * Create a new entity on the server from a set of properties. Properties
-	 * must include a "type" property. Executes asynchronously in background and
-	 * the callbacks are called in the UI thread.
-	 * 
-	 * @param properties
-	 * @param callback
-	 */
-	public void createEntityAsync(final Map<String, Object> properties,
-			final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return createEntity(properties);
-			}
-		}).execute();
-	}
-
-
-	/**
-	 * Creates a user. Executes asynchronously in background and the callbacks
-	 * are called in the UI thread.
-	 * 
-	 * @param username
-	 * @param name
-	 * @param email
-	 * @param password
-	 * @param callback
-	 */
-	public void createUserAsync(final String username, final String name,
-			final String email, final String password,
-			final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return createUser(username, name, email, password);
-			}
-		}).execute();
-	}
-
-
-
-	/**
-	 * Get the groups for the user. Executes asynchronously in background and
-	 * the callbacks are called in the UI thread.
-	 * 
-	 * @param userId
-	 * @param callback
-	 */
-	public void getGroupsForUserAsync(final String userId,
-			final GroupsRetrievedCallback callback) {
-		(new ClientAsyncTask<Map<String, Group>>(callback) {
-			@Override
-			public Map<String, Group> doTask() {
-				return getGroupsForUser(userId);
-			}
-		}).execute();
-	}
-
-	/**
-	 * Get a user's activity feed. Returned as a query to ease paging. Executes
-	 * asynchronously in background and the callbacks are called in the UI
-	 * thread.
-	 * 
-	 * 
-	 * @param userId
-	 * @param callback
-	 */
-	public void queryActivityFeedForUserAsync(final String userId, final QueryResultsCallback callback) {
-		(new ClientAsyncTask<Query>(callback) {
-			@Override
-			public Query doTask() {
-				return queryActivityFeedForUser(userId);
-			}
-		}).execute();
-	}
-
-	
-	/**
-	 * Creates and posts an activity to a user. Executes asynchronously in
-	 * background and the callbacks are called in the UI thread.
-	 * 
-	 * @param verb
-	 * @param title
-	 * @param content
-	 * @param category
-	 * @param user
-	 * @param object
-	 * @param objectType
-	 * @param objectName
-	 * @param objectContent
-	 * @param callback
-	 */
-	public void postUserActivityAsync(final String verb, final String title,
-			final String content, final String category, final User user,
-			final Entity object, final String objectType,
-			final String objectName, final String objectContent,
-			final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return postUserActivity(verb, title, content, category, user,
-						object, objectType, objectName, objectContent);
-			}
-		}).execute();
-	}
-
-	
-	/**
-	 * Creates and posts an activity to a group. Executes asynchronously in
-	 * background and the callbacks are called in the UI thread.
-	 * 
-	 * @param groupId
-	 * @param verb
-	 * @param title
-	 * @param content
-	 * @param category
-	 * @param user
-	 * @param object
-	 * @param objectType
-	 * @param objectName
-	 * @param objectContent
-	 * @param callback
-	 */
-	public void postGroupActivityAsync(final String groupId, final String verb, final String title,
-			final String content, final String category, final User user,
-			final Entity object, final String objectType,
-			final String objectName, final String objectContent,
-			final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return postGroupActivity(groupId, verb, title, content, category, user,
-						object, objectType, objectName, objectContent);
-			}
-		}).execute();
-	}
-
-
-	/**
-	 * Get a group's activity feed. Returned as a query to ease paging. Executes
-	 * asynchronously in background and the callbacks are called in the UI
-	 * thread.
-	 * 
-	 * 
-	 * @param userId
-	 * @param callback
-	 */
-	public void queryActivityFeedForGroupAsync(final String groupId,
-			final QueryResultsCallback callback) {
-		(new ClientAsyncTask<Query>(callback) {
-			@Override
-			public Query doTask() {
-				return queryActivityFeedForGroup(groupId);
-			}
-		}).execute();
-	}
-
-
-	/**
-	 * Perform a query request and return a query object. The Query object
-	 * provides a simple way of dealing with result sets that need to be
-	 * iterated or paged through. Executes asynchronously in background and the
-	 * callbacks are called in the UI thread.
-	 * 
-	 * @param callback
-	 * @param method
-	 * @param params
-	 * @param data
-	 * @param segments
-	 */
-	public void queryEntitiesRequestAsync(final QueryResultsCallback callback,
-			final HttpMethod method, final Map<String, Object> params,
-			final Object data, final String... segments) {
-		(new ClientAsyncTask<Query>(callback) {
-			@Override
-			public Query doTask() {
-				return queryEntitiesRequest(method, params, data, segments);
-			}
-		}).execute();
-	}
-
-
-	/**
-	 * Perform a query of the users collection. Executes asynchronously in
-	 * background and the callbacks are called in the UI thread.
-	 * 
-	 * @param callback
-	 */
-	public void queryUsersAsync(QueryResultsCallback callback) {
-		queryEntitiesRequestAsync(callback, HttpMethod.GET, null, null,
-				getApplicationId(), "users");
-	}
-
-	/**
-	 * Perform a query of the users collection using the provided query command.
-	 * For example: "name contains 'ed'". Executes asynchronously in background
-	 * and the callbacks are called in the UI thread.
-	 * 
-	 * @param ql
-	 * @param callback
-	 */
-	public void queryUsersAsync(String ql, QueryResultsCallback callback) {
-		Map<String, Object> params = new HashMap<String, Object>();
-		params.put("ql", ql);
-		queryEntitiesRequestAsync(callback, HttpMethod.GET, params, null,
-				getApplicationId(), "users");
-	}
-
-	
-	/**
-	 * Queries the users for the specified group. Executes asynchronously in
-	 * background and the callbacks are called in the UI thread.
-	 * 
-	 * @param groupId
-	 * @param callback
-	 */
-	public void queryUsersForGroupAsync(String groupId,
-			QueryResultsCallback callback) {
-		queryEntitiesRequestAsync(callback, HttpMethod.GET, null, null,
-				getApplicationId(), "groups", groupId, "users");
-	}
-
-	/**
-	 * Adds a user to the specified groups. Executes asynchronously in
-	 * background and the callbacks are called in the UI thread.
-	 * 
-	 * @param userId
-	 * @param groupId
-	 * @param callback
-	 */
-	public void addUserToGroupAsync(final String userId, final String groupId,
-			final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return addUserToGroup(userId, groupId);
-			}
-		}).execute();
-	}
-
-
-	/**
-	 * Creates a group with the specified group path. Group paths can be slash
-	 * ("/") delimited like file paths for hierarchical group relationships.
-	 * Executes asynchronously in background and the callbacks are called in the
-	 * UI thread.
-	 * 
-	 * @param groupPath
-	 * @param callback
-	 */
-	public void createGroupAsync(String groupPath,
-			final ApiResponseCallback callback) {
-		createGroupAsync(groupPath, null);
-	}
-
-	
-
-	/**
-	 * Creates a group with the specified group path and group title. Group
-	 * paths can be slash ("/") deliminted like file paths for hierarchical
-	 * group relationships. Executes asynchronously in background and the
-	 * callbacks are called in the UI thread.
-	 * 
-	 * @param groupPath
-	 * @param groupTitle
-	 * @param callback
-	 */
-	public void createGroupAsync(final String groupPath,
-			final String groupTitle, final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return createGroup(groupPath, groupTitle);
-			}
-		}).execute();
-	}
-
-	
-	/**
-	 * Connect two entities together. Executes asynchronously in background and
-	 * the callbacks are called in the UI thread.
-	 * 
-	 * @param connectingEntityType
-	 * @param connectingEntityId
-	 * @param connectionType
-	 * @param connectedEntityId
-	 * @param callback
-	 */
-	public void connectEntitiesAsync(final String connectingEntityType,
-			final String connectingEntityId, final String connectionType,
-			final String connectedEntityId, final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return connectEntities(connectingEntityType,
-						connectingEntityId, connectionType, connectedEntityId);
-			}
-		}).execute();
-	}
-
-
-
-	/**
-	 * Disconnect two entities. Executes asynchronously in background and the
-	 * callbacks are called in the UI thread.
-	 * 
-	 * @param connectingEntityType
-	 * @param connectingEntityId
-	 * @param connectionType
-	 * @param connectedEntityId
-	 * @param callback
-	 */
-	public void disconnectEntitiesAsync(final String connectingEntityType,
-			final String connectingEntityId, final String connectionType,
-			final String connectedEntityId, final ApiResponseCallback callback) {
-		(new ClientAsyncTask<ApiResponse>(callback) {
-			@Override
-			public ApiResponse doTask() {
-				return connectEntities(connectingEntityType,
-						connectingEntityId, connectionType, connectedEntityId);
-			}
-		}).execute();
-	}
-
-
-
-	/**
-	 * Query the connected entities. Executes asynchronously in background and
-	 * the callbacks are called in the UI thread.
-	 * 
-	 * @param connectingEntityType
-	 * @param connectingEntityId
-	 * @param connectionType
-	 * @param ql
-	 * @param callback
-	 */
-	public void queryEntityConnectionsAsync(String connectingEntityType,
-			String connectingEntityId, String connectionType, String ql,
-			QueryResultsCallback callback) {
-		Map<String, Object> params = new HashMap<String, Object>();
-		params.put("ql", ql);
-		queryEntitiesRequestAsync(callback, HttpMethod.GET, params, null,
-				getApplicationId(), connectingEntityType, connectingEntityId,
-				connectionType);
-	}
-
-
-	/**
-	 * Query the connected entities within distance of a specific point. .
-	 * Executes asynchronously in background and the callbacks are called in the
-	 * UI thread.
-	 * 
-	 * @param connectingEntityType
-	 * @param connectingEntityId
-	 * @param connectionType
-	 * @param distance
-	 * @param latitude
-	 * @param longitude
-	 * @param callback
-	 */
-	public void queryEntityConnectionsWithinLocationAsync(
-			String connectingEntityType, String connectingEntityId,
-			String connectionType, float distance, Location location,
-			String ql, QueryResultsCallback callback) {
-		Map<String, Object> params = new HashMap<String, Object>();
-		params.put("ql", makeLocationQL(distance, location.getLatitude(), location.getLongitude(), ql));
-		params.put("ql", ql);
-		queryEntitiesRequestAsync(callback, HttpMethod.GET, params, null,
-				getApplicationId(), connectingEntityType, connectingEntityId,
-				connectionType);
-	}
-
-	
-	
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ApiResponseCallback.java
----------------------------------------------------------------------
diff --git a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ApiResponseCallback.java b/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ApiResponseCallback.java
deleted file mode 100644
index 6da5040..0000000
--- a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ApiResponseCallback.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.usergrid.android.client.callbacks;
-
-import org.usergrid.java.client.response.ApiResponse;
-
-
-public interface ApiResponseCallback extends ClientCallback<ApiResponse> {
-
-	public void onResponse(ApiResponse response);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ClientAsyncTask.java
----------------------------------------------------------------------
diff --git a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ClientAsyncTask.java b/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ClientAsyncTask.java
deleted file mode 100644
index da2dcaa..0000000
--- a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ClientAsyncTask.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.usergrid.android.client.callbacks;
-
-import android.os.AsyncTask;
-
-public abstract class ClientAsyncTask<T> extends AsyncTask<Void, Exception, T> {
-
-	ClientCallback<T> callback;
-
-	public ClientAsyncTask(ClientCallback<T> callback) {
-		this.callback = callback;
-	}
-
-	@Override
-	protected T doInBackground(Void... v) {
-		try {
-			return doTask();
-		} catch (Exception e) {
-			this.publishProgress(e);
-		}
-		return null;
-	}
-
-	public abstract T doTask();
-
-	@Override
-	protected void onPostExecute(T response) {
-		if (callback != null) {
-			callback.onResponse(response);
-		}
-	}
-
-	@Override
-	protected void onProgressUpdate(Exception... e) {
-		if ((callback != null) && (e != null) && (e.length > 0)) {
-			callback.onException(e[0]);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ClientCallback.java
----------------------------------------------------------------------
diff --git a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ClientCallback.java b/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ClientCallback.java
deleted file mode 100644
index d84d17b..0000000
--- a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/ClientCallback.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.usergrid.android.client.callbacks;
-
-public interface ClientCallback<T> {
-
-	public void onResponse(T response);
-
-	public void onException(Exception e);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/DeviceRegistrationCallback.java
----------------------------------------------------------------------
diff --git a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/DeviceRegistrationCallback.java b/sdks/android/src/main/java/org/usergrid/android/client/callbacks/DeviceRegistrationCallback.java
deleted file mode 100644
index 2ed0ce8..0000000
--- a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/DeviceRegistrationCallback.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.usergrid.android.client.callbacks;
-
-import org.usergrid.java.client.entities.Device;
-
-public interface DeviceRegistrationCallback extends ClientCallback<Device> {
-
-	public void onDeviceRegistration(Device device);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/GroupsRetrievedCallback.java
----------------------------------------------------------------------
diff --git a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/GroupsRetrievedCallback.java b/sdks/android/src/main/java/org/usergrid/android/client/callbacks/GroupsRetrievedCallback.java
deleted file mode 100644
index 4586f60..0000000
--- a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/GroupsRetrievedCallback.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.usergrid.android.client.callbacks;
-
-import java.util.Map;
-
-import org.usergrid.java.client.entities.Group;
-
-
-public interface GroupsRetrievedCallback extends
-		ClientCallback<Map<String, Group>> {
-
-	public void onGroupsRetrieved(Map<String, Group> groups);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/QueryResultsCallback.java
----------------------------------------------------------------------
diff --git a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/QueryResultsCallback.java b/sdks/android/src/main/java/org/usergrid/android/client/callbacks/QueryResultsCallback.java
deleted file mode 100644
index 9aac648..0000000
--- a/sdks/android/src/main/java/org/usergrid/android/client/callbacks/QueryResultsCallback.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.usergrid.android.client.callbacks;
-
-import org.usergrid.java.client.Client.Query;
-
-public interface QueryResultsCallback extends ClientCallback<Query> {
-
-	public void onQueryResults(Query query);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/android/src/main/java/org/usergrid/android/client/utils/DeviceUuidFactory.java
----------------------------------------------------------------------
diff --git a/sdks/android/src/main/java/org/usergrid/android/client/utils/DeviceUuidFactory.java b/sdks/android/src/main/java/org/usergrid/android/client/utils/DeviceUuidFactory.java
deleted file mode 100644
index d3ac84a..0000000
--- a/sdks/android/src/main/java/org/usergrid/android/client/utils/DeviceUuidFactory.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package org.usergrid.android.client.utils;
-
-import static org.usergrid.android.client.utils.ObjectUtils.isEmpty;
-
-import java.io.UnsupportedEncodingException;
-import java.util.UUID;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.net.wifi.WifiManager;
-import android.os.Build;
-import android.provider.Settings.Secure;
-import android.telephony.TelephonyManager;
-
-/**
- * Tries to get the device ID as a UUID and fallsback to a generated UUID value
- * if it doesn't work.
- * 
- * @see http 
- *      ://stackoverflow.com/questions/2785485/is-there-a-unique-android-device
- *      -id
- * 
- */
-public class DeviceUuidFactory {
-	protected static final String PREFS_FILE = "device_id.xml";
-	protected static final String PREFS_DEVICE_ID = "device_id";
-
-	protected static UUID uuid;
-
-	public DeviceUuidFactory(Context context) {
-
-		if (uuid == null) {
-			synchronized (DeviceUuidFactory.class) {
-				if (uuid == null) {
-					final SharedPreferences prefs = context
-							.getSharedPreferences(PREFS_FILE, 0);
-					final String id = prefs.getString(PREFS_DEVICE_ID, null);
-
-					if (id != null) {
-						// Use the ids previously computed and stored in the
-						// prefs file
-						uuid = UUID.fromString(id);
-
-					} else {
-
-						final String androidId = Secure
-								.getString(context.getContentResolver(),
-										Secure.ANDROID_ID);
-
-						// Use the Android ID unless it's broken, in which case
-						// fallback on deviceId,
-						// unless it's not available, then fallback on a random
-						// number which we store
-						// to a prefs file
-						try {
-							if (!"9774d56d682e549c".equals(androidId)) {
-								uuid = UUID.nameUUIDFromBytes(androidId
-										.getBytes("utf8"));
-							} else {
-								final String deviceId = ((TelephonyManager) context
-										.getSystemService(Context.TELEPHONY_SERVICE))
-										.getDeviceId();
-								uuid = deviceId != null ? UUID
-										.nameUUIDFromBytes(deviceId
-												.getBytes("utf8"))
-										: generateDeviceUuid(context);
-							}
-						} catch (UnsupportedEncodingException e) {
-							throw new RuntimeException(e);
-						}
-
-						// Write the value out to the prefs file
-						prefs.edit()
-								.putString(PREFS_DEVICE_ID, uuid.toString())
-								.commit();
-
-					}
-
-				}
-			}
-		}
-
-	}
-
-	private UUID generateDeviceUuid(Context context) {
-
-		// Get some of the hardware information
-		String buildParams = Build.BOARD + Build.BRAND + Build.CPU_ABI
-				+ Build.DEVICE + Build.DISPLAY + Build.FINGERPRINT + Build.HOST
-				+ Build.ID + Build.MANUFACTURER + Build.MODEL + Build.PRODUCT
-				+ Build.TAGS + Build.TYPE + Build.USER;
-
-		// Requires READ_PHONE_STATE
-		TelephonyManager tm = (TelephonyManager) context
-				.getSystemService(Context.TELEPHONY_SERVICE);
-
-		// gets the imei (GSM) or MEID/ESN (CDMA)
-		String imei = tm.getDeviceId();
-
-		// gets the android-assigned id
-		String androidId = Secure.getString(context.getContentResolver(),
-				Secure.ANDROID_ID);
-
-		// requires ACCESS_WIFI_STATE
-		WifiManager wm = (WifiManager) context
-				.getSystemService(Context.WIFI_SERVICE);
-
-		// gets the MAC address
-		String mac = wm.getConnectionInfo().getMacAddress();
-
-		// if we've got nothing, return a random UUID
-		if (isEmpty(imei) && isEmpty(androidId) && isEmpty(mac)) {
-			return UUID.randomUUID();
-		}
-
-		// concatenate the string
-		String fullHash = buildParams.toString() + imei + androidId + mac;
-
-		return UUID.nameUUIDFromBytes(fullHash.getBytes());
-	}
-
-	/**
-	 * Returns a unique UUID for the current android device. As with all UUIDs,
-	 * this unique ID is "very highly likely" to be unique across all Android
-	 * devices. Much more so than ANDROID_ID is.
-	 * 
-	 * The UUID is generated by using ANDROID_ID as the base key if appropriate,
-	 * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
-	 * be incorrect, and finally falling back on a random UUID that's persisted
-	 * to SharedPreferences if getDeviceID() does not return a usable value.
-	 * 
-	 * In some rare circumstances, this ID may change. In particular, if the
-	 * device is factory reset a new device ID may be generated. In addition, if
-	 * a user upgrades their phone from certain buggy implementations of Android
-	 * 2.2 to a newer, non-buggy version of Android, the device ID may change.
-	 * Or, if a user uninstalls your app on a device that has neither a proper
-	 * Android ID nor a Device ID, this ID may change on reinstallation.
-	 * 
-	 * Note that if the code falls back on using TelephonyManager.getDeviceId(),
-	 * the resulting ID will NOT change after a factory reset. Something to be
-	 * aware of.
-	 * 
-	 * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
-	 * directly.
-	 * 
-	 * @see http://code.google.com/p/android/issues/detail?id=10603
-	 * 
-	 * @return a UUID that may be used to uniquely identify your device for most
-	 *         purposes.
-	 */
-	public UUID getDeviceUuid() {
-		return uuid;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/android/src/main/java/org/usergrid/android/client/utils/ObjectUtils.java
----------------------------------------------------------------------
diff --git a/sdks/android/src/main/java/org/usergrid/android/client/utils/ObjectUtils.java b/sdks/android/src/main/java/org/usergrid/android/client/utils/ObjectUtils.java
deleted file mode 100644
index a9d5a16..0000000
--- a/sdks/android/src/main/java/org/usergrid/android/client/utils/ObjectUtils.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.usergrid.android.client.utils;
-
-import java.util.Map;
-
-public class ObjectUtils {
-
-	public static boolean isEmpty(Object s) {
-		if (s == null) {
-			return true;
-		}
-		if ((s instanceof String) && (((String) s).trim().length() == 0)) {
-			return true;
-		}
-		if (s instanceof Map) {
-			return ((Map<?, ?>) s).isEmpty();
-		}
-		return false;
-	}
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/java/README.txt
----------------------------------------------------------------------
diff --git a/sdks/java/README.txt b/sdks/java/README.txt
index 5540ba4..ce11b55 100644
--- a/sdks/java/README.txt
+++ b/sdks/java/README.txt
@@ -1,8 +1,7 @@
 
-Usergrid Android Client
+Apache Usergrid Java Client
 
-Experimental Android client for Usergrid. Basically uses Spring Android and
-Jackson to wrap calls to Usergrid REST API. Loosely based on the Usergrid
+Experimental Java client for Apache Usergrid. Loosely based on the Usergrid
 Javascript client.
 
 Requires the following permissions:

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/java/pom.xml
----------------------------------------------------------------------
diff --git a/sdks/java/pom.xml b/sdks/java/pom.xml
index 6913cf9..ebeb2bf 100644
--- a/sdks/java/pom.xml
+++ b/sdks/java/pom.xml
@@ -14,12 +14,12 @@
 	</parent>
 	
 	<modelVersion>4.0.0</modelVersion>
-	<groupId>org.usergrid</groupId>
+	<groupId>org.apache.usergrid</groupId>
 	<artifactId>usergrid-java-client</artifactId>
 	<version>0.0.8-SNAPSHOT</version>
 	<packaging>jar</packaging>
 	<description>A simple java client for usergrid</description>
-	<url>https://github.com/apigee/usergrid-stack-internal</url>
+	<url>https://github.com/usergrid/usergrid</url>
 	
 	<licenses>
 		<license>
@@ -82,9 +82,4 @@
 			<url>http://maven.springframework.org/milestone</url>
 		</repository>
 	</repositories>
-	<scm>
-		<connection>scm:git:git@github.com:apigee/usergrid-java-sdk.git</connection>
-		<developerConnection>scm:git:git@github.com:apigee/usergrid-java-sdk.git</developerConnection>
-		<url>git@github.com:apigee/usergrid-java-sdk.git</url>
-	</scm>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3ccbfd8a/sdks/java/src/main/java/org/apache/usergrid/java/client/Client.java
----------------------------------------------------------------------
diff --git a/sdks/java/src/main/java/org/apache/usergrid/java/client/Client.java b/sdks/java/src/main/java/org/apache/usergrid/java/client/Client.java
new file mode 100644
index 0000000..c3e9d69
--- /dev/null
+++ b/sdks/java/src/main/java/org/apache/usergrid/java/client/Client.java
@@ -0,0 +1,1277 @@
+package org.apache.usergrid.java.client;
+
+import static org.apache.usergrid.java.client.utils.JsonUtils.parse;
+import static org.apache.usergrid.java.client.utils.ObjectUtils.isEmpty;
+import static org.apache.usergrid.java.client.utils.UrlUtils.addQueryParams;
+import static org.apache.usergrid.java.client.utils.UrlUtils.encodeParams;
+import static org.apache.usergrid.java.client.utils.UrlUtils.path;
+import static org.springframework.util.StringUtils.arrayToDelimitedString;
+import static org.springframework.util.StringUtils.tokenizeToStringArray;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+
+import org.apache.usergrid.java.client.entities.Activity;
+import org.apache.usergrid.java.client.entities.Device;
+import org.apache.usergrid.java.client.entities.Entity;
+import org.apache.usergrid.java.client.entities.Group;
+import org.apache.usergrid.java.client.entities.User;
+import org.apache.usergrid.java.client.response.ApiResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * The Client class for accessing the Usergrid API. Start by instantiating this
+ * class though the appropriate constructor.
+ * 
+ */
+public class Client {
+
+    private static final Logger log = LoggerFactory.getLogger(Client.class);
+
+    public static boolean FORCE_PUBLIC_API = false;
+
+    // Public API
+    public static String PUBLIC_API_URL = "http://api.usergrid.com";
+
+    // Local API of standalone server
+    public static String LOCAL_STANDALONE_API_URL = "http://localhost:8080";
+
+    // Local API of Tomcat server in Eclipse
+    public static String LOCAL_TOMCAT_API_URL = "http://localhost:8080/ROOT";
+
+    // Local API
+    public static String LOCAL_API_URL = LOCAL_STANDALONE_API_URL;
+
+    private String apiUrl = PUBLIC_API_URL;
+
+    private String organizationId;
+    private String applicationId;
+    private String clientId;
+    private String clientSecret;
+
+    private User loggedInUser = null;
+
+    private String accessToken = null;
+
+    private String currentOrganization = null;
+
+    static RestTemplate restTemplate = new RestTemplate();
+
+    /**
+     * Default constructor for instantiating a client.
+     */
+    public Client() {
+        init();
+    }
+
+    /**
+     * Instantiate client for a specific app
+     * 
+     * @param applicationId
+     *            the application id or name
+     */
+    public Client(String organizationId, String applicationId) {
+        init();
+        this.organizationId = organizationId;
+        this.applicationId = applicationId;
+    }
+
+    public void init() {
+
+    }
+
+    /**
+     * @return the Usergrid API url (default: http://api.usergrid.com)
+     */
+    public String getApiUrl() {
+        return apiUrl;
+    }
+
+    /**
+     * @param apiUrl
+     *            the Usergrid API url (default: http://api.usergrid.com)
+     */
+    public void setApiUrl(String apiUrl) {
+        this.apiUrl = apiUrl;
+    }
+
+    /**
+     * @param apiUrl
+     *            the Usergrid API url (default: http://api.usergrid.com)
+     * @return Client object for method call chaining
+     */
+    public Client withApiUrl(String apiUrl) {
+        this.apiUrl = apiUrl;
+        return this;
+    }
+    
+    
+    /**
+     * the organizationId to set
+     * @param organizationId
+     * @return
+     */
+    public Client withOrganizationId(String organizationId){
+        this.organizationId = organizationId;
+        return this;
+    }
+    
+    
+
+    /**
+     * @return the organizationId
+     */
+    public String getOrganizationId() {
+        return organizationId;
+    }
+
+    /**
+     * @param organizationId the organizationId to set
+     */
+    public void setOrganizationId(String organizationId) {
+        this.organizationId = organizationId;
+    }
+
+    /**
+     * @return the application id or name
+     */
+    public String getApplicationId() {
+        return applicationId;
+    }
+
+    /**
+     * @param applicationId
+     *            the application id or name
+     */
+    public void setApplicationId(String applicationId) {
+        this.applicationId = applicationId;
+    }
+   
+
+    /**
+     * @param applicationId
+     *            the application id or name
+     * @return Client object for method call chaining
+     */
+    public Client withApplicationId(String applicationId) {
+        this.applicationId = applicationId;
+        return this;
+    }
+
+    /**
+     * @return the client key id for making calls as the application-owner. Not
+     *         safe for most mobile use.
+     */
+    public String getClientId() {
+        return clientId;
+    }
+
+    /**
+     * @param clientId
+     *            the client key id for making calls as the application-owner.
+     *            Not safe for most mobile use.
+     */
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    /**
+     * @param clientId
+     *            the client key id for making calls as the application-owner.
+     *            Not safe for most mobile use.
+     * @return Client object for method call chaining
+     */
+    public Client withClientId(String clientId) {
+        this.clientId = clientId;
+        return this;
+    }
+
+    /**
+     * @return the client key id for making calls as the application-owner. Not
+     *         safe for most mobile use.
+     */
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    /**
+     * @param clientSecret
+     *            the client key id for making calls as the application-owner.
+     *            Not safe for most mobile use.
+     */
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    /**
+     * @param clientSecret
+     *            the client key id for making calls as the application-owner.
+     *            Not safe for most mobile use.
+     * @return Client object for method call chaining
+     */
+    public Client withClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+        return this;
+    }
+
+    /**
+     * @return the logged-in user after a successful authorizeAppUser request
+     */
+    public User getLoggedInUser() {
+        return loggedInUser;
+    }
+
+    /**
+     * @param loggedInUser
+     *            the logged-in user, usually not set by host application
+     */
+    public void setLoggedInUser(User loggedInUser) {
+        this.loggedInUser = loggedInUser;
+    }
+
+    /**
+     * @return the OAuth2 access token after a successful authorize request
+     */
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    /**
+     * @param accessToken
+     *            an OAuth2 access token. Usually not set by host application
+     */
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    /**
+     * @return the currentOrganization
+     */
+    public String getCurrentOrganization() {
+        return currentOrganization;
+    }
+
+    /**
+     * @param currentOrganization
+     */
+    public void setCurrentOrganization(String currentOrganization) {
+        this.currentOrganization = currentOrganization;
+    }
+
+    /**
+     * Low-level HTTP request method. Synchronous, blocks till response or
+     * timeout.
+     * 
+     * @param method
+     *            HttpMethod method
+     * @param cls
+     *            class for the return type
+     * @param params
+     *            parameters to encode as querystring or body parameters
+     * @param data
+     *            JSON data to put in body
+     * @param segments
+     *            REST url path segments (i.e. /segment1/segment2/segment3)
+     * @return results marshalled into class specified in cls parameter
+     */
+    public <T> T httpRequest(HttpMethod method, Class<T> cls,
+            Map<String, Object> params, Object data, String... segments) {
+        HttpHeaders requestHeaders = new HttpHeaders();
+        requestHeaders.setAccept(Collections
+                .singletonList(MediaType.APPLICATION_JSON));
+        if (accessToken != null) {
+            String auth = "Bearer " + accessToken;
+            requestHeaders.set("Authorization", auth);
+            log.info("Authorization: " + auth);
+        }
+        String url = path(apiUrl, segments);
+
+        MediaType contentType = MediaType.APPLICATION_JSON;
+        if (method.equals(HttpMethod.POST) && isEmpty(data) && !isEmpty(params)) {
+            data = encodeParams(params);
+            contentType = MediaType.APPLICATION_FORM_URLENCODED;
+        } else {
+            url = addQueryParams(url, params);
+        }
+        requestHeaders.setContentType(contentType);
+        HttpEntity<?> requestEntity = null;
+
+        if (method.equals(HttpMethod.POST) || method.equals(HttpMethod.PUT)) {
+            if (isEmpty(data)) {
+                data = JsonNodeFactory.instance.objectNode();
+            }
+            requestEntity = new HttpEntity<Object>(data, requestHeaders);
+        } else {
+            requestEntity = new HttpEntity<Object>(requestHeaders);
+        }
+        log.info("Client.httpRequest(): url: " + url);
+        ResponseEntity<T> responseEntity = restTemplate.exchange(url, method,
+                requestEntity, cls);
+        log.info("Client.httpRequest(): reponse body: "
+                + responseEntity.getBody().toString());
+        return responseEntity.getBody();
+    }
+
+    /**
+     * High-level Usergrid API request.
+     * 
+     * @param method
+     * @param params
+     * @param data
+     * @param segments
+     * @return
+     */
+    public ApiResponse apiRequest(HttpMethod method,
+            Map<String, Object> params, Object data, String... segments) {
+        ApiResponse response = null;
+        try {
+            response = httpRequest(method, ApiResponse.class, params, data,
+                    segments);
+            log.info("Client.apiRequest(): Response: " + response);
+        } catch (HttpClientErrorException e) {
+            log.error("Client.apiRequest(): HTTP error: "
+                    + e.getLocalizedMessage());
+            response = parse(e.getResponseBodyAsString(), ApiResponse.class);
+            if ((response != null) && !isEmpty(response.getError())) {
+                log.error("Client.apiRequest(): Response error: "
+                        + response.getError());
+                if (!isEmpty(response.getException())) {
+                    log.error("Client.apiRequest(): Response exception: "
+                            + response.getException());
+                }
+            }
+        }
+        return response;
+    }
+
+    protected void assertValidApplicationId() {
+        if (isEmpty(applicationId)) {
+            throw new IllegalArgumentException("No application id specified");
+        }
+    }
+
+    /**
+     * Log the user in and get a valid access token.
+     * 
+     * @param email
+     * @param password
+     * @return non-null ApiResponse if request succeeds, check getError() for
+     *         "invalid_grant" to see if access is denied.
+     */
+    public ApiResponse authorizeAppUser(String email, String password) {
+        validateNonEmptyParam(email, "email");
+        validateNonEmptyParam(password,"password");
+        assertValidApplicationId();
+        loggedInUser = null;
+        accessToken = null;
+        currentOrganization = null;
+        Map<String, Object> formData = new HashMap<String, Object>();
+        formData.put("grant_type", "password");
+        formData.put("username", email);
+        formData.put("password", password);
+        ApiResponse response = apiRequest(HttpMethod.POST, formData, null,
+                organizationId, applicationId, "token");
+        if (response == null) {
+            return response;
+        }
+        if (!isEmpty(response.getAccessToken()) && (response.getUser() != null)) {
+            loggedInUser = response.getUser();
+            accessToken = response.getAccessToken();
+            currentOrganization = null;
+            log.info("Client.authorizeAppUser(): Access token: " + accessToken);
+        } else {
+            log.info("Client.authorizeAppUser(): Response: " + response);
+        }
+        return response;
+    }
+
+    /**
+     * Change the password for the currently logged in user. You must supply the
+     * old password and the new password.
+     * 
+     * @param username
+     * @param oldPassword
+     * @param newPassword
+     * @return
+     */
+    public ApiResponse changePassword(String username, String oldPassword,
+            String newPassword) {
+
+        Map<String, Object> data = new HashMap<String, Object>();
+        data.put("newpassword", newPassword);
+        data.put("oldpassword", oldPassword);
+
+        return apiRequest(HttpMethod.POST, null, data, organizationId,  applicationId, "users",
+                username, "password");
+
+    }
+
+    /**
+     * Log the user in with their numeric pin-code and get a valid access token.
+     * 
+     * @param email
+     * @param pin
+     * @return non-null ApiResponse if request succeeds, check getError() for
+     *         "invalid_grant" to see if access is denied.
+     */
+    public ApiResponse authorizeAppUserViaPin(String email, String pin) {
+        validateNonEmptyParam(email, "email");
+        validateNonEmptyParam(pin, "pin");
+        assertValidApplicationId();
+        loggedInUser = null;
+        accessToken = null;
+        currentOrganization = null;
+        Map<String, Object> formData = new HashMap<String, Object>();
+        formData.put("grant_type", "pin");
+        formData.put("username", email);
+        formData.put("pin", pin);
+        ApiResponse response = apiRequest(HttpMethod.POST, formData, null,
+                organizationId,  applicationId, "token");
+        if (response == null) {
+            return response;
+        }
+        if (!isEmpty(response.getAccessToken()) && (response.getUser() != null)) {
+            loggedInUser = response.getUser();
+            accessToken = response.getAccessToken();
+            currentOrganization = null;
+            log.info("Client.authorizeAppUser(): Access token: " + accessToken);
+        } else {
+            log.info("Client.authorizeAppUser(): Response: " + response);
+        }
+        return response;
+    }
+
+    /**
+     * Log the user in with their Facebook access token retrived via Facebook
+     * OAuth.
+     * 
+     * @param email
+     * @param pin
+     * @return non-null ApiResponse if request succeeds, check getError() for
+     *         "invalid_grant" to see if access is denied.
+     */
+    public ApiResponse authorizeAppUserViaFacebook(String fb_access_token) {
+        validateNonEmptyParam(fb_access_token, "Facebook token");
+        assertValidApplicationId();
+        loggedInUser = null;
+        accessToken = null;
+        currentOrganization = null;
+        Map<String, Object> formData = new HashMap<String, Object>();
+        formData.put("fb_access_token", fb_access_token);
+        ApiResponse response = apiRequest(HttpMethod.POST, formData, null,
+                organizationId,  applicationId, "auth", "facebook");
+        if (response == null) {
+            return response;
+        }
+        if (!isEmpty(response.getAccessToken()) && (response.getUser() != null)) {
+            loggedInUser = response.getUser();
+            accessToken = response.getAccessToken();
+            currentOrganization = null;
+            log.info("Client.authorizeAppUserViaFacebook(): Access token: "
+                    + accessToken);
+        } else {
+            log.info("Client.authorizeAppUserViaFacebook(): Response: "
+                    + response);
+        }
+        return response;
+    }
+
+    /**
+     * Log the app in with it's client id and client secret key. Not recommended
+     * for production apps.
+     * 
+     * @param email
+     * @param pin
+     * @return non-null ApiResponse if request succeeds, check getError() for
+     *         "invalid_grant" to see if access is denied.
+     */
+    public ApiResponse authorizeAppClient(String clientId, String clientSecret) {
+        validateNonEmptyParam(clientId, "client identifier");
+        validateNonEmptyParam(clientSecret, "client secret");
+        assertValidApplicationId();
+        loggedInUser = null;
+        accessToken = null;
+        currentOrganization = null;
+        Map<String, Object> formData = new HashMap<String, Object>();
+        formData.put("grant_type", "client_credentials");
+        formData.put("client_id", clientId);
+        formData.put("client_secret", clientSecret);
+        ApiResponse response = apiRequest(HttpMethod.POST, formData, null,
+                organizationId, applicationId, "token");
+        if (response == null) {
+            return response;
+        }
+        if (!isEmpty(response.getAccessToken())) {
+            loggedInUser = null;
+            accessToken = response.getAccessToken();
+            currentOrganization = null;
+            log.info("Client.authorizeAppClient(): Access token: "
+                    + accessToken);
+        } else {
+            log.info("Client.authorizeAppClient(): Response: " + response);
+        }
+        return response;
+    }
+
+    private void validateNonEmptyParam(Object param, String paramName) {
+        if ( isEmpty(param) ) {
+            throw new IllegalArgumentException(paramName + " cannot be null or empty");
+        }
+    }
+
+    /**
+     * Registers a device using the device's unique device ID.
+     * 
+     * @param context
+     * @param properties
+     * @return a Device object if success
+     */
+    public Device registerDevice(UUID deviceId, Map<String, Object> properties) {
+        assertValidApplicationId();
+        if (properties == null) {
+            properties = new HashMap<String, Object>();
+        }
+        properties.put("refreshed", System.currentTimeMillis());
+        ApiResponse response = apiRequest(HttpMethod.PUT, null, properties,
+                organizationId, applicationId, "devices", deviceId.toString());
+        return response.getFirstEntity(Device.class);
+    }
+
+    /**
+     * Registers a device using the device's unique device ID.
+     *
+     * @param context
+     * @param properties
+     * @return a Device object if success
+     */
+    public Device registerDeviceForPush(UUID deviceId,
+                                        String notifier,
+                                        String token,
+                                        Map<String, Object> properties) {
+      if (properties == null) {
+          properties = new HashMap<String, Object>();
+      }
+      String notifierKey = notifier + ".notifier.id";
+      properties.put(notifierKey, token);
+      return registerDevice(deviceId, properties);
+    }
+
+    /**
+     * Create a new entity on the server.
+     * 
+     * @param entity
+     * @return an ApiResponse with the new entity in it.
+     */
+    public ApiResponse createEntity(Entity entity) {
+        assertValidApplicationId();
+        if (isEmpty(entity.getType())) {
+            throw new IllegalArgumentException("Missing entity type");
+        }
+        ApiResponse response = apiRequest(HttpMethod.POST, null, entity,
+                organizationId, applicationId, entity.getType());
+        return response;
+    }
+
+    /**
+     * Create a new entity on the server from a set of properties. Properties
+     * must include a "type" property.
+     * 
+     * @param properties
+     * @return an ApiResponse with the new entity in it.
+     */
+    public ApiResponse createEntity(Map<String, Object> properties) {
+        assertValidApplicationId();
+        if (isEmpty(properties.get("type"))) {
+            throw new IllegalArgumentException("Missing entity type");
+        }
+        ApiResponse response = apiRequest(HttpMethod.POST, null, properties,
+                organizationId, applicationId, properties.get("type").toString());
+        return response;
+    }
+
+    /**
+     * Creates a user.
+     * 
+     * @param username
+     *            required
+     * @param name
+     * @param email
+     * @param password
+     * @return
+     */
+    public ApiResponse createUser(String username, String name, String email,
+            String password) {
+        Map<String, Object> properties = new HashMap<String, Object>();
+        properties.put("type", "user");
+        if (username != null) {
+            properties.put("username", username);
+        }
+        if (name != null) {
+            properties.put("name", name);
+        }
+        if (email != null) {
+            properties.put("email", email);
+        }
+        if (password != null) {
+            properties.put("password", password);
+        }
+        return createEntity(properties);
+    }
+
+    /**
+     * Get the groups for the user.
+     * 
+     * @param userId
+     * @return a map with the group path as the key and the Group entity as the
+     *         value
+     */
+    public Map<String, Group> getGroupsForUser(String userId) {
+        ApiResponse response = apiRequest(HttpMethod.GET, null, null,
+                organizationId, applicationId, "users", userId, "groups");
+        Map<String, Group> groupMap = new HashMap<String, Group>();
+        if (response != null) {
+            List<Group> groups = response.getEntities(Group.class);
+            for (Group group : groups) {
+                groupMap.put(group.getPath(), group);
+            }
+        }
+        return groupMap;
+    }
+
+    /**
+     * Get a user's activity feed. Returned as a query to ease paging.
+     * 
+     * @param userId
+     * @return
+     */
+    public Query queryActivityFeedForUser(String userId) {
+        Query q = queryEntitiesRequest(HttpMethod.GET, null, null,
+                organizationId, applicationId, "users", userId, "feed");
+        return q;
+    }
+
+    /**
+     * Posts an activity to a user. Activity must already be created.
+     * 
+     * @param userId
+     * @param activity
+     * @return
+     */
+    public ApiResponse postUserActivity(String userId, Activity activity) {
+        return apiRequest(HttpMethod.POST, null, activity,  organizationId, applicationId, "users",
+                userId, "activities");
+    }
+
+    /**
+     * Creates and posts an activity to a user.
+     * 
+     * @param verb
+     * @param title
+     * @param content
+     * @param category
+     * @param user
+     * @param object
+     * @param objectType
+     * @param objectName
+     * @param objectContent
+     * @return
+     */
+    public ApiResponse postUserActivity(String verb, String title,
+            String content, String category, User user, Entity object,
+            String objectType, String objectName, String objectContent) {
+        Activity activity = Activity.newActivity(verb, title, content,
+                category, user, object, objectType, objectName, objectContent);
+        return postUserActivity(user.getUuid().toString(), activity);
+    }
+
+    /**
+     * Posts an activity to a group. Activity must already be created.
+     * 
+     * @param userId
+     * @param activity
+     * @return
+     */
+    public ApiResponse postGroupActivity(String groupId, Activity activity) {
+        return apiRequest(HttpMethod.POST, null, activity, organizationId, applicationId, "groups",
+                groupId, "activities");
+    }
+
+    /**
+     * Creates and posts an activity to a group.
+     * 
+     * @param groupId
+     * @param verb
+     * @param title
+     * @param content
+     * @param category
+     * @param user
+     * @param object
+     * @param objectType
+     * @param objectName
+     * @param objectContent
+     * @return
+     */
+    public ApiResponse postGroupActivity(String groupId, String verb, String title,
+            String content, String category, User user, Entity object,
+            String objectType, String objectName, String objectContent) {
+        Activity activity = Activity.newActivity(verb, title, content,
+                category, user, object, objectType, objectName, objectContent);
+        return postGroupActivity(groupId, activity);
+    }
+
+    /**
+     * Post an activity to the stream.
+     * 
+     * @param activity
+     * @return
+     */
+    public ApiResponse postActivity(Activity activity) {
+        return createEntity(activity);
+    }
+
+    /**
+     * Creates and posts an activity to a group.
+     * 
+     * @param verb
+     * @param title
+     * @param content
+     * @param category
+     * @param user
+     * @param object
+     * @param objectType
+     * @param objectName
+     * @param objectContent
+     * @return
+     */
+    public ApiResponse postActivity(String verb, String title,
+            String content, String category, User user, Entity object,
+            String objectType, String objectName, String objectContent) {
+        Activity activity = Activity.newActivity(verb, title, content,
+                category, user, object, objectType, objectName, objectContent);
+        return createEntity(activity);
+    }
+    
+    /**
+     * Get a group's activity feed. Returned as a query to ease paging.
+     * 
+     * @param userId
+     * @return
+     */
+    public Query queryActivity() {
+        Query q = queryEntitiesRequest(HttpMethod.GET, null, null,
+               organizationId, applicationId, "activities");
+        return q;
+    }
+
+    
+
+    /**
+     * Get a group's activity feed. Returned as a query to ease paging.
+     * 
+     * @param userId
+     * @return
+     */
+    public Query queryActivityFeedForGroup(String groupId) {
+        Query q = queryEntitiesRequest(HttpMethod.GET, null, null,
+                organizationId,  applicationId, "groups", groupId, "feed");
+        return q;
+    }
+
+    /**
+     * Perform a query request and return a query object. The Query object
+     * provides a simple way of dealing with result sets that need to be
+     * iterated or paged through.
+     * 
+     * @param method
+     * @param params
+     * @param data
+     * @param segments
+     * @return
+     */
+    public Query queryEntitiesRequest(HttpMethod method,
+            Map<String, Object> params, Object data, String... segments) {
+        ApiResponse response = apiRequest(method, params, data, segments);
+        return new EntityQuery(response, method, params, data, segments);
+    }
+
+    /**
+     * Perform a query of the users collection.
+     * 
+     * @return
+     */
+    public Query queryUsers() {
+        Query q = queryEntitiesRequest(HttpMethod.GET, null, null,
+                organizationId,  applicationId, "users");
+        return q;
+    }
+
+    /**
+     * Perform a query of the users collection using the provided query command.
+     * For example: "name contains 'ed'".
+     * 
+     * @param ql
+     * @return
+     */
+    public Query queryUsers(String ql) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("ql", ql);
+        Query q = queryEntitiesRequest(HttpMethod.GET, params, null,organizationId,
+                applicationId, "users");
+        return q;
+    }
+
+    /**
+     * Perform a query of the users collection within the specified distance of
+     * the specified location and optionally using the provided query command.
+     * For example: "name contains 'ed'".
+     * 
+     * @param distance
+     * @param location
+     * @param ql
+     * @return
+     */
+    public Query queryUsersWithinLocation(float distance, float lattitude,
+            float longitude, String ql) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("ql",
+                this.makeLocationQL(distance, lattitude, longitude, ql));
+        Query q = queryEntitiesRequest(HttpMethod.GET, params, null, organizationId,
+                applicationId, "users");
+        return q;
+    }
+
+    /**
+     * Queries the users for the specified group.
+     * 
+     * @param groupId
+     * @return
+     */
+    public Query queryUsersForGroup(String groupId) {
+        Query q = queryEntitiesRequest(HttpMethod.GET, null, null, organizationId,
+                applicationId, "groups", groupId, "users");
+        return q;
+    }
+
+    /**
+     * Adds a user to the specified groups.
+     * 
+     * @param userId
+     * @param groupId
+     * @return
+     */
+    public ApiResponse addUserToGroup(String userId, String groupId) {
+        return apiRequest(HttpMethod.POST, null, null, organizationId,  applicationId, "groups",
+                groupId, "users", userId);
+    }
+
+    /**
+     * Creates a group with the specified group path. Group paths can be slash
+     * ("/") delimited like file paths for hierarchical group relationships.
+     * 
+     * @param groupPath
+     * @return
+     */
+    public ApiResponse createGroup(String groupPath) {
+        return createGroup(groupPath, null);
+    }
+
+    /**
+     * Creates a group with the specified group path and group title. Group
+     * paths can be slash ("/") delimited like file paths for hierarchical group
+     * relationships.
+     * 
+     * @param groupPath
+     * @param groupTitle
+     * @return
+     */
+    public ApiResponse createGroup(String groupPath, String groupTitle) {
+     return createGroup(groupPath, groupTitle, null);  
+    }
+    
+    /**
+     * Create a group with a path, title and name
+     * @param groupPath
+     * @param groupTitle
+     * @param groupName
+     * @return
+     */
+    public ApiResponse createGroup(String groupPath, String groupTitle, String groupName){
+        Map<String, Object> data = new HashMap<String, Object>();
+        data.put("type", "group");
+        data.put("path", groupPath);
+        
+        if (groupTitle != null) {
+            data.put("title", groupTitle);
+        }
+        
+        if(groupName != null){
+            data.put("name", groupName);
+        }
+        
+        return apiRequest(HttpMethod.POST, null, data,  organizationId, applicationId, "groups");
+    }
+    
+    /**
+     * Perform a query of the users collection using the provided query command.
+     * For example: "name contains 'ed'".
+     * 
+     * @param ql
+     * @return
+     */
+    public Query queryGroups(String ql) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("ql", ql);
+        Query q = queryEntitiesRequest(HttpMethod.GET, params, null, organizationId,
+                applicationId, "groups");
+        return q;
+    }
+
+    
+
+    /**
+     * Connect two entities together.
+     * 
+     * @param connectingEntityType
+     * @param connectingEntityId
+     * @param connectionType
+     * @param connectedEntityId
+     * @return
+     */
+    public ApiResponse connectEntities(String connectingEntityType,
+            String connectingEntityId, String connectionType,
+            String connectedEntityId) {
+        return apiRequest(HttpMethod.POST, null, null,  organizationId, applicationId,
+                connectingEntityType, connectingEntityId, connectionType,
+                connectedEntityId);
+    }
+
+    /**
+     * Disconnect two entities.
+     * 
+     * @param connectingEntityType
+     * @param connectingEntityId
+     * @param connectionType
+     * @param connectedEntityId
+     * @return
+     */
+    public ApiResponse disconnectEntities(String connectingEntityType,
+            String connectingEntityId, String connectionType,
+            String connectedEntityId) {
+        return apiRequest(HttpMethod.DELETE, null, null,  organizationId, applicationId,
+                connectingEntityType, connectingEntityId, connectionType,
+                connectedEntityId);
+    }
+
+    /**
+     * Query the connected entities.
+     * 
+     * @param connectingEntityType
+     * @param connectingEntityId
+     * @param connectionType
+     * @param ql
+     * @return
+     */
+    public Query queryEntityConnections(String connectingEntityType,
+            String connectingEntityId, String connectionType, String ql) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("ql", ql);
+        Query q = queryEntitiesRequest(HttpMethod.GET, params, null,
+                organizationId, applicationId, connectingEntityType, connectingEntityId,
+                connectionType);
+        return q;
+    }
+
+    protected String makeLocationQL(float distance, double lattitude,
+            double longitude, String ql) {
+        String within = String.format("within %d of %d , %d", distance,
+                lattitude, longitude);
+        ql = ql == null ? within : within + " and " + ql;
+        return ql;
+    }
+
+    /**
+     * Query the connected entities within distance of a specific point.
+     * 
+     * @param connectingEntityType
+     * @param connectingEntityId
+     * @param connectionType
+     * @param distance
+     * @param latitude
+     * @param longitude
+     * @return
+     */
+    public Query queryEntityConnectionsWithinLocation(
+            String connectingEntityType, String connectingEntityId,
+            String connectionType, float distance, float lattitude,
+            float longitude, String ql) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("ql", makeLocationQL(distance, lattitude, longitude, ql));
+        Query q = queryEntitiesRequest(HttpMethod.GET, params, null, organizationId,
+                applicationId, connectingEntityType, connectingEntityId,
+                connectionType);
+        return q;
+    }
+
+    public interface Query {
+
+        public ApiResponse getResponse();
+
+        public boolean more();
+
+        public Query next();
+
+    }
+
+    /**
+     * Query object
+     * 
+     */
+    private class EntityQuery implements Query {
+        final HttpMethod method;
+        final Map<String, Object> params;
+        final Object data;
+        final String[] segments;
+        final ApiResponse response;
+
+        private EntityQuery(ApiResponse response, HttpMethod method,
+                Map<String, Object> params, Object data, String[] segments) {
+            this.response = response;
+            this.method = method;
+            this.params = params;
+            this.data = data;
+            this.segments = segments;
+        }
+
+        private EntityQuery(ApiResponse response, EntityQuery q) {
+            this.response = response;
+            method = q.method;
+            params = q.params;
+            data = q.data;
+            segments = q.segments;
+        }
+
+        /**
+         * @return the api response of the last request
+         */
+        public ApiResponse getResponse() {
+            return response;
+        }
+
+        /**
+         * @return true if the server indicates more results are available
+         */
+        public boolean more() {
+            if ((response != null) && (response.getCursor() != null)
+                    && (response.getCursor().length() > 0)) {
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Performs a request for the next set of results
+         * 
+         * @return query that contains results and where to get more from.
+         */
+        public Query next() {
+            if (more()) {
+                Map<String, Object> nextParams = null;
+                if (params != null) {
+                    nextParams = new HashMap<String, Object>(params);
+                } else {
+                    nextParams = new HashMap<String, Object>();
+                }
+                nextParams.put("cursor", response.getCursor());
+                ApiResponse nextResponse = apiRequest(method, nextParams, data,
+                        segments);
+                return new EntityQuery(nextResponse, this);
+            }
+            return null;
+        }
+
+    }
+
+    private String normalizeQueuePath(String path) {
+        return arrayToDelimitedString(
+                tokenizeToStringArray(path, "/", true, true), "/");
+    }
+
+    public ApiResponse postMessage(String path, Map<String, Object> message) {
+        return apiRequest(HttpMethod.POST, null, message, organizationId,  applicationId,
+                "queues", normalizeQueuePath(path));
+    }
+
+    public ApiResponse postMessage(String path,
+            List<Map<String, Object>> messages) {
+        return apiRequest(HttpMethod.POST, null, messages,  organizationId, applicationId,
+                "queues", normalizeQueuePath(path));
+    }
+
+    public enum QueuePosition {
+        START("start"), END("end"), LAST("last"), CONSUMER("consumer");
+
+        private final String shortName;
+
+        QueuePosition(String shortName) {
+            this.shortName = shortName;
+        }
+
+        static Map<String, QueuePosition> nameMap = new ConcurrentHashMap<String, QueuePosition>();
+
+        static {
+            for (QueuePosition op : EnumSet.allOf(QueuePosition.class)) {
+                if (op.shortName != null) {
+                    nameMap.put(op.shortName, op);
+                }
+            }
+        }
+
+        public static QueuePosition find(String s) {
+            if (s == null) {
+                return null;
+            }
+            return nameMap.get(s);
+        }
+
+        @Override
+        public String toString() {
+            return shortName;
+        }
+    }
+
+    public ApiResponse getMessages(String path, String consumer, UUID last,
+            Long time, Integer prev, Integer next, Integer limit,
+            QueuePosition pos, Boolean update, Boolean sync) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        if (consumer != null) {
+            params.put("consumer", consumer);
+        }
+        if (last != null) {
+            params.put("last", last);
+        }
+        if (time != null) {
+            params.put("time", time);
+        }
+        if (prev != null) {
+            params.put("prev", prev);
+        }
+        if (next != null) {
+            params.put("next", next);
+        }
+        if (limit != null) {
+            params.put("limit", limit);
+        }
+        if (pos != null) {
+            params.put("pos", pos.toString());
+        }
+        if (update != null) {
+            params.put("update", update);
+        }
+        if (sync != null) {
+            params.put("synchronized", sync);
+        }
+        return apiRequest(HttpMethod.GET, params, null,  organizationId, applicationId,
+                "queues", normalizeQueuePath(path));
+    }
+
+    public ApiResponse addSubscriber(String publisherQueue,
+            String subscriberQueue) {
+        return apiRequest(HttpMethod.POST, null, null, organizationId,  applicationId, "queues",
+                normalizeQueuePath(publisherQueue), "subscribers",
+                normalizeQueuePath(subscriberQueue));
+    }
+
+    public ApiResponse removeSubscriber(String publisherQueue,
+            String subscriberQueue) {
+        return apiRequest(HttpMethod.DELETE, null, null, organizationId,  applicationId,
+                "queues", normalizeQueuePath(publisherQueue), "subscribers",
+                normalizeQueuePath(subscriberQueue));
+    }
+
+    private class QueueQuery implements Query {
+        final HttpMethod method;
+        final Map<String, Object> params;
+        final Object data;
+        final String queuePath;
+        final ApiResponse response;
+
+        private QueueQuery(ApiResponse response, HttpMethod method,
+                Map<String, Object> params, Object data, String queuePath) {
+            this.response = response;
+            this.method = method;
+            this.params = params;
+            this.data = data;
+            this.queuePath = normalizeQueuePath(queuePath);
+        }
+
+        private QueueQuery(ApiResponse response, QueueQuery q) {
+            this.response = response;
+            method = q.method;
+            params = q.params;
+            data = q.data;
+            queuePath = q.queuePath;
+        }
+
+        /**
+         * @return the api response of the last request
+         */
+        public ApiResponse getResponse() {
+            return response;
+        }
+
+        /**
+         * @return true if the server indicates more results are available
+         */
+        public boolean more() {
+            if ((response != null) && (response.getCursor() != null)
+                    && (response.getCursor().length() > 0)) {
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Performs a request for the next set of results
+         * 
+         * @return query that contains results and where to get more from.
+         */
+        public Query next() {
+            if (more()) {
+                Map<String, Object> nextParams = null;
+                if (params != null) {
+                    nextParams = new HashMap<String, Object>(params);
+                } else {
+                    nextParams = new HashMap<String, Object>();
+                }
+                nextParams.put("start", response.getCursor());
+                ApiResponse nextResponse = apiRequest(method, nextParams, data,
+                        queuePath);
+                return new QueueQuery(nextResponse, this);
+            }
+            return null;
+        }
+
+    }
+
+    public Query queryQueuesRequest(HttpMethod method,
+            Map<String, Object> params, Object data, String queuePath) {
+        ApiResponse response = apiRequest(method, params, data, queuePath);
+        return new QueueQuery(response, method, params, data, queuePath);
+    }
+
+}