http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/21b60593/sdks/android/src/main/java/org/apache/usergrid/android/sdk/UGClient.java
----------------------------------------------------------------------
diff --git 
a/sdks/android/src/main/java/org/apache/usergrid/android/sdk/UGClient.java 
b/sdks/android/src/main/java/org/apache/usergrid/android/sdk/UGClient.java
new file mode 100755
index 0000000..61b069f
--- /dev/null
+++ b/sdks/android/src/main/java/org/apache/usergrid/android/sdk/UGClient.java
@@ -0,0 +1,3160 @@
+package org.apache.usergrid.android.sdk;
+
+import static org.apache.usergrid.android.sdk.utils.ObjectUtils.isEmpty;
+import static org.apache.usergrid.android.sdk.utils.UrlUtils.addQueryParams;
+import static org.apache.usergrid.android.sdk.utils.UrlUtils.encodeParams;
+import static org.apache.usergrid.android.sdk.utils.UrlUtils.path;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Date;
+
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationListener;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Log;
+
+import org.apache.usergrid.android.sdk.URLConnectionFactory;
+import org.apache.usergrid.android.sdk.callbacks.ApiResponseCallback;
+import org.apache.usergrid.android.sdk.callbacks.ClientAsyncTask;
+import org.apache.usergrid.android.sdk.callbacks.GroupsRetrievedCallback;
+import org.apache.usergrid.android.sdk.callbacks.QueryResultsCallback;
+import org.apache.usergrid.android.sdk.entities.Activity;
+import org.apache.usergrid.android.sdk.entities.Collection;
+import org.apache.usergrid.android.sdk.entities.Device;
+import org.apache.usergrid.android.sdk.entities.Entity;
+import org.apache.usergrid.android.sdk.entities.Group;
+import org.apache.usergrid.android.sdk.entities.Message;
+import org.apache.usergrid.android.sdk.entities.User;
+import org.apache.usergrid.android.sdk.response.ApiResponse;
+import org.apache.usergrid.android.sdk.utils.DeviceUuidFactory;
+import org.apache.usergrid.android.sdk.utils.JsonUtils;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+
+
+/**
+ * The UGClient class for accessing the Usergrid API. Start by instantiating 
this
+ * class though the appropriate constructor. Most calls to the API will be 
handled
+ * by the methods in this class.
+ * 
+ * @see org.apache.usergrid.android.sdk.UGClient
+ * @see <a 
href="http://apigee.com/docs/app-services/content/installing-apigee-sdk-android";>Usergrid
 SDK install guide</a>
+ */
+public class UGClient {
+
+    /**
+     * Most current version of the Usergrid Android SDK
+     */
+    public static final String SDK_VERSION  = "0.0.8";
+    /**
+     * Platform type of this SDK
+     */
+    public static final String SDK_TYPE     = "Android";
+
+    /**
+     * @y.exclude
+     */
+    public static final String OPTION_KEY_BASE_URL = "baseURL";
+
+    /**
+     * @y.exclude
+     */
+    public static boolean FORCE_PUBLIC_API = false;
+
+    /** 
+     * Public API
+     */
+    public static String PUBLIC_API_URL = "https://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;
+
+    /**
+     * Standard HTTP methods use in generic request methods
+     * @see apiRequest 
+     * @see doHttpRequest
+     */
+    protected static final String HTTP_METHOD_DELETE = "DELETE";
+    /**
+     * Standard HTTP methods use in generic request methods
+     * @see apiRequest 
+     * @see doHttpRequest
+     */
+    protected static final String HTTP_METHOD_GET    = "GET";
+    /**
+     * Standard HTTP methods use in generic request methods
+     * @see apiRequest 
+     * @see doHttpRequest
+     */
+    protected static final String HTTP_METHOD_POST   = "POST";
+    /**
+     * Standard HTTP methods use in generic request methods
+     * @see apiRequest 
+     * @see doHttpRequest
+     */
+    protected static final String HTTP_METHOD_PUT    = "PUT";
+    
+    protected static final String LOGGING_TAG    = "UGCLIENT";
+
+    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;
+    private URLConnectionFactory urlConnectionFactory = null;
+    
+    private LocationManager locationManager;
+    private UUID deviceID;
+    
+    /**
+    * Interface for EntityQuery and QueueQuery
+    */
+    public interface Query {
+
+        public ApiResponse getResponse();
+
+        public boolean more();
+
+        public Query next();
+
+    }
+
+    /**
+     * @y.exclude
+     */
+    public static boolean isUuidValid(UUID uuid) {
+       return( uuid != null );
+    }
+
+    protected static String arrayToDelimitedString(String[] arrayOfStrings, 
String delimiter) {
+       StringBuilder sb = new StringBuilder();
+       
+       for( int i = 0; i < arrayOfStrings.length; ++i ) {
+               if( i > 0 ) {
+                       sb.append(delimiter);
+               }
+               
+               sb.append(arrayOfStrings[i]);
+       }
+       
+       return sb.toString();
+    }
+    
+    protected static String[] tokenizeToStringArray(String str, String 
delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
+       if (str == null) {
+               return null;
+       }
+
+       StringTokenizer st = new StringTokenizer(str, delimiters);
+       
+       int numTokens = st.countTokens();
+       List<String> listTokens;
+       
+       if( numTokens > 0 ) {
+
+               listTokens = new ArrayList<String>(numTokens);
+
+               while (st.hasMoreTokens()) {
+
+                       String token = st.nextToken();
+
+                       if (trimTokens) {
+                               token = token.trim();
+                       }
+
+                       if (!ignoreEmptyTokens || token.length() > 0) {
+                               listTokens.add(token);
+                       }
+               }
+       } else {
+               listTokens = new ArrayList<String>();
+       }
+       
+       return listTokens.toArray(new String[listTokens.size()]);
+    }
+    
+
+    /****************** CONSTRUCTORS ***********************/
+    /****************** CONSTRUCTORS ***********************/
+
+    /**
+     * @y.exclude
+     */
+    public UGClient() {
+        init();
+    }
+
+    /**
+     * Instantiate a data client for a specific app. This is used to call most 
+     * SDK methods.
+     * 
+     * @param  organizationId  the Usergrid organization name
+     * @param  applicationId  the Usergrid application id or name
+     */
+    public UGClient(String organizationId, String applicationId) {
+        init();
+        this.organizationId = organizationId;
+        this.applicationId = applicationId;        
+    }
+
+    /**
+     * Instantiate a data client for a specific app with a base URL other than 
the default
+     * api.usergrid.com. This is used to call most SDK methods.
+     * 
+     * @param  organizationId  the Usergrid organization name
+     * @param  applicationId  the Usergrid application id or name
+     * @param  baseURL  the base URL to use for all API calls
+     */
+    public UGClient(String organizationId, String applicationId, String 
baseURL) {
+        init();
+        this.organizationId = organizationId;
+        this.applicationId = applicationId;
+        
+        if( baseURL != null ) {
+               this.setApiUrl(baseURL);
+        }
+    }
+
+    public void init() {
+    }
+    
+
+    /****************** ACCESSORS/MUTATORS ***********************/
+    /****************** ACCESSORS/MUTATORS ***********************/
+
+    /**
+     * Sets a new URLConnectionFactory object in the UGClient
+     *
+     * @param  urlConnectionFactory  a new URLConnectionFactory object
+     * @y.exclude
+     */
+    public void setUrlConnectionFactory(URLConnectionFactory 
urlConnectionFactory) {
+       this.urlConnectionFactory = urlConnectionFactory;
+    }
+
+    /**
+     * @return the Usergrid API url (default: http://api.usergrid.com)
+     */
+    public String getApiUrl() {
+        return apiUrl;
+    }
+
+    /**
+     * Sets the base URL for API requests
+     *
+     * @param apiUrl the API base url to be set (default: 
http://api.usergrid.com)
+     */
+    public void setApiUrl(String apiUrl) {
+        this.apiUrl = apiUrl;
+    }
+
+    /**
+     * Sets the base URL for API requests and returns the updated UGClient 
object
+     *
+     * @param apiUrl the Usergrid API url (default: http://api.usergrid.com)
+     * @return UGClient object for method call chaining
+     */
+    public UGClient withApiUrl(String apiUrl) {
+        this.apiUrl = apiUrl;
+        return this;
+    }
+    
+    
+    /**
+     * Sets the Usergrid organization ID and returns the UGClient object
+     *
+     * @param  organizationId  the organizationId to set
+     * @return  the updated UGClient object
+     */
+    public UGClient withOrganizationId(String organizationId){
+        this.organizationId = organizationId;
+        return this;
+    }
+    
+    
+
+    /**
+     * Gets the current Usergrid organization ID set in the UGClient
+     *
+     * @return the current organizationId
+     */
+    public String getOrganizationId() {
+        return organizationId;
+    }
+
+    /**
+     * Sets the Usergrid organization ID
+     *
+     * @param  organizationId  the organizationId to set     
+     */
+    public void setOrganizationId(String organizationId) {
+        this.organizationId = organizationId;
+    }
+
+    /**
+     * Gets the current Usergrid application ID set in the UGClient
+     *
+     * @return the current organizationId or name
+     */
+    public String getApplicationId() {
+        return applicationId;
+    }
+
+    /**
+     * Sets the Usergrid application Id
+     *
+     * @param  applicationId  the application id or name
+     */
+    public void setApplicationId(String applicationId) {
+        this.applicationId = applicationId;
+    }
+   
+
+    /**
+     * Sets the Usergrid application ID and returns the UGClient object
+     *
+     * @param  applicationId  the application ID to set
+     * @return  the updated UGClient object
+     */
+    public UGClient withApplicationId(String applicationId) {
+        this.applicationId = applicationId;
+        return this;
+    }
+
+    /**
+     * Gets the application (not organization) client ID credential for making 
calls as the 
+     * application-owner. Not safe for most mobile use. 
+     * @return the client id 
+     */
+    public String getClientId() {
+        return clientId;
+    }
+
+    /**
+     * Sets the application (not organization) client ID credential, used for 
making 
+     * calls as the application-owner. Not safe for most mobile use.
+     * @param clientId the client id 
+     */
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    /**
+     * Sets the client ID credential in the UGClient object. Not safe for most 
mobile use.
+     *
+     * @param clientId the client key id
+     * @return UGClient object for method call chaining
+     */
+    public UGClient withClientId(String clientId) {
+        this.clientId = clientId;
+        return this;
+    }
+
+    /**
+     * Gets the application (not organization) client secret credential for 
making calls as the 
+     * application-owner. Not safe for most mobile use. 
+     * @return the client secret 
+     */
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    /**
+     * Sets the application (not organization) client secret credential, used 
for making 
+     * calls as the application-owner. Not safe for most mobile use.
+     *
+     * @param clientSecret the client secret 
+     */
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    /**
+     * Sets the client secret credential in the UGClient object. Not safe for 
most mobile use.
+     *
+     * @param clientSecret the client secret
+     * @return UGClient object for method call chaining
+     */
+    public UGClient withClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+        return this;
+    }
+
+    /**
+     * Gets the UUID of the logged-in user after a successful authorizeAppUser 
request
+     * @return the UUID of the logged-in user
+     */
+    public User getLoggedInUser() {
+        return loggedInUser;
+    }
+
+    /**
+     * Sets the UUID of the logged-in user. Usually not set by host application
+     * @param loggedInUser the UUID of the logged-in user
+     */
+    public void setLoggedInUser(User loggedInUser) {
+        this.loggedInUser = loggedInUser;
+    }
+
+    /**
+     * Gets the OAuth2 access token for the current logged-in user after a 
+     * successful authorize request
+     *
+     * @return the OAuth2 access token
+     */
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    /**
+     * Saves the OAuth2 access token in the UGClient after a successful 
authorize
+     * request. Usually not set by host application.
+     *
+     * @param accessToken an OAuth2 access token
+     */
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    /**
+     * Gets the current organization from UGClient 
+     *
+     * @return the currentOrganization
+     */
+    public String getCurrentOrganization() {
+        return currentOrganization;
+    }
+
+    /**     
+     * Sets the current organizanization from UGClient 
+     *
+     * @param currentOrganization The organization this data client should use.
+     */
+    public void setCurrentOrganization(String currentOrganization) {
+        this.currentOrganization = currentOrganization;
+    }
+
+    /****************** LOGGING ***********************/
+    /****************** LOGGING ***********************/
+
+
+    /**
+     * Logs a trace-level logging message with tag 'DATA_CLIENT'
+     *
+     * @param   logMessage  the message to log
+     */
+    public void logTrace(String logMessage) {
+        if( logMessage != null ) {
+            Log.v(LOGGING_TAG,logMessage);
+        }
+    }
+    
+    /**
+     * Logs a debug-level logging message with tag 'DATA_CLIENT'
+     *
+     * @param   logMessage  the message to log
+     */
+    public void logDebug(String logMessage) {
+        if( logMessage != null ) {
+            Log.d(LOGGING_TAG,logMessage);
+        }
+    }
+    
+    /**
+     * Logs an info-level logging message with tag 'DATA_CLIENT'
+     *
+     * @param   logMessage  the message to log
+     */
+    public void logInfo(String logMessage) {
+        if( logMessage != null ) {
+            Log.i(LOGGING_TAG,logMessage);
+        }
+    }
+    
+    /**
+     * Logs a warn-level logging message with tag 'DATA_CLIENT'
+     *
+     * @param   logMessage  the message to log
+     */
+    public void logWarn(String logMessage) {
+        if( logMessage != null ) {
+            Log.w(LOGGING_TAG,logMessage);
+        }
+    }
+    
+    /**
+     * Logs an error-level logging message with tag 'DATA_CLIENT'
+     *
+     * @param   logMessage  the message to log
+     */
+    public void logError(String logMessage) {
+        if( logMessage != null ) {
+            Log.e(LOGGING_TAG,logMessage);
+        }
+    }
+
+    /**
+     * Logs a debug-level logging message with tag 'DATA_CLIENT'
+     *
+     * @param   logMessage  the message to log
+     */
+    public void writeLog(String logMessage) {
+        if( logMessage != null ) {
+            //TODO: do we support different log levels in this class?
+            Log.d(LOGGING_TAG, logMessage);
+        }
+    }
+    
+    /****************** API/HTTP REQUEST ***********************/
+    /****************** API/HTTP REQUEST ***********************/
+
+    /**
+     *  Forms and initiates a raw synchronous http request and processes the 
response.
+     *
+     *  @param  httpMethod the HTTP method in the format: 
+     *      HTTP_METHOD_<method_name> (e.g. HTTP_METHOD_POST)
+     *  @param  params the URL parameters to append to the request URL
+     *  @param  data the body of the request
+     *  @param  segments  additional URL path segments to append to the 
request URL 
+     *  @return  ApiResponse object
+     */
+       public ApiResponse doHttpRequest(String httpMethod, Map<String, Object> 
params, Object data, String... segments) {
+               
+        ApiResponse response = null;
+               OutputStream out = null;
+               InputStream in = null;
+               HttpURLConnection conn = null;
+               
+               String urlAsString = path(apiUrl, segments);
+               
+               try {
+               String contentType = "application/json";
+               if (httpMethod.equals(HTTP_METHOD_POST) && isEmpty(data) && 
!isEmpty(params)) {
+                   data = encodeParams(params);
+                   contentType = "application/x-www-form-urlencoded";
+               } else {
+                   urlAsString = addQueryParams(urlAsString, params);
+               }
+
+                       //logTrace("Invoking " + httpMethod + " to '" + 
urlAsString + "'");
+
+                       URL url = new URL(urlAsString);
+                       conn = (HttpURLConnection) url.openConnection();
+            
+                       conn.setRequestMethod(httpMethod);
+                       conn.setRequestProperty("Content-Type", contentType);
+                       conn.setUseCaches(false);
+                       
+                       if  ((accessToken != null) && (accessToken.length() > 
0)) {
+                               String authStr = "Bearer " + accessToken;
+                               conn.setRequestProperty("Authorization", 
authStr);
+                       }
+
+                       conn.setDoInput(true);
+                       
+               if (httpMethod.equals(HTTP_METHOD_POST) || 
httpMethod.equals(HTTP_METHOD_PUT)) {
+                   if (isEmpty(data)) {
+                       data = JsonNodeFactory.instance.objectNode();
+                   }
+                   
+                   String dataAsString = null;
+                   
+                   if ((data != null) && (!(data instanceof String))) {
+                       ObjectMapper objectMapper = new ObjectMapper();
+                               
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+                               dataAsString = 
objectMapper.writeValueAsString(data);
+                   } else {
+                       dataAsString = (String) data;
+                   }
+                   
+                       //logTrace("Posting/putting data: '" + dataAsString + 
"'");
+
+                               byte[] dataAsBytes = dataAsString.getBytes();
+
+                               conn.setRequestProperty("Content-Length", 
Integer.toString(dataAsBytes.length));
+                               conn.setDoOutput(true);
+
+                               out = conn.getOutputStream();
+                               out.write(dataAsBytes);
+                               out.flush();
+                               out.close();
+                               out = null;
+               }
+               
+                       in = conn.getInputStream();
+                       if( in != null ) {
+                               BufferedReader reader = new BufferedReader(new 
InputStreamReader(in));
+                               StringBuilder sb = new StringBuilder();
+                               String line;
+                               
+                               while( (line = reader.readLine()) != null ) {
+                                       sb.append(line);
+                                       sb.append('\n');
+                               }
+                               
+                               String responseAsString = sb.toString();
+
+                               //logTrace("response from server: '" + 
responseAsString + "'");
+                ObjectMapper objectMapper = new ObjectMapper();
+                
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
+                
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+                response = (ApiResponse) 
objectMapper.readValue(responseAsString, ApiResponse.class);
+                               response.setRawResponse(responseAsString);
+
+                               response.setUGClient(this);
+                       } else {
+                               response = null;
+                               logTrace("no response body from server");
+                       }
+
+                       //final int responseCode = conn.getResponseCode();
+                       //logTrace("responseCode from server = " + 
responseCode);
+               }
+               catch(Exception e) {
+                       logError("Error " + httpMethod + " to '" + urlAsString 
+ "'" );
+                       if( e != null ) {
+                               e.printStackTrace();
+                               logError(e.getLocalizedMessage());
+                       }
+                       response = null;
+               }
+               catch(Throwable t) {
+                       logError("Error " + httpMethod + " to '" + urlAsString 
+ "'" );
+                       if( t != null ) {
+                               t.printStackTrace();
+                               logError(t.getLocalizedMessage());
+                       }
+                       response = null;
+               }
+               finally {
+                       try {
+                               if( out != null ) {
+                                       out.close();
+                               }
+                       
+                               if( in != null ) {
+                                       in.close();
+                               }
+                               
+                               if( conn != null ) {
+                                       conn.disconnect();
+                               }
+                       } catch(Exception ignored) {
+                       }
+               }
+               
+           return response;
+       }
+
+
+    /**
+     * High-level synchronous API request. Implements the http request
+     * for most SDK methods by calling 
+     * {@link #doHttpRequest(String,Map,Object,String...)}
+     * 
+     *  @param  httpMethod the HTTP method in the format: 
+     *      HTTP_METHOD_<method_name> (e.g. HTTP_METHOD_POST)
+     *  @param  params the URL parameters to append to the request URL
+     *  @param  data the body of the request
+     *  @param  segments  additional URL path segments to append to the 
request URL 
+     *  @return  ApiResponse object
+     */
+    public ApiResponse apiRequest(String httpMethod,
+            Map<String, Object> params, Object data, String... segments) {
+        ApiResponse response = null;
+        
+        response = doHttpRequest(httpMethod, params, data, segments);
+        
+        if( (response == null) ) {
+               logError("doHttpRequest returned null");
+        }
+        
+        return response;
+    }
+
+    protected void assertValidApplicationId() {
+        if (isEmpty(applicationId)) {
+            throw new IllegalArgumentException("No application id specified");
+        }
+    }
+
+    /****************** ROLES/PERMISSIONS ***********************/
+    /****************** ROLES/PERMISSIONS ***********************/
+
+    /**
+     * Assigns permissions to the specified user, group, or role.
+     * 
+     * @param entityType the entity type of the entity the permissions are 
being assigned to. 'user', 'group' and 'role' are valid.
+     * @param entityID the UUID of 'name' property of the entity the 
permissions are being assigned to.
+     * @param permissions a comma-separated list of the permissions to be 
assigned in the format: <operations>:<path>, e.g. get, put, post, delete: /users
+     * @throws IllegalArgumentException thrown if an entityType other than 
'group' or 'user' is passed to the method
+     * @return ApiResponse object
+     */
+    public ApiResponse assignPermissions(String entityType, String entityID, 
String permissions) {
+
+        if (!entityType.substring(entityType.length() - 1 ).equals("s")) {
+            entityType += "s";
+        }
+        
+        if (!validateTypeForPermissionsAndRoles(entityType, "permission")) {
+            throw new IllegalArgumentException("Permissions can only be 
assigned to group, user, or role entities");
+        }
+
+        Map<String, Object> data = new HashMap<String, Object>();
+        if (permissions != null){
+            data.put("permission", permissions);
+        }
+
+        return apiRequest(HTTP_METHOD_POST, null, data, organizationId,  
applicationId, entityType,
+                entityID, "permissions");
+
+    }
+
+    /**
+     * Assigns permissions to the specified user, group, or role. Executes 
asynchronously in
+     * background and the callbacks are called in the UI thread.
+     * 
+     * @param entityType the entity type of the entity the permissions are 
being assigned to. 'user', 'group' and 'role' are valid.
+     * @param entityID the UUID of 'name' property of the entity the 
permissions are being assigned to.
+     * @param permissions a comma-separated list of the permissions to be 
assigned in the format: <operations>:<path>, e.g. get, put, post, delete: 
/users     
+     * @param  callback  an ApiResponseCallback to handle the async response
+     */
+    public void assignPermissionsAsync(final String entityType,
+            final String entityID, final String permissions, final 
ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return assignPermissions(entityType, entityID, permissions);
+            }
+        }).execute();
+    }
+
+    /**
+     * Removes permissions from the specified user, group or role.
+     * 
+     * @param entityType the entity type of the entity the permissions are 
being removed from. 'user', 'group' and 'role' are valid.
+     * @param entityID the UUID of 'name' property of the entity the 
permissions are being removed from.
+     * @param permissions a comma-separated list of the permissions to be 
removed in the format: <operations>:<path>, e.g. get, put, post, delete: /users
+     * @throws IllegalArgumentException thrown if an entityType other than 
'group' or 'user' is passed to the method
+     * @return ApiResponse object
+     */
+    public ApiResponse removePermissions(String entityType, String entityID, 
String permissions) {
+
+        if (!validateTypeForPermissionsAndRoles(entityType, "permission")) {
+            throw new IllegalArgumentException("Permissions can only be 
assigned to group, user, or role entities");
+        }
+
+        Map<String, Object> params = new HashMap<String, Object>();
+        if (permissions != null){
+            params.put("permission", permissions);
+        }
+        
+        return apiRequest(HTTP_METHOD_DELETE, params, null, organizationId,  
applicationId, entityType,
+                entityID, "permissions");
+
+    }
+
+    /**
+     * Removes permissions from the specified user, group or role. Executes 
asynchronously in
+     * background and the callbacks are called in the UI thread.
+     * 
+     * @param entityType the entity type of the entity the permissions are 
being removed from. 'user', 'group', and 'role' are valid.
+     * @param entityID the UUID of 'name' property of the entity the 
permissions are being removed from.
+     * @param permissions a comma-separated list of the permissions to be 
removed in the format: <operations>:<path>, e.g. get, put, post, delete: /users 
    
+     * @param  callback  an ApiResponseCallback to handle the async response
+     */
+    public void removePermissionsAsync(final String entityType,
+            final String entityID, final String permissions, final 
ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return removePermissions(entityType, entityID, permissions);
+            }
+        }).execute();
+    }
+
+    /**
+     * Creates a new role and assigns permissions to it.
+     * 
+     * @param roleName the name of the new role
+     * @param permissions a comma-separated list of the permissions to be 
assigned in the format: <operations>:<path>, e.g. get, put, post, delete: /users
+     * @return ApiResponse object
+     */
+    public ApiResponse createRole(String roleName, String permissions) {
+
+        Map<String, Object> properties = new HashMap<String, Object>();
+        properties.put("type", "role");
+        properties.put("name", roleName);
+
+        ApiResponse response = this.createEntity(properties);
+
+        String uuid = null;
+
+        if (response.getEntityCount() == 1){
+            uuid = response.getFirstEntity().getUuid().toString();
+        }
+
+        return assignPermissions("role", uuid, permissions);
+
+    }
+
+    /**
+     * Creates a new role and assigns permissions to it.
+     * 
+     * @param roleName the name of the new role
+     * @param permissions a comma-separated list of the permissions to be 
assigned in the format: <operations>:<path>, e.g. get, put, post, delete: /users
+     * @param  callback  an ApiResponseCallback to handle the async response   
  
+     */
+    public void createRoleAsync(final String roleName, final String 
permissions, 
+                  final ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return createRole(roleName, permissions);
+            }
+        }).execute();
+    }
+
+    /**
+     * Assigns a role to a user or group entity.
+     * 
+     * @param roleName the name of the role to be assigned to the entity
+     * @param entityType the entity type of the entity the role is being 
assigned to. 'user' and 'group' are valid.
+     * @param entityID the UUID or 'name' property of the entity the role is 
being assigned to.     
+     * @throws IllegalArgumentException thrown if an entityType other than 
'group' or 'user' is passed to the method
+     * @return ApiResponse object
+     */
+    public ApiResponse assignRole(String roleName, String entityType, String 
entityID) {
+
+        if (!entityType.substring(entityType.length() - 1 ).equals("s")) {
+            entityType += "s";
+        }
+
+        if (!validateTypeForPermissionsAndRoles(entityType, "role")) {
+            throw new IllegalArgumentException("Permissions can only be 
assigned to a group or user");
+        }
+
+        return apiRequest(HTTP_METHOD_POST, null, null, organizationId,  
applicationId, "roles", roleName, 
+                      entityType, entityID);
+
+    }
+
+    /**
+     * Assigns a role to a user or group entity. Executes asynchronously in
+     * background and the callbacks are called in the UI thread.
+     * 
+     * @param roleName the name of the role to be assigned to the entity
+     * @param entityType the entity type of the entity the role is being 
assigned to. 'user' and 'group' are valid.
+     * @param entityID the UUID or 'name' property of the entity the role is 
being removed from.     
+     * @param callback  an ApiResponseCallback to handle the async response
+     */
+    public void assignRoleAsync(final String roleName, final String entityType,
+            final String entityID, final ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return assignRole(roleName, entityType, entityID);
+            }
+        }).execute();
+    }
+
+    /**
+     * Removes a role from a user or group entity.
+     * 
+     * @param roleName the name of the role to be removed from the entity
+     * @param entityType the entity type of the entity the role is being 
removed from. 'user' and 'group' are valid.
+     * @param entityID the UUID or 'name' property of the entity the role is 
being removed from.     
+     * @throws IllegalArgumentException thrown if an entityType other than 
'group' or 'user' is passed to the method
+     * @return ApiResponse object
+     */
+    public ApiResponse removeRole(String roleName, String entityType, String 
entityID) {
+
+        if (!entityType.substring(entityType.length() - 1 ).equals("s")) {
+            entityType += "s";
+        }
+
+        if (!validateTypeForPermissionsAndRoles(entityType, "role")) {
+            throw new IllegalArgumentException("Permissions can only be 
removed from a group or user");
+        }
+
+        return apiRequest(HTTP_METHOD_DELETE, null, null, organizationId,  
applicationId, "roles", roleName, 
+                      entityType, entityID);
+
+    }
+
+    /**
+     * Removes a role from a user or group entity. Executes asynchronously in
+     * background and the callbacks are called in the UI thread.
+     * 
+     * @param roleName the name of the role to be removed from the entity
+     * @param entityType the entity type of the entity the role is being 
removed from. 'user' and 'group' are valid.
+     * @param entityID the UUID or 'name' property of the entity the role is 
being removed from.     
+     * @param callback  an ApiResponseCallback to handle the async response
+     */
+    public void removeRoleAsync(final String roleName, final String entityType,
+            final String entityID, final ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return removeRole(roleName, entityType, entityID);
+            }
+        }).execute();
+    }
+
+    /**
+     * Checks if a permission or role can be assigned to an entity
+     * @y.exclude
+     */
+    private Boolean validateTypeForPermissionsAndRoles(String type, String 
permissionOrRole){
+        ArrayList<String> validTypes = new ArrayList<String>();        
+        validTypes.add("groups");        
+        validTypes.add("users");
+        
+        if (permissionOrRole.equals("permission")){
+            validTypes.add("roles");
+        }
+
+        return validTypes.contains(type);
+    }
+
+    /****************** LOG IN/LOG OUT/OAUTH ***********************/
+    /****************** LOG IN/LOG OUT/OAUTH ***********************/
+
+    /**
+     * Logs the user in and get a valid access token.
+     * 
+     * @param usernameOrEmail the username or email associated with the user 
entity in Usergrid
+     * @param password the user's Usergrid password
+     * @return non-null ApiResponse if request succeeds, check getError() for
+     *         "invalid_grant" to see if access is denied.
+     */
+    public ApiResponse authorizeAppUser(String usernameOrEmail, String 
password) {
+        validateNonEmptyParam(usernameOrEmail, "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", usernameOrEmail);
+        formData.put("password", password);
+        ApiResponse response = apiRequest(HTTP_METHOD_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;
+            logInfo("authorizeAppUser(): Access token: " + accessToken);
+        } else {
+            logInfo("authorizeAppUser(): Response: " + response);
+        }
+        return response;
+    }
+
+       /**
+        * Log the user in and get a valid access token. Executes 
asynchronously in
+        * background and the callbacks are called in the UI thread.
+        * 
+        * @param  usernameOrEmail  the username or email associated with the 
user entity in Usergrid
+     * @param  password  the users Usergrid password
+     * @param  callback  an ApiResponseCallback to handle the async response
+        */
+       public void authorizeAppUserAsync(final String usernameOrEmail,
+                       final String password, final ApiResponseCallback 
callback) {
+               (new ClientAsyncTask<ApiResponse>(callback) {
+                       @Override
+                       public ApiResponse doTask() {
+                               return authorizeAppUser(usernameOrEmail, 
password);
+                       }
+               }).execute();
+       }
+
+    /**
+     * Change the password for the currently logged in user. You must supply 
the
+     * old password and the new password.
+     * 
+     * @param username the username or email address associated with the user 
entity in Usergrid
+     * @param oldPassword the user's old password
+     * @param newPassword the user's new password
+     * @return ApiResponse object
+     */
+    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(HTTP_METHOD_POST, null, data, organizationId,  
applicationId, "users",
+                username, "password");
+
+    }
+
+    public void changePasswordAsync(final String username, final String 
oldPassword,
+            final String newPassword, final ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return changePassword(username, oldPassword, newPassword);
+            }
+        }).execute();
+    }
+
+    /**
+     * Log the user in with their numeric pin-code and get a valid access 
token.
+     * 
+     * @param  email  the email address associated with the user entity in 
Usergrid
+     * @param  pin  the pin associated with the user entity in Usergrid
+     * @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(HTTP_METHOD_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;
+            logInfo("authorizeAppUser(): Access token: " + accessToken);
+        } else {
+            logInfo("authorizeAppUser(): Response: " + response);
+        }
+        return response;
+    }
+
+       /**
+        * 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  the email address associated with the user entity in 
Usergrid
+     * @param  pin  the pin associated with the user entity in Usergrid     
+     * @param callback A callback for the async response.
+        */
+       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 app in with it's application (not organization) 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  the Usergrid application's client ID 
+     * @param  clientSecret  the Usergrid application's client secret
+     * @param  callback  an ApiResponseCallback to handle the async response
+     */
+    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();
+    }
+
+    private void validateNonEmptyParam(Object param, String paramName) {
+        if ( isEmpty(param) ) {
+            throw new IllegalArgumentException(paramName + " cannot be null or 
empty");
+        }
+    }
+
+    /**
+     * Log the user in with their Facebook access token retrieved via Facebook
+     * OAuth. Sets the user's identifier and Usergrid OAuth2 access token in 
UGClient 
+     * if successfully authorized.
+     * 
+     * @param fb_access_token the valid OAuth token returned by Facebook     
+     * @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(HTTP_METHOD_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;
+            logInfo("authorizeAppUserViaFacebook(): Access token: "
+                    + accessToken);
+        } else {
+            logInfo("authorizeAppUserViaFacebook(): Response: "
+                    + response);
+        }
+        return response;
+    }
+    
+       /**
+     * Log the user in with their Facebook access token retrieved via Facebook
+     * OAuth. Sets the user's identifier and Usergrid OAuth2 access token in 
UGClient 
+     * if successfully authorized. Executes asynchronously in background and 
the 
+     * callbacks are called in the UI thread.
+     * 
+     * @param  fb_access_token the valid OAuth token returned by Facebook 
+     * @param  callback  an ApiResponseCallback to handle the async response   
       
+     */
+       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 out a user and destroy the access token currently stored in 
UGClient 
+     * on the server and in the UGClient.
+     * 
+     * @param  username  The username to be logged out
+     * @return  non-null ApiResponse if request succeeds
+     */
+    public ApiResponse logOutAppUser(String username) {
+        String token = getAccessToken();
+        Map<String,Object> params = new HashMap<String,Object>();
+        params.put("token",token);
+        ApiResponse response = apiRequest(HTTP_METHOD_PUT, params, null,
+                organizationId,  applicationId, 
"users",username,"revoketoken?");
+        if (response == null) {
+            return response;
+        } else {
+            logInfo("logoutAppUser(): Response: " + response);
+            setAccessToken(null);
+        }
+        return response;
+    }
+
+    /**
+     * Log out a user and destroy the access token currently stored in 
UGClient 
+     * on the server and in the UGClient.
+     * Executes asynchronously in background and the callbacks are called in 
the
+     * UI thread.
+     * 
+     * @param  username  The username to be logged out
+     * @param  callback  an ApiResponseCallback to handle the async response   
  
+     */
+    public void logOutAppUserAsync(final String username, final 
ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return logOutAppUser(username);
+            }
+        }).execute();
+    }
+
+   /**
+     * Destroy a specific user token on the server. The token will also be 
cleared 
+     * from the UGClient instance, if it matches the token provided.
+     * 
+     * @param username The username to be logged out
+     * @param token The access token to be destroyed on the server
+     * @return  non-null ApiResponse if request succeeds
+     */
+    public ApiResponse logOutAppUserForToken(String username, String token) {  
              
+        Map<String,Object> params = new HashMap<String,Object>();
+        params.put("token",token);
+        ApiResponse response = apiRequest(HTTP_METHOD_PUT, params, null,
+                organizationId,  applicationId, 
"users",username,"revoketoken?");
+        if (response == null) {
+            return response;
+        } else {
+            logInfo("logoutAppWithTokenUser(): Response: " + response);
+            if (token.equals(getAccessToken())) {
+                setAccessToken(null);
+            }
+        }
+        return response;
+    }
+
+    /**
+     * Destroy a specific user token on the server. The token will also be 
cleared 
+     * from the UGClient instance, if it matches the token provided.
+     * Executes asynchronously in background and the callbacks are called in 
the UI thread.
+     * 
+     * @param  username  The username to be logged out
+     * @param  token  The access token to be destroyed on the server   
+     * @param callback A callback for the async response  
+     */
+    public void logOutAppUserForTokenAsync(final String username, final String 
token, final ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return logOutAppUserForToken(username, token);
+            }
+        }).execute();
+    }
+
+    /**
+     * Log out a user and destroy all associated tokens on the server.
+     * The token stored in UGClient will also be destroyed.
+     * 
+     * @param  username The username to be logged out
+     * @return  non-null ApiResponse if request succeeds
+     */
+    public ApiResponse logOutAppUserForAllTokens(String username) {
+        ApiResponse response = apiRequest(HTTP_METHOD_PUT, null, null,
+                organizationId,  applicationId, 
"users",username,"revoketokens");
+        if (response == null) {
+            return response;
+        } else {
+            logInfo("logoutAppUserForAllTokens(): Response: " + response);
+            setAccessToken(null);
+        }
+        return response;
+    }
+
+    /**
+     * Log out a user and destroy all associated tokens on the server.
+     * The token stored in UGClient will also be destroyed.
+     * Executes asynchronously in background and the callbacks are called in 
the UI thread.
+     * 
+     * @param  username  The username to be logged out
+     * @param callback A callback for the response
+     */
+    public void logOutAppUserForAllTokensAsync(final String username, final 
ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return logOutAppUserForAllTokens(username);
+            }
+        }).execute();
+    }
+
+    /**
+     * Log the app in with it's application (not organization) client id and 
+     * client secret key. Not recommended for production apps.
+     * 
+     * @param  clientId  the Usergrid application's client ID 
+     * @param  clientSecret  the Usergrid application's client secret     
+     */
+    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(HTTP_METHOD_POST, formData, null,
+                organizationId, applicationId, "token");
+        if (response == null) {
+            return response;
+        }
+        if (!isEmpty(response.getAccessToken())) {
+            loggedInUser = null;
+            accessToken = response.getAccessToken();
+            currentOrganization = null;
+            logInfo("authorizeAppClient(): Access token: "
+                    + accessToken);
+        } else {
+            logInfo("authorizeAppClient(): Response: " + response);
+        }
+        return response;
+    }
+
+
+    /****************** GENERIC ENTITY MANAGEMENT ***********************/
+    /****************** GENERIC ENTITY MANAGEMENT ***********************/
+
+    /**
+     * 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(HTTP_METHOD_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(HTTP_METHOD_POST, null, properties,
+                organizationId, applicationId, 
properties.get("type").toString());
+        return response;
+    }
+    
+    /**
+        * Create a new entity on the server. Executes asynchronously in 
background
+        * and the callbacks are called in the UI thread.
+        * 
+        * @param entity An instance with data to use to create the entity
+        * @param callback A callback for the async response
+        */
+       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 The values to use, with keys as property names and 
values 
+        * as property values
+        * @param callback A callback for the async response
+        */
+       public void createEntityAsync(final Map<String, Object> properties,
+                       final ApiResponseCallback callback) {
+               (new ClientAsyncTask<ApiResponse>(callback) {
+                       @Override
+                       public ApiResponse doTask() {
+                               return createEntity(properties);
+                       }
+               }).execute();
+       }
+       
+       /**
+        * Create a set of entities on the server from an ArrayList. Each item 
in the array
+        * contains a set of properties that define a entity.
+        * 
+        * @param type The type of entities to create.
+        * @param entities A list of maps where keys are entity property names 
and values
+        * are property values.
+        * @return An instance with response data from the server.
+        */
+       public ApiResponse createEntities(String type, ArrayList<Map<String, 
Object>> entities) {
+        assertValidApplicationId();                
+        if (isEmpty(type)) {
+            throw new IllegalArgumentException("Missing entity type");
+        }
+        ApiResponse response = apiRequest(HTTP_METHOD_POST, null, entities,
+                    organizationId, applicationId, type);                      
        
+               return response;        
+    }
+    
+    /**
+        * Create a set of entities on the server from an ArrayList. Each item 
in the array
+        * contains a set of properties that define a entity. Executes 
asynchronously in 
+        * background and the callbacks are called in the UI thread.
+        * 
+        * @param type The type of entities to create.
+        * @param entities A list of maps where keys are entity property names 
and values
+        * are property values.
+        * @param callback A callback for the async response
+        */
+    public void createEntitiesAsync(final String type, final 
ArrayList<Map<String, Object>> entities,
+                       final ApiResponseCallback callback) {
+               (new ClientAsyncTask<ApiResponse>(callback) {
+                       @Override
+                       public ApiResponse doTask() {
+                               return createEntities(type, entities);
+                       }
+               }).execute();
+       }
+
+    /**
+     * Creates an object instance that corresponds to the provided entity type.
+     * Supported object types are Activity, Device, Group, Message, and User.
+     * All other types will return a generic Entity instance with no type 
assigned.
+     *
+     * @param  type  the entity type of which to create an object instance
+     * @return  an object instance that corresponds to the type provided
+    */
+    public Entity createTypedEntity(String type) {
+        Entity entity = null;
+        
+        if( Activity.isSameType(type) ) {
+            entity = new Activity(this);
+        } else if( Device.isSameType(type) ) {
+            entity = new Device(this);
+        } else if( Group.isSameType(type) ) {
+            entity = new Group(this);
+        } else if( Message.isSameType(type) ) {
+            entity = new Message(this);
+        } else if( User.isSameType(type) ) {
+            entity = new User(this);
+        } else {
+            entity = new Entity(this);
+        }
+        
+        return entity;
+    }
+
+    /**
+     * Requests all entities of specified type that match the provided query 
string.
+     *
+     * @param  type  the entity type to be retrieved
+     * @param  queryString  a query string to send with the request
+     * @return  a non-null ApiResponse object if successful
+    */
+    public ApiResponse getEntities(String type,String queryString)
+    {
+        Map<String, Object> params = null;
+
+        if (queryString.length() > 0) {
+            params = new HashMap<String, Object>();
+            params.put("ql", queryString);
+        }
+        
+        return apiRequest(HTTP_METHOD_GET, // method
+                            params, // params
+                            null, // data
+                            organizationId,
+                            applicationId,
+                            type);
+    }
+    
+    /**
+     * Asynchronously requests all entities of specified type that match the 
provided query string.
+     *
+     * @param  type  the entity type to be retrieved
+     * @param  queryString  a query string to send with the request
+     * @param  callback an ApiResponseCallback to handle the async response
+    */
+    public void getEntitiesAsync(final String type,
+            final String queryString, final ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return getEntities(type, queryString);
+            }
+        }).execute();
+    }
+
+    /**
+     * Update an existing entity on the server.
+     * 
+     * @param entityID the entity to update
+     * @param updatedProperties the new properties
+     * @return an ApiResponse with the updated entity in it.
+     */
+    public ApiResponse updateEntity(String entityID, Map<String, Object> 
updatedProperties) {
+       assertValidApplicationId();
+       if (isEmpty(updatedProperties.get("type"))) {
+            throw new IllegalArgumentException("Missing entity type");
+       }
+       ApiResponse response = apiRequest(HTTP_METHOD_PUT, null, 
updatedProperties,
+                       organizationId, applicationId, 
updatedProperties.get("type").toString(), entityID);
+       return response;
+    }
+
+    
+    /**
+     * Update an existing entity on the server. Properties
+     * must include a "type" property. Executes asynchronously in background 
and
+     * the callbacks are called in the UI thread.
+     *
+     * @param entityID the entity to update
+     * @param updatedProperties the new properties
+     * @param callback A callback for the async response
+     */
+    public void updateEntityAsync(final String entityID, final Map<String, 
Object> updatedProperties,
+                                      final ApiResponseCallback callback) {
+          (new ClientAsyncTask<ApiResponse>(callback) {
+                 @Override
+                 public ApiResponse doTask() {
+                         return updateEntity(entityID, updatedProperties);
+                 }
+          }).execute();
+    }
+
+    /**
+     * Updates the password associated with a user entity
+     *
+     * @param  usernameOrEmail  the username or email address associated with 
the user entity
+     * @param  oldPassword  the user's old password
+     * @param  newPassword  the user's new password
+     * @return an ApiResponse with the updated entity in it.
+     */
+    public ApiResponse updateUserPassword(String usernameOrEmail, String 
oldPassword, String newPassword) {
+       Map<String,Object> updatedProperties = new HashMap<String,Object>();
+       updatedProperties.put("oldpassword", oldPassword);
+       updatedProperties.put("newpassword", newPassword);
+       return apiRequest(HTTP_METHOD_POST, null, updatedProperties,
+                       organizationId, applicationId, "users", 
usernameOrEmail);
+    }
+
+    
+    /**
+     * Remove an existing entity on the server.
+     * 
+     * @param entityType the collection of the entity
+     * @param entityID the specific entity to delete
+     * @return an ApiResponse indicating whether the removal was successful
+     */
+    public ApiResponse removeEntity(String entityType, String entityID) {
+       assertValidApplicationId();
+       if (isEmpty(entityType)) {
+            throw new IllegalArgumentException("Missing entity type");
+       }
+       ApiResponse response = apiRequest(HTTP_METHOD_DELETE, null, null,
+                       organizationId, applicationId, entityType, entityID);
+       return response;
+    }
+    
+    /**
+     * Remove an existing entity on the server.
+     * Executes asynchronously in background and
+     * the callbacks are called in the UI thread.
+     *
+     * @param entityType the collection of the entity
+     * @param entityID the specific entity to delete
+     * @param callback A callback with the async response
+     */
+    public void removeEntityAsync(final String entityType, final String 
entityID,
+                                                               final 
ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+               return removeEntity(entityType, entityID);
+               }
+       }).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.
+     * 
+     * See {@link #doHttpRequest(String,Map,Object,String...)} for
+     * more on the parameters.
+     * 
+     * @param httpMethod The HTTP method to use in the query
+     * @param params Query parameters.
+     * @param data The request body.
+     * @param segments Additional URL path segments to append to the request 
URL
+     * @return An instance representing query results
+     */
+    public Query queryEntitiesRequest(String httpMethod,
+            Map<String, Object> params, Object data, String... segments) {
+        ApiResponse response = apiRequest(httpMethod, params, data, segments);
+        return new EntityQuery(response, httpMethod, params, data, segments);
+    }
+
+    /**
+     * 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.
+     * 
+     * See {@link #doHttpRequest(String,Map,Object,String...)} for
+     * more on the parameters.
+     * 
+     * @param callback A callback for the async response
+     * @param httpMethod The HTTP method to use in the query
+     * @param params Query parameters.
+     * @param data The request body.
+     * @param segments Additional URL path segments to append to the request 
URL
+     */
+    public void queryEntitiesRequestAsync(final QueryResultsCallback callback,
+            final String httpMethod, final Map<String, Object> params,
+            final Object data, final String... segments) {
+        (new ClientAsyncTask<Query>(callback) {
+            @Override
+            public Query doTask() {
+                return queryEntitiesRequest(httpMethod, params, data, 
segments);
+            }
+        }).execute();
+    }
+
+    /**
+     * Query object for handling the response from certain query requests
+     * @y.exclude
+     */
+    private class EntityQuery implements Query {
+        final String httpMethod;
+        final Map<String, Object> params;
+        final Object data;
+        final String[] segments;
+        final ApiResponse response;
+
+        private EntityQuery(ApiResponse response, String httpMethod,
+                Map<String, Object> params, Object data, String[] segments) {
+            this.response = response;
+            this.httpMethod = httpMethod;
+            this.params = params;
+            this.data = data;
+            this.segments = segments;
+        }
+
+        private EntityQuery(ApiResponse response, EntityQuery q) {
+            this.response = response;
+            httpMethod = q.httpMethod;
+            params = q.params;
+            data = q.data;
+            segments = q.segments;
+        }
+
+        /**
+         * Gets the API response from the last request
+         *
+         * @return an ApiResponse object
+         */
+        public ApiResponse getResponse() {
+            return response;
+        }
+
+        /**
+         * Checks if there are more results available based on whether a 
+         * 'cursor' property was present in the last result set.
+         *
+         * @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 based on the cursor
+         * from the last result set.
+         * 
+         * @return query that contains results and where to get more.
+         */
+        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(httpMethod, nextParams, 
data,
+                        segments);
+                return new EntityQuery(nextResponse, this);
+            }
+            return null;
+        }
+
+    }
+
+
+    /****************** USER ENTITY MANAGEMENT ***********************/
+    /****************** USER ENTITY MANAGEMENT ***********************/
+
+    /**
+     * Creates a user entity.
+     * 
+     * @param  username  required. The username to be associated with the user 
entity.
+     * @param  name  the user's full name. Can be null.
+     * @param  email  the user's email address.
+     * @param  password  the user's password
+     * @return  an ApiResponse object
+     */
+    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);
+    }
+
+       /**
+        * Creates a user. Executes asynchronously in background and the 
callbacks
+        * are called in the UI thread.
+        * 
+        * @param  username required. The username to be associated with the 
user entity.
+     * @param  name  the user's full name. Can be null.
+     * @param  email  the user's email address.
+     * @param  password  the user's password.
+        * @param  callback  an ApiResponse callback for handling the async 
response.
+        */
+       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();
+       }
+
+    /**
+     * Retrieves the /users collection.
+     * 
+     * @return a Query object
+     */
+    public Query queryUsers() {
+        Query q = queryEntitiesRequest(HTTP_METHOD_GET, null, null,
+                organizationId,  applicationId, "users");
+        return q;
+    }
+    
+    /**
+     * Retrieves the /users collection. Executes asynchronously in
+     * background and the callbacks are called in the UI thread.
+     * 
+     * @param  callback  a QueryResultsCallback object to handle the async 
response
+     */
+    public void queryUsersAsync(QueryResultsCallback callback) {
+        queryEntitiesRequestAsync(callback, HTTP_METHOD_GET, null, null,
+                organizationId, applicationId, "users");
+    }
+
+
+    /**
+     * Performs a query of the users collection using the provided query 
command.
+     * For example: "name contains 'ed'".
+     * 
+     * @param  ql  the query to execute
+     * @return  a Query object
+     */
+    public Query queryUsers(String ql) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("ql", ql);
+        Query q = queryEntitiesRequest(HTTP_METHOD_GET, params, 
null,organizationId,
+                applicationId, "users");
+        return q;
+    }
+
+    /**
+     * 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  the query to execute
+     * @param  callback  a QueryResultsCallback object to handle the async 
response
+     */
+    public void queryUsersAsync(String ql, QueryResultsCallback callback) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("ql", ql);
+        queryEntitiesRequestAsync(callback, HTTP_METHOD_GET, params, null, 
+                organizationId, applicationId, "users");
+    }
+    
+    /**
+     * Perform a query of the users collection within the specified distance of
+     * the specified location and optionally using the provided additional 
query.
+     * For example: "name contains 'ed'".
+     * 
+     * @param  distance  distance from the location in meters
+     * @param  latitude  the latitude of the location to measure from
+     * @param  longitude  the longitude of the location to measure from
+     * @param  ql  an optional additional query to send with the request
+     * @return  a Query object
+     */
+    public Query queryUsersWithinLocation(float distance, float latitude,
+            float longitude, String ql) {
+        Map<String, Object> params = new HashMap<String, Object>();
+        params.put("ql",
+                this.makeLocationQL(distance, latitude, longitude, ql));
+        Query q = queryEntitiesRequest(HTTP_METHOD_GET, params, null, 
organizationId,
+                applicationId, "users");
+        return q;
+    }
+
+    
+    /****************** GROUP ENTITY MANAGEMENT ***********************/
+    /****************** GROUP ENTITY MANAGEMENT ***********************/
+
+    /**
+     * Creates a group with the specified group path. Group paths can be slash
+     * ("/") delimited like file paths for hierarchical group relationships.
+     * 
+     * @param  groupPath  the path to use for the new group.
+     * @return  an ApiResponse object
+     */
+    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  the path to use for the new group
+     * @param  groupTitle  the title to use for the new group
+     * @return  an ApiResponse object
+     */
+    public ApiResponse createGroup(String groupPath, String groupTitle) {
+     return createGroup(groupPath, groupTitle, null);  
+    }
+    
+    /**
+     * Create a group with a path, title and name. Group
+     * paths can be slash ("/") delimited like file paths for hierarchical 
group
+     * relationships.
+     *
+     * @param  groupPath  the path to use for the new group
+     * @param  groupTitle  the title to use for the new group
+     * @param  groupName  the name to use for the new group
+     * @return  an ApiResponse object
+     */
+    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(HTTP_METHOD_POST, null, data,  organizationId, 
applicationId, "groups");
+    }
+
+    /**
+     * 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  the path to use for the new group.
+     * @param  callback  an ApiResponseCallback object to handle the async 
response
+     */
+    public void createGroupAsync(String groupPath,
+            final ApiResponseCallback callback) {
+        createGroupAsync(groupPath, null, 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  the path to use for the new group.
+     * @param  groupTitle  the title to use for the new group.
+     * @param  callback  an ApiResponseCallback object to handle the async 
response
+     */
+    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();
+    }
+
+    /**
+     * Gets the groups associated with a user entity
+     * 
+     * @param  userId  the UUID of the user entity
+     * @return  a map with the group path as the key and a Group object as the 
value
+     */
+    public Map<String, Group> getGroupsForUser(String userId) {
+        ApiResponse response = apiRequest(HTTP_METHOD_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;
+    }
+
+       /**
+        * Gets the groups associated with a user entity. Executes 
asynchronously in background and
+        * the callbacks are called in the UI thread.
+        * 
+     * @param  userId  the UUID of the user entity
+        * @param  callback  a GroupsRetrievedCallback object to handle the 
async response
+        */
+       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();
+       }
+
+    /**
+     * Gets the user entities associated with the specified group.
+     * 
+     * @param  groupId  UUID of the group entity
+     * @return  a Query object with the results of the query
+     */
+    public Query queryUsersForGroup(String groupId) {
+        Query q = queryEntitiesRequest(HTTP_METHOD_GET, null, null, 
organizationId,
+                applicationId, "groups", groupId, "users");
+        return q;
+    }
+
+    /**
+     * Gets the user entities associated with the specified group. Executes 
+     * asynchronously in background and the callbacks are called in the UI 
thread.
+     * 
+     * @param  groupId  UUID of the group entity
+     * @param  callback a QueryResultsCallback object to handle the async 
response
+     */
+    public void queryUsersForGroupAsync(String groupId,
+            QueryResultsCallback callback) {
+        queryEntitiesRequestAsync(callback, HTTP_METHOD_GET, null, null,
+                getApplicationId(), "groups", groupId, "users");
+    }
+
+    /**
+     * Connects a user entity to the specified group entity.
+     * 
+     * @param  userId  UUID of the user entity
+     * @param  groupId  UUID of the group entity 
+     * @return  an ApiResponse object
+     */
+    public ApiResponse addUserToGroup(String userId, String groupId) {
+        return apiRequest(HTTP_METHOD_POST, null, null, organizationId,  
applicationId, "groups",
+                groupId, "users", userId);
+    }
+
+    /**
+     * Connects a user entity to the specified group entity. Executes 
asynchronously in
+     * background and the callbacks are called in the UI thread.
+     * 
+     * @param  userId  UUID of the user entity
+     * @param  groupId  UUID of the group entity 
+     * @param  callback  an ApiResponseCallback object to handle the async 
response
+     */
+    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();
+    }
+
+    /**
+     * Disconnects a user entity from the specified group entity.
+     * 
+     * @param  userId  UUID of the user entity
+     * @param  groupId  UUID of the group entity 
+     * @return  an ApiResponse object
+     */
+    public ApiResponse removeUserFromGroup(String userId, String groupId) {
+        return apiRequest(HTTP_METHOD_DELETE, null, null, organizationId,  
applicationId, "groups",
+                groupId, "users", userId);
+    }
+
+    /**
+     * Disconnects a user entity from the specified group entity. Executes 
asynchronously in
+     * background and the callbacks are called in the UI thread.
+     * 
+     * @param  userId  UUID of the user entity
+     * @param  groupId  UUID of the group entity 
+     * @param  callback  an ApiResponseCallback object to handle the async 
response
+     */
+    public void removeUserFromGroupAsync(final String userId, final String 
groupId,
+            final ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return removeUserFromGroup(userId, groupId);
+            }
+        }).execute();
+    }
+
+    /****************** ACTIVITY ENTITY MANAGEMENT ***********************/
+    /****************** ACTIVITY ENTITY MANAGEMENT ***********************/
+
+    /**
+     * Get a user's activity feed. Returned as a query to ease paging.
+     * 
+     * @param  userId  UUID of user entity
+     * @return  a Query object
+     */
+    public Query queryActivityFeedForUser(String userId) {
+        Query q = queryEntitiesRequest(HTTP_METHOD_GET, null, null,
+                organizationId, applicationId, "users", userId, "feed");
+        return q;
+    }
+    
+       /**
+        * 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  UUID of user entity
+        * @param  callback  a QueryResultsCallback object to handle the async 
response
+        */
+       public void queryActivityFeedForUserAsync(final String userId, final 
QueryResultsCallback callback) {
+               (new ClientAsyncTask<Query>(callback) {
+                       @Override
+                       public Query doTask() {
+                               return queryActivityFeedForUser(userId);
+                       }
+               }).execute();
+       }
+
+
+    /**
+     * Posts an activity to a user entity's activity stream. Activity must 
already be created.
+     * 
+     * @param userId 
+     * @param activity 
+     * @return An instance with the server response
+     */
+    public ApiResponse postUserActivity(String userId, Activity activity) {
+        return apiRequest(HTTP_METHOD_POST, null, activity,  organizationId, 
applicationId, "users",
+                userId, "activities");
+    }
+
+    /**
+     * Creates and posts an activity to a user entity's activity stream.
+     * 
+     * @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(this, verb, title, content,
+                category, user, object, objectType, objectName, objectContent);
+        return postUserActivity(user.getUuid().toString(), activity);
+    }
+
+       /**
+        * 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();
+       }
+
+    /**
+     * Posts an activity to a group. Activity must already be created.
+     * 
+     * @param groupId
+     * @param activity
+     * @return
+     */
+    public ApiResponse postGroupActivity(String groupId, Activity activity) {
+        return apiRequest(HTTP_METHOD_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(this, verb, title, content,
+                category, user, object, objectType, objectName, objectContent);
+        return postGroupActivity(groupId, activity);
+    }
+
+       /**
+        * 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();
+       }
+
+    /**
+     * 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(this, 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.
+     *      
+     * @return
+     */
+    public Query queryActivity() {
+        Query q = queryEntitiesRequest(HTTP_METHOD_GET, null, null,
+               organizationId, applicationId, "activities");
+        return q;
+    }
+
+    
+
+    /**
+     * Get a group's activity feed. Returned as a query to ease paging.
+     * 
+     * @param groupId
+     * @return
+     */
+    public Query queryActivityFeedForGroup(String groupId) {
+        Query q = queryEntitiesRequest(HTTP_METHOD_GET, null, null,
+                organizationId,  applicationId, "groups", groupId, "feed");
+        return q;
+    }
+
+    /**
+     * 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 groupId
+     * @param callback
+     */
+    public void queryActivityFeedForGroupAsync(final String groupId,
+            final QueryResultsCallback callback) {
+        (new ClientAsyncTask<Query>(callback) {
+            @Override
+            public Query doTask() {
+                return queryActivityFeedForGroup(groupId);
+            }
+        }).execute();
+    }
+    
+
+    /****************** ENTITY CONNECTIONS ***********************/
+    /****************** ENTITY CONNECTIONS ***********************/
+
+    /**
+     * Connect two entities together.
+     * 
+     * @param connectingEntityType The type of the first entity.
+     * @param connectingEntityId The ID of the first entity.
+     * @param connectionType The type of connection between the entities.
+     * @param connectedEntityId The ID of the second entity.
+     * @return An instance with the server's response.
+     */
+    public ApiResponse connectEntities(String connectingEntityType,
+            String connectingEntityId, String connectionType,
+            String connectedEntityId) {
+        return apiRequest(HTTP_METHOD_POST, null, null,  organizationId, 
applicationId,
+                connectingEntityType, connectingEntityId, connectionType,
+                connectedEntityId);
+    }
+    
+    /**
+     * Connect two entities together
+     * 
+     * @param connectorType The type of the first entity in the connection.
+     * @param connectorID The first entity's ID.
+     * @param connectionType The type of connection to make.
+     * @param connecteeType The type of the second entity.
+     * @param connecteeID The second entity's ID
+     * @return An instance with the server's response.
+     */
+    public ApiResponse connectEntities(String connectorType,
+               String connectorID,
+               String connectionType,
+               String connecteeType,
+               String connecteeID) {
+               return apiRequest(HTTP_METHOD_POST, null, null, organizationId, 
applicationId,
+                               connectorType, connectorID, connectionType, 
connecteeType, connecteeID);
+    }
+
+
+       /**
+        * Connect two entities together. Executes asynchronously in background 
and
+        * the callbacks are called in the UI thread.
+        * 
+     * @param connectingEntityType The type of the first entity.
+     * @param connectingEntityId The UUID or 'name' property of the first 
entity.
+     * @param connectionType The type of connection between the entities.
+     * @param connectedEntityId The UUID of the second entity.
+        * @param callback A callback with the async response.
+        */
+       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();
+       }
+
+    /**
+     * Connect two entities together. Allows the 'name' of the connected entity
+     * to be specified but requires the type also be specified. Executes 
asynchronously 
+     * in background and the callbacks are called in the UI thread.
+     * 
+     * @param connectingEntityType The type of the first entity.
+     * @param connectingEntityId The UUID or 'name' property of the first 
entity.
+     * @param connectionType The type of connection between the entities.
+     * @param connectedEntityType The type of connection between the entities.
+     * @param connectedEntityId The UUID or 'name' property of the second 
entity.
+     * @param callback A callback with the async response.
+     */
+    public void connectEntitiesAsync(final String connectingEntityType,
+            final String connectingEntityId, final String connectionType,
+            final String connectedEntityType, final String connectedEntityId, 
+            final ApiResponseCallback callback) {
+        (new ClientAsyncTask<ApiResponse>(callback) {
+            @Override
+            public ApiResponse doTask() {
+                return connectEntities(connectingEntityType,
+                        connectingEntityId, connectionType, 
connectedEntityType, connectedEntityId);
+            }
+        }).execute();
+    }
+       
+    /**
+     * Disconnect two entities.
+     * 
+     * @param connectingEntityType The collection name or UUID of the first 
entity.
+     * @param connectingEntityId The name or UUID of the first entity.
+     * @param connectionType The type of connection between the entities.     
+     * @param connectedEntityId The name or UUID of the second entity.
+     * @return An instance with the server's response.
+     */
+    public ApiResponse disconnectEntities(String connectingEntityType,
+            String connectingEntityId, String connectionType,
+            String connectedEntity

<TRUNCATED>

Reply via email to