Initial commit of Usergrid Java SDK into its own repo
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..40f7468
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.idea
+target/
+*.iml
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e06d208
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..95e4d04
--- /dev/null
+++ b/README.md
@@ -0,0 +1,580 @@
+# Usergrid Java SDK
+
+Usergrid SDK written for Java 
+
+## Initialization
+
+There are two different ways of initializing the Usergrid Java SDK: 
+
+1. The singleton pattern is both convenient and enables the developer to use a globally available and always-initialized instance of Usergrid. 
+
+```java
+Usergrid.initSharedInstance("orgId", "appId");
+```
+
+2. The Instance pattern enables the developer to manage instances of the Usergrid client independently and in an isolated fashion. The primary use-case for this is when an application connects to multiple Usergrid targets.
+
+```java
+UsergridClient client = new UsergridClient("orgId","appId");
+```
+
+_Note: Examples in this readme assume you are using the `Usergrid` shared instance. If you've implemented the instance pattern instead, simply replace `Usergrid` with your client instance variable._
+
+## RESTful operations
+
+When making any RESTful call, a `type` parameter (or `path`) is always required. Whether you specify this as an argument or in an object as a parameter is up to you.
+
+### GET
+
+- To get entities in a collection:
+
+```java
+UsergridResponse response = Usergrid.GET("collection");
+List<UsergridEntity> entities = response.getEntities();
+```
+
+- To get a specific entity in a collection by uuid or name:
+
+```java
+UsergridResponse response = Usergrid.GET("collection","<uuid-or-name>");
+UsergridEntity entities = response.entity();
+```
+
+- To get specific entities in a collection by passing a `UsergridQuery` object:
+
+```java
+UsergridQuery query = new UsergridQuery("cats").gt("weight", 2.4)
+                                 	.contains("color", "bl*")
+                                 .not()
+                                 .eq("color", "blue")
+                                 .or()
+                                 .eq("color", "orange");
+	
+// this will build out the following query:
+// select * where weight > 2.4 and color contains 'bl*' and not color = 'blue' or color = 'orange'
+	
+UsergridResponse response = Usergrid.GET(query);
+List<UsergridEntity> entities = response.getEntities();
+```
+
+### POST and PUT
+
+POST and PUT requests both require a JSON body payload. You can pass either a Java object or a `UsergridEntity` instance. While the former works in principle, best practise is to use a `UsergridEntity` wherever practical. When an entity has a uuid or name property and already exists on the server, use a PUT request to update it. If it does not, use POST to create it.
+
+- To create a new entity in a collection (**POST**):
+
+```java
+HashMap<String,String> propertyMap = new HashMap<>();
+propertyMap.put("cuisine","pizza");
+UsergridEntity entity = new UsergridEntity("restaurant","Dino's Deep Dish", propertyMap);	
+Usergrid.POST(entity); // entity should now have a uuid property and be created
+	
+// you can also POST an array of entities:
+	
+HashMap<String,String> propertyMap = new HashMap<>();
+propertyMap.put("cuisine","pizza");
+
+ArrayList<UsergridEntity> entities = new ArrayList<>();
+entities.add(new UsergridEntity("restaurant","Dino's Deep Dish", propertyMap));
+entities.add(new UsergridEntity("restaurant","Pizza da Napoli", propertyMap));
+UsergridResponse response = Usergrid.POST(entities);
+List<UsergridEntity> responseEntities = response.getEntities(); // responseEntities should now contain now valid posted entities.
+```
+
+- To update an entity in a collection (**PUT**):
+
+```java
+HashMap<String,String> propertyMap = new HashMap<>();
+propertyMap.put("cuisine","pizza");
+UsergridEntity entity = new UsergridEntity("restaurant","Dino's Deep Dish", propertyMap);	
+UsergridResponse response = Usergrid.POST(entity);
+if( response.ok() ) {
+	entity.putProperty("owner","Mia Carrara");
+	Usergrid.PUT(entity); // entity now has the property 'owner'
+}
+	
+// or update a set of entities by passing a UsergridQuery object
+
+HashMap<String,String> propertiesToUpdate = new HashMap<>();
+propertiesToUpdate.put("cuisine","pizza");
+UsergridQuery query = new UsergridQuery("restaurants").eq("cuisine","italian");
+
+UsergridResponse response = Usergrid.PUT(query, propertiesToUpdate);
+	
+    /* the first 10 entities matching this query criteria will be updated:
+    e.g.:
+        [
+            {
+                "type": "restaurant",
+                "restaurant": "Il Tarazzo",
+                "cuisine": "italian",
+                "keywords": ["pasta"]
+            },
+            {
+                "type": "restaurant",
+                "restaurant": "Cono Sur Pizza & Pasta",
+                "cuisine": "italian",
+                "keywords": ["pasta"]
+            }
+        ]
+    */
+```
+
+### DELETE
+
+DELETE requests require either a specific entity or a `UsergridQuery` object to be passed as an argument.
+
+- To delete a specific entity in a collection by uuid or name:
+
+```java
+UsergridResponse response = Usergrid.DELETE("collection", "<uuid-or-name>"); // if successful, entity will now be deleted
+```
+
+- To specific entities in a collection to delete by passing a `UsergridQuery` object:
+
+```java
+UsergridQuery query = new UsergridQuery("cats").eq("color","black").or().eq("color","white");
+	
+// this will build out the following query:
+// select * where color = 'black' or color = 'white'
+	
+UsergridResponse response = Usergrid.DELETE(query); // the first 10 entities matching this query criteria will be deleted
+```
+
+## Entity operations and convenience methods
+
+`UsergridEntity` has a number of helper/convenience methods to make working with entities more convenient.
+
+### reload()
+
+Reloads the entity from the server:
+
+```java
+entity.reload(); // entity is now reloaded from the server
+```
+
+### save()
+
+Saves (or creates) the entity on the server:
+
+
+```java
+entity.putProperty("aNewProperty","A new value");
+entity.save(); // entity is now updated on the server
+```
+
+### remove()
+
+Deletes the entity from the server:
+
+```java
+entity.remove(); // entity is now deleted on the server and the local instance should be destroyed
+```
+
+## Authentication, current user, and auth-fallback
+
+### appAuth and authenticateApp()
+
+`Usergrid` can use the app client ID and secret that were passed upon initialization and automatically retrieve an app-level token for these credentials.
+
+```java
+Usergrid.setAppAuth(new UsergridAppAuth("<client-id>", "<client-secret>"));
+Usergrid.authenticateApp(); // Usergrid.appAuth is authenticated automatically when this call is successful
+```
+
+### currentUser, userAuth,  and authenticateUser()
+
+`Usergrid` has a special `currentUser` property. 
+
+By default, when calling `authenticateUser()`, `.currentUser` will be set to this user if the authentication flow is successful.
+
+```java
+UsergridUserAuth userAuth = new UsergridUserAuth("<username>","<password>");
+Usergrid.authenticateUser(userAuth); // Usergrid.currentUser is set to the authenticated user and the token is stored within that context
+```
+    
+If you want to utilize authenticateUser without setting as the current user, simply pass a `false` boolean value as the second parameter:
+
+```java
+UsergridUserAuth userAuth = new UsergridUserAuth("<username>","<password>");
+Usergrid.authenticateUser(userAuth,false); // user is authenticated but Usergrid.currentUser is not set.
+```
+
+### authMode
+
+Auth-mode defines what the client should pass in for the authorization header. 
+
+By default, `Usergrid.authMode` is set to `.User`, when a `Usergrid.currentUser` is present and authenticated, an API call will be performed using the token for the user. 
+
+If `Usergrid.authMode` is set to `.None`, all API calls will be performed unauthenticated. 
+
+If instead `Usergrid.authMode` is set to `.App`, the API call will instead be performed using client credentials, _if_ they're available (i.e. `authenticateApp()` was performed at some point). 
+
+### usingAuth()
+
+At times it is desireable to have complete, granular control over the authentication context of an API call. 
+
+To facilitate this, the passthrough function `.usingAuth()` allows you to pre-define the auth context of the next API call.
+
+```java
+// assume Usergrid.authMode = UsergridAuthMode.NONE.
+
+Map<String, String> permissionsMap = new HashMap<>();
+permissionsMap.put("permission","get,post,put,delete:/**");
+UsergridResponse response = Usergrid.usingAuth(Usergrid.getAppAuth()).POST("roles/guest/permissions",permissionsMap);
+
+// here we've temporarily used the client credentials to modify permissions
+// subsequent calls will not use this auth context
+```
+
+## User operations and convenience methods
+
+`UsergridUser` has a number of helper/convenience methods to make working with user entities more convenient. If you are _not_ utilizing the `Usergrid` shared instance, you must pass an instance of `UsergridClient` as the first argument to any of these helper methods.
+    
+### create()
+
+Creating a new user:
+
+```java
+UsergridUser user = new UsergridUser("username","password");
+user.create(); // user has now been created and should have a valid uuid
+```
+
+### login()
+
+A simpler means of retrieving a user-level token:
+
+```java
+user.login("username","password"); // user is now logged in
+```
+
+### logout()
+
+Logs out the selected user. You can also use this convenience method on `Usergrid.currentUser`.
+
+```java
+user.logout(); // user is now logged out
+```
+
+### resetPassword()
+
+Resets the password for the selected user.
+
+```java
+// if it was done correctly, the new password will be changed
+user.resetPassword("oldPassword", "newPassword");
+```
+
+### UsergridUser.CheckAvailable()
+
+This is a class (static) method that allows you to check whether a username or email address is available or not.
+
+```java
+boolean available = UsergridUser.checkAvailable("email", null); // 'available' == whether an email already exists for a user
+
+available = UsergridUser.checkAvailable(null, "username"); // 'available' == whether an username already exists for a user
+
+available = UsergridUser.checkAvailable("email", "username"); // 'available' == whether an email or username already exist for a user
+```
+
+## Querying and filtering data
+
+### UsergridQuery initialization
+
+The `UsergridQuery` class allows you to build out complex query filters using the Usergrid [query syntax](http://docs.apigee.com/app-services/content/querying-your-data).
+
+The first parameter of the `UsergridQuery` builder pattern should be the collection (or type) you intend to query. You can either pass this as an argument, or as the first builder object:
+
+```java
+UsergridQuery query = new UsergridQuery("cats");
+// or
+UsergridQuery query = new UsergridQuery().collection("cats");
+```
+
+You then can layer on additional queries:
+
+```java
+UsergridQuery query = new UsergridQuery("cats").gt("weight",2.4).contains("color","bl*")
+                                 .not()
+                                 .eq("color","white")
+                                 .or()
+                                 .eq("color","orange");
+```
+
+You can also adjust the number of results returned:
+
+```java
+UsergridQuery query = new UsergridQuery("cats").eq("color","black").limit(100);
+                                 
+// returns a maximum of 100 entities
+```
+
+And sort the results:
+
+```java
+UsergridQuery query = new UsergridQuery("cats").eq("color","black").limit(100).asc("name")
+                                 
+// sorts by 'name', ascending
+```
+
+And you can do geo-location queries:
+
+```java
+UsergridQuery query = new UsergridQuery("devices").locationWithin(<distance>, <lat>, <long>);
+```
+
+### Using a query in a request
+
+Queries can be passed as parameters to GET, PUT, and DELETE requests:
+
+```java
+// Gets entities matching the query.
+Usergrid.GET(query);
+
+// Updates the entities matching the query with the new property.
+Usergrid.PUT(query, Collections.singletonMap("aNewProperty","A new value"));
+
+// Deletes entities of a given type matching the query.
+Usergrid.DELETE(query);
+```
+### List of query builder objects
+
+`type("string")`
+
+> The collection name to query
+
+`collection("string")`
+
+> An alias for `type`
+
+`eq("key","value")` or 
+`equals("key","value")` or 
+`filter("key","value")` 
+
+> Equal to (e.g. `where color = 'black'`)
+
+`contains("key","value")` or
+`containsString("key","value")` or
+`containsWord("key","value")`
+
+> Contains a string (e.g.` where color contains 'bl*'`)
+
+`gt("key","value")` or
+`greaterThan("key","value")`
+
+> Greater than (e.g. `where weight > 2.4`)
+
+`gte("key","value")` or 
+`greaterThanOrEqual("key","value")`
+
+> Greater than or equal to (e.g. `where weight >= 2.4`)
+
+`lt("key","value")` or `lessThan("key","value")`
+
+> Less than (e.g. `where weight < 2.4`)
+
+`lte("key","value")` or `lessThanOrEqual("key","value")`
+
+> Less than or equal to (e.g. `where weight <= 2.4`)
+
+`not()`
+
+> Negates the next block in the builder pattern, e.g.:
+
+```java
+UsergridQuery query = new UsergridQuery("cats").not().eq("color","black");
+// select * from cats where not color = 'black'
+```
+
+`and()`
+
+> Joins two queries by requiring both of them. `and` is also implied when joining two queries _without_ an operator. E.g.:
+
+```java
+UsergridQuery query = new UsergridQuery("cats").eq("color","black").eq("fur","longHair");
+// is identical to:
+UsergridQuery query = new UsergridQuery("cats").eq("color","black").and().eq("fur","longHair");
+```
+
+`or()`
+
+> Joins two queries by requiring only one of them. `or` is never implied. e.g.:
+
+```java
+UsergridQuery query = new UsergridQuery("cats").eq("color","black").or().eq("color", "white");
+```
+    
+> When using `or()` and `and()` operators, `and()` joins will take precedence over `or()` joins. You can read more about query operators and precedence [here](http://docs.apigee.com/api-baas/content/supported-query-operators-data-types).
+
+`locationWithin(distanceInMeters, latitude, longitude)`
+
+> Returns entities which have a location within the specified radius. Arguments can be `float` or `int`.
+
+`asc("key")` or `ascending("key")`
+
+> Sorts the results by the specified property, ascending
+
+`desc("key")` or `descending("key")`
+
+> Sorts the results by the specified property, descending
+
+`sort("key",UsergridQuerySortOrder.ASC)`
+
+> Sorts the results by the specified property, in the specified `UsergridQuerySortOrder` (`.ASC` or `.DESC`).
+ 
+`limit(int)`
+
+> The maximum number of entities to return
+
+`cursor("string")`
+
+> A pagination cursor string
+
+`fromString("query string")`
+
+> A special builder property that allows you to input a pre-defined query string. All builder properties will be ignored when this property is defined. For example:
+    
+```java
+UsergridQuery query = new UsergridQuery().fromString("select * where color = 'black' order by name asc");
+```
+
+## UsergridResponse object
+
+`UsergridResponse` is the core class that handles both successful and unsuccessful HTTP responses from Usergrid. 
+
+If a request is successful, any entities returned in the response will be automatically parsed into `UsergridEntity` objects and pushed to the `entities` property.
+
+If a request fails, the `error` property will contain information about the problem encountered.
+
+### ok
+
+You can check `UsergridResponse.ok`, a `Bool` value, to see if the response was successful. Any status code `< 400` returns true.
+
+```java
+UsergridResponse response = Usergrid.GET("collection");
+if( response.ok() ) {
+    // woo!
+}
+```
+    
+### entity, entities, user, users, first, last
+
+Depending on the call you make, any entities returned in the response will be automatically parsed into `UsergridEntity` objects and pushed to the `entities` property. If you're querying the `users` collection, these will also be `UsergridUser` objects, a subclass of `UsergridEntity`.
+
+- `.first()` returns the first entity in an array of entities; `.entity()` is an alias to `.first()`. If there are no entities, both of these will be undefined.
+
+- `.last()` returns the last entity in an array of entities; if there is only one entity in the array, this will be the same as `.first()` _and_ `.entity()`, and will be undefined if there are no entities in the response.
+
+- `.getEntities()` will either be an array of entities in the response, or an empty array.
+
+- `.user()` is a special alias for `.entity()` for when querying the `users()` collection. Instead of being a `UsergridEntity`, it will be its subclass, `UsergridUser`.
+
+- `.users()` is the same as `.user()`, though behaves as `.getEntities()` does by returning either an array of UsergridUser objects or an empty array.
+
+Examples:
+
+```java
+UsergridResponse response = Usergrid.GET("collection");
+    // you can access:
+    //     response.getEntities() (the returned entities)
+    //     response.first() (the first entity)
+    //     response.entity() (same as response.first)
+    //     response.last() (the last entity returned)
+
+UsergridResponse response = Usergrid.GET("collection","<uuid-or-name>");
+    // you can access:
+    //     response.entity() (the returned entity) 
+    //     response.getEntities() (containing only the returned entity)
+    //     response.first() (same as response.entity)
+    //     response.last() (same as response.entity)
+
+UsergridResponse response = Usergrid.GET("users");
+    // you can access:
+    //     response.users() (the returned users)
+    //     response.getEntities() (same as response.users)
+    //     response.user() (the first user)    
+    //     response.entity() (same as response.user)   
+    //     response.first() (same as response.user)  
+    //     response.last() (the last user)
+
+UsergridResponse response = Usergrid.GET("users","<uuid-or-name>");
+    // you can access;
+    //     response.users() (containing only the one user)
+    //     response.getEntities() (same as response.users)
+    //     response.user() (the returned user)    
+    //     response.entity() (same as response.user)   
+    //     response.first() (same as response.user)  
+    //     response.last() (same as response.user)  
+```
+
+## Connections
+
+Connections can be managed using `Usergrid.connect()`, `Usergrid.disconnect()`, and `Usergrid.getConnections()`, or entity convenience methods of the same name. 
+
+When retrieving connections via `Usergrid.getConnections()`, you can pass in a optional `UsergridQuery` object in order to filter the connectioned entities returned.
+
+### Connect
+
+Create a connection between two entities:
+
+```java
+Usergrid.connect(entity1, "relationship", entity2); // entity1 now has an outbound connection to entity2
+```
+
+### Retrieve Connections
+
+Retrieve outbound connections:
+
+```java
+Usergrid.getConnections(UsergridDirection.OUT, entity1, "relationship");
+    // entities is an array of entities that entity1 is connected to via 'relationship'
+    // in this case, we'll see entity2 in the array
+```
+
+Retrieve inbound connections:
+
+```java
+Usergrid.getConnections(UsergridDirection.IN, entity2, "relationship");
+    // entities is an array of entities that connect to entity2 via 'relationship'
+    // in this case, we'll see entity1 in the array
+```
+
+### Disconnect
+
+Delete a connection between two entities:
+
+```java
+Usergrid.disconnect(entity1, "relationship", entity2);
+    // entity1's outbound connection to entity2 has been destroyed
+```
+
+## Custom UsergridEntity Subclasses
+
+Creating custom subclasses of the base `UsergridEntity` class (just like `UsergridUser` and `UsergridDevice`) is possible.
+
+- To do so, subclass `UsergridEntity` and implement the required methods:
+
+```java
+public class ActivityEntity extends UsergridEntity {
+	public static final String ACTIVITY_ENTITY_TYPE = "activity";
+	
+   public ActivityEntity(){
+       super(ACTIVITY_ENTITY_TYPE);
+   }
+}
+```
+- You will also need to register the custom subclass:
+
+```java
+Usergrid.initSharedInstance("orgId","appId");
+UsergridEntity.mapCustomSubclassToType("activity", ActivityEntity.class);
+```
+
+By registering your custom subclass, the `UsergridEntity` and `UsergridResponse` classes are able to generate instances of these classes based on the an entities `type`.
+
+In the above example, entities which have a `type` value of `activity` can now be cast as `ActivityEntity` objects. e.g.:
+
+```java
+UsergridResponse response = Usergrid.GET("activity");
+ActivityEntity activityEntity = (ActivityEntity)response.entity();
+```
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a4bb6dc
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,127 @@
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <bundle.symbolicName>org.apache.usergrid</bundle.symbolicName>
+        <bundle.namespace>org.apache.usergrid</bundle.namespace>
+        <jackson-version>2.7.3</jackson-version>
+        <junit-version>4.11</junit-version>
+        <okhttp-version>3.2.0</okhttp-version>
+        <intellij-annotations-version>9.0.4</intellij-annotations-version>
+    </properties>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.usergrid</groupId>
+    <artifactId>usergrid-java-client</artifactId>
+    <version>2.2.0-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <description>A Java client for Usergrid</description>
+    <url>http://usergrid.apache.org</url>
+
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <developers>
+        <developer>
+            <id>eanuff</id>
+            <name>Ed Anuff</name>
+        </developer>
+        <developer>
+            <id>tnine</id>
+            <name>Todd Nine</name>
+        </developer>
+        <developer>
+            <id>sganyo</id>
+            <name>Scott Ganyo</name>
+        </developer>
+        <developer>
+            <id>jwest</id>
+            <name>Jeffrey West</name>
+        </developer>
+        <developer>
+            <id>adastagiri</id>
+            <name>Ayesha Dastagiri</name>
+        </developer>
+        <developer>
+            <id>rwalsh</id>
+            <name>Robert Walsh</name>
+        </developer>
+    </developers>
+
+    <build>
+        <plugins>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.9.1</version>
+                <configuration>
+                    <doclet>com.sun.tools.doclets.standard.Standard</doclet>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.3</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>${junit-version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>${jackson-version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <version>${jackson-version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${jackson-version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>${okhttp-version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.intellij</groupId>
+            <artifactId>annotations</artifactId>
+            <version>${intellij-annotations-version}</version>
+        </dependency>
+    </dependencies>
+    <name>Apache Usergrid Java SDK</name>
+    <organization>
+        <name>The Apache Software Foundation</name>
+        <url>http://apache.org</url>
+    </organization>
+    <issueManagement>
+        <system>JIRA</system>
+        <url>https://issues.apache.org/jira/browse/USERGRID</url>
+    </issueManagement>
+</project>
\ No newline at end of file
diff --git a/src/main/java/org/apache/usergrid/java/client/Usergrid.java b/src/main/java/org/apache/usergrid/java/client/Usergrid.java
new file mode 100644
index 0000000..f7cd545
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/Usergrid.java
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client;
+
+import org.apache.usergrid.java.client.UsergridEnums.UsergridAuthMode;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.auth.UsergridAuth;
+import org.apache.usergrid.java.client.auth.UsergridUserAuth;
+import org.apache.usergrid.java.client.model.*;
+import org.apache.usergrid.java.client.query.UsergridQuery;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.apache.usergrid.java.client.UsergridEnums.UsergridDirection;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("unused")
+public final class Usergrid {
+    @NotNull public static final String UsergridSDKVersion = "2.1.0";
+
+    private static UsergridClient sharedClient;
+    private Usergrid() { /** Private constructor because we only have static methods. **/ }
+
+    public static boolean isInitialized() {
+        return (Usergrid.sharedClient != null);
+    }
+    public static void reset() { Usergrid.sharedClient = null; }
+
+    @NotNull
+    public static UsergridClient getInstance() throws NullPointerException {
+        if (!Usergrid.isInitialized()) {
+            throw new NullPointerException("Shared client has not been initialized!");
+        }
+        return Usergrid.sharedClient;
+    }
+
+    @NotNull
+    public static UsergridClient initSharedInstance(@NotNull final UsergridClientConfig config) {
+        if (Usergrid.isInitialized()) {
+            System.out.print("The Usergrid shared instance was already initialized. All subsequent initialization attempts (including this) will be ignored.");
+        } else {
+            Usergrid.sharedClient = new UsergridClient(config);
+        }
+        return Usergrid.sharedClient;
+    }
+
+    @NotNull
+    public static UsergridClient initSharedInstance(@NotNull final String orgId, @NotNull final String appId) {
+        return Usergrid.initSharedInstance(new UsergridClientConfig(orgId, appId));
+    }
+
+    @NotNull
+    public static UsergridClient initSharedInstance(@NotNull final String orgId, @NotNull final String appId, @NotNull final String baseUrl) {
+        return Usergrid.initSharedInstance(new UsergridClientConfig(orgId, appId, baseUrl));
+    }
+
+    @NotNull
+    public static UsergridClient initSharedInstance(@NotNull final String orgId, @NotNull final String appId, @NotNull final String baseUrl, @NotNull final UsergridAuthMode authMode) {
+        return Usergrid.initSharedInstance(new UsergridClientConfig(orgId, appId, baseUrl, authMode));
+    }
+
+    @NotNull public static UsergridClientConfig getConfig() { return Usergrid.getInstance().getConfig(); }
+    public static void setConfig(@NotNull UsergridClientConfig config) { Usergrid.getInstance().setConfig(config); }
+
+    @NotNull public static String getAppId() { return Usergrid.getInstance().getAppId(); }
+    public static void setAppId(@NotNull String appId) { Usergrid.getInstance().setAppId(appId); }
+
+    @NotNull public static String getOrgId() { return Usergrid.getInstance().getOrgId(); }
+    public static void setOrgId(@NotNull String orgId) { Usergrid.getInstance().setOrgId(orgId); }
+
+    @NotNull public static String getBaseUrl() { return Usergrid.getInstance().getBaseUrl(); }
+    public static void setBaseUrl(@NotNull String baseUrl) { Usergrid.getInstance().setBaseUrl(baseUrl); }
+
+    @NotNull public static String clientAppUrl() { return Usergrid.getInstance().clientAppUrl(); }
+
+    @NotNull public static UsergridAuthMode getAuthMode() { return Usergrid.getInstance().getAuthMode(); }
+    public static void setAuthMode(@NotNull final UsergridAuthMode authMode) { Usergrid.getInstance().setAuthMode(authMode); }
+
+    @Nullable public static UsergridAppAuth getAppAuth() { return Usergrid.getInstance().getAppAuth(); }
+    public static void setAppAuth(@Nullable final UsergridAppAuth appAuth) { Usergrid.getInstance().setAppAuth(appAuth); }
+
+    @Nullable public static UsergridUser getCurrentUser() { return Usergrid.getInstance().getCurrentUser(); }
+    public static void setCurrentUser(@Nullable final UsergridUser currentUser) { Usergrid.getInstance().setCurrentUser(currentUser); }
+
+    @Nullable
+    public static UsergridAuth authForRequests() {
+        return Usergrid.getInstance().authForRequests();
+    }
+
+    @NotNull
+    public static UsergridClient usingAuth(@NotNull final UsergridAuth auth) {
+        return Usergrid.getInstance().usingAuth(auth);
+    }
+
+    @NotNull
+    public static UsergridClient usingToken(@NotNull final String accessToken) {
+        return Usergrid.getInstance().usingToken(accessToken);
+    }
+
+    @NotNull
+    public static UsergridResponse resetPassword(@NotNull final UsergridUser user, @NotNull final String oldPassword, @NotNull final String newPassword) {
+        return Usergrid.getInstance().resetPassword(user, oldPassword, newPassword);
+    }
+
+    @NotNull
+    public static UsergridResponse authenticateApp() {
+        return Usergrid.getInstance().authenticateApp();
+    }
+
+    @NotNull
+    public static UsergridResponse authenticateApp(@NotNull final UsergridAppAuth appAuth) {
+        return Usergrid.getInstance().authenticateApp(appAuth);
+    }
+
+    @NotNull
+    public static UsergridResponse authenticateUser(@NotNull final UsergridUserAuth userAuth) {
+        return Usergrid.getInstance().authenticateUser(userAuth);
+    }
+
+    @NotNull
+    public static UsergridResponse authenticateUser(@NotNull final UsergridUserAuth userAuth, final boolean setAsCurrentUser) {
+        return Usergrid.getInstance().authenticateUser(userAuth,setAsCurrentUser);
+    }
+
+    @NotNull
+    public static UsergridResponse logoutCurrentUser() {
+        return Usergrid.getInstance().logoutCurrentUser();
+    }
+
+    @NotNull
+    public static UsergridResponse logoutUserAllTokens(@NotNull final String uuidOrUsername) {
+        return Usergrid.getInstance().logoutUserAllTokens(uuidOrUsername);
+    }
+
+    @NotNull
+    public static UsergridResponse logoutUser(@NotNull final String uuidOrUsername, @Nullable final String token) {
+        return Usergrid.getInstance().logoutUser(uuidOrUsername,token);
+    }
+
+    @NotNull
+    public static UsergridResponse sendRequest(@NotNull final UsergridRequest request) {
+        return Usergrid.getInstance().sendRequest(request);
+    }
+
+    @NotNull
+    public static UsergridResponse GET(@NotNull final String type, @NotNull final String uuidOrName) {
+        return Usergrid.getInstance().GET(type, uuidOrName);
+    }
+
+    @NotNull
+    public static UsergridResponse GET(@NotNull final String type) {
+        return Usergrid.getInstance().GET(type);
+    }
+
+    @NotNull
+    public static UsergridResponse GET(@NotNull final UsergridQuery query) {
+        return Usergrid.getInstance().GET(query);
+    }
+
+    @NotNull
+    public static UsergridResponse PUT(@NotNull final String type, @NotNull final String uuidOrName, @NotNull final Map<String, ?> jsonBody) {
+        return Usergrid.getInstance().PUT(type, uuidOrName, jsonBody);
+    }
+
+    @NotNull
+    public static UsergridResponse PUT(@NotNull final String type, @NotNull final Map<String, ?> jsonBody) {
+        return Usergrid.getInstance().PUT(type, jsonBody);
+    }
+
+    @NotNull
+    public static UsergridResponse PUT(@NotNull final UsergridEntity entity) {
+        return Usergrid.getInstance().PUT(entity);
+    }
+
+    @NotNull
+    public static UsergridResponse PUT(@NotNull final UsergridQuery query, @NotNull final Map<String, ?> jsonBody) {
+        return Usergrid.getInstance().PUT(query, jsonBody);
+    }
+
+    @NotNull
+    public static UsergridResponse POST(@NotNull final String type, @NotNull final String uuidOrName, @NotNull final Map<String, Object> jsonBody) {
+        return Usergrid.getInstance().POST(type, uuidOrName, jsonBody);
+    }
+
+    @NotNull
+    public static UsergridResponse POST(@NotNull final String type, @NotNull final Map<String, ?> jsonBody) {
+        return Usergrid.getInstance().POST(type, jsonBody);
+    }
+
+    @NotNull
+    public static UsergridResponse POST(@NotNull final String type, @NotNull final List<Map<String, ?>> jsonBodies) {
+        return Usergrid.getInstance().POST(type, jsonBodies);
+    }
+
+    @NotNull
+    public static UsergridResponse POST(@NotNull final UsergridEntity entity) throws NullPointerException {
+        return Usergrid.getInstance().POST(entity);
+    }
+
+    @NotNull
+    public static UsergridResponse POST(@NotNull final List<UsergridEntity> entities) {
+        return Usergrid.getInstance().POST(entities);
+    }
+
+    @NotNull
+    public static UsergridResponse DELETE(@NotNull final String type, @NotNull final String uuidOrName) {
+        return Usergrid.getInstance().DELETE(type, uuidOrName);
+    }
+
+    @NotNull
+    public static UsergridResponse DELETE(@NotNull final UsergridEntity entity) {
+        return Usergrid.getInstance().DELETE(entity);
+    }
+
+    @NotNull
+    public static UsergridResponse DELETE(@NotNull final UsergridQuery query) {
+        return Usergrid.getInstance().DELETE(query);
+    }
+
+    @NotNull
+    public static UsergridResponse connect(@NotNull final UsergridEntity entity, @NotNull final String relationship, @NotNull final UsergridEntity to) {
+        return Usergrid.getInstance().connect(entity, relationship, to);
+    }
+
+    @NotNull
+    public static UsergridResponse connect(@NotNull final String entityType, @NotNull final String entityId, @NotNull final String relationship, @NotNull final String fromUuid) {
+        return Usergrid.getInstance().connect(entityType,entityId,relationship,fromUuid);
+    }
+
+    @NotNull
+    public static UsergridResponse connect(@NotNull final String entityType, @NotNull final String entityId, @NotNull final String relationship, @NotNull final String toType, @NotNull final String toName) {
+        return Usergrid.getInstance().connect(entityType,entityId,relationship,toType,toName);
+    }
+
+    @NotNull
+    public static UsergridResponse disconnect(@NotNull final UsergridEntity entity, @NotNull final String relationship, @NotNull final UsergridEntity from) {
+        return Usergrid.getInstance().disconnect(entity, relationship, from);
+    }
+
+    @NotNull
+    public static UsergridResponse disconnect(@NotNull final String entityType, @NotNull final String entityId, @NotNull final String relationship, @NotNull final String fromUuid) {
+        return Usergrid.getInstance().disconnect(entityType, entityId, relationship, fromUuid);
+    }
+
+    @NotNull
+    public static UsergridResponse disconnect(@NotNull final String entityType, @NotNull final String entityId, @NotNull final String relationship, @NotNull final String fromType, @NotNull final String fromName) {
+        return Usergrid.getInstance().disconnect(entityType, entityId, relationship, fromType, fromName);
+    }
+
+    @NotNull
+    public static UsergridResponse getConnections(@NotNull final UsergridDirection direction, @NotNull final UsergridEntity entity, @NotNull final String relationship) {
+        return Usergrid.getInstance().getConnections(direction, entity, relationship);
+    }
+
+    @NotNull
+    public static UsergridResponse getConnections(@NotNull final UsergridDirection direction, @NotNull final UsergridEntity entity, @NotNull final String relationship, @Nullable final UsergridQuery query) {
+        return Usergrid.getInstance().getConnections(direction, entity, relationship, query);
+    }
+
+    @NotNull
+    public static UsergridResponse getConnections(@NotNull final UsergridDirection direction, @NotNull final String type, @NotNull final String uuidOrName, @NotNull final String relationship, @Nullable final UsergridQuery query) {
+        return Usergrid.getInstance().getConnections(direction,type,uuidOrName,relationship,query);
+    }
+
+    @NotNull
+    public static UsergridResponse getConnections(@NotNull final UsergridDirection direction, @NotNull final String uuid, @NotNull final String relationship, @Nullable final UsergridQuery query) {
+        return Usergrid.getInstance().getConnections(direction, uuid, relationship, query);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/usergrid/java/client/UsergridClient.java b/src/main/java/org/apache/usergrid/java/client/UsergridClient.java
new file mode 100644
index 0000000..a317d07
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/UsergridClient.java
@@ -0,0 +1,429 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client;
+
+import org.apache.usergrid.java.client.UsergridEnums.*;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.auth.UsergridAuth;
+import org.apache.usergrid.java.client.auth.UsergridUserAuth;
+import org.apache.usergrid.java.client.model.*;
+import org.apache.usergrid.java.client.query.UsergridQuery;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("unused")
+public class UsergridClient {
+
+    @NotNull public static String DEFAULT_BASE_URL = "https://api.usergrid.com";
+
+    @NotNull private UsergridClientConfig config;
+    @Nullable private UsergridUser currentUser = null;
+    @Nullable private UsergridAuth tempAuth = null;
+
+    @NotNull private final UsergridRequestManager requestManager;
+
+    public UsergridClient(@NotNull final UsergridClientConfig config) {
+        this.config = config;
+        this.requestManager = new UsergridRequestManager(this);
+    }
+
+    public UsergridClient(@NotNull final String orgId, @NotNull final String appId) {
+        this(new UsergridClientConfig(orgId, appId));
+    }
+
+    public UsergridClient(@NotNull final String orgId, @NotNull final String appId, @NotNull final String baseUrl) {
+        this(new UsergridClientConfig(orgId, appId, baseUrl));
+    }
+
+    public UsergridClient(@NotNull final String orgId, @NotNull final String appId, @NotNull final String baseUrl, @NotNull final UsergridAuthMode authMode) {
+        this(new UsergridClientConfig(orgId, appId, baseUrl, authMode));
+    }
+
+    @NotNull public UsergridClientConfig getConfig() { return this.config; }
+    public void setConfig(@NotNull final UsergridClientConfig config) { this.config = config; }
+
+    @NotNull public String getAppId() { return this.config.appId; }
+    public void setAppId(@NotNull final String appId) { this.config.appId = appId; }
+
+    @NotNull public String getOrgId() { return this.config.orgId; }
+    public void setOrgId(@NotNull final String orgId) { this.config.orgId = orgId; }
+
+    @NotNull public String getBaseUrl() { return this.config.baseUrl; }
+    public void setBaseUrl(@NotNull final String baseUrl) { this.config.baseUrl = baseUrl; }
+
+    @NotNull public String clientAppUrl() { return getBaseUrl() + "/" + getOrgId() + "/" + getAppId(); }
+
+    @NotNull public String managementUrl() { return getBaseUrl() + "/management"; }
+
+    @NotNull public UsergridAuthMode getAuthMode() { return this.config.authMode; }
+    public void setAuthMode(@NotNull final UsergridAuthMode authMode) { this.config.authMode = authMode; }
+
+    @Nullable public UsergridUser getCurrentUser() { return this.currentUser; }
+    public void setCurrentUser(@Nullable final UsergridUser currentUser) { this.currentUser = currentUser; }
+
+    @Nullable public UsergridUserAuth getUserAuth() { return (this.currentUser != null) ? this.currentUser.getUserAuth() : null; }
+
+    @Nullable public UsergridAppAuth getAppAuth() { return this.config.appAuth; }
+    public void setAppAuth(@Nullable final UsergridAppAuth appAuth) { this.config.appAuth = appAuth; }
+
+    @Nullable
+    public UsergridAuth authForRequests() {
+        UsergridAuth authForRequests = null;
+        if (tempAuth != null) {
+            if (tempAuth.isValidToken()) {
+                authForRequests = tempAuth;
+            }
+            tempAuth = null;
+        } else {
+            switch (config.authMode) {
+                case USER: {
+                    if (this.currentUser != null && this.currentUser.getUserAuth() != null && this.currentUser.getUserAuth().isValidToken()) {
+                        authForRequests = this.currentUser.getUserAuth();
+                    }
+                    break;
+                }
+                case APP: {
+                    if (this.config.appAuth != null && this.config.appAuth.isValidToken()) {
+                        authForRequests = this.config.appAuth;
+                    }
+                    break;
+                }
+            }
+        }
+        return authForRequests;
+    }
+
+    @NotNull
+    public UsergridClient usingAuth(@Nullable final UsergridAuth auth) {
+        this.tempAuth = auth;
+        return this;
+    }
+
+    @NotNull
+    public UsergridClient usingToken(@NotNull final String accessToken) {
+        this.tempAuth = new UsergridAuth(accessToken);
+        return this;
+    }
+
+    @NotNull
+    public UsergridResponse authenticateApp() {
+        if( this.config.appAuth == null ) {
+            return UsergridResponse.fromError(this,  "Invalid UsergridAppAuth.", "UsergridClient's appAuth is null.");
+        }
+        return this.authenticateApp(this.config.appAuth);
+    }
+
+    @NotNull
+    public UsergridResponse authenticateApp(@NotNull final UsergridAppAuth auth) {
+        this.config.appAuth = auth;
+        return this.requestManager.authenticateApp(auth);
+    }
+
+    @NotNull
+    public UsergridResponse authenticateUser(@NotNull final UsergridUserAuth userAuth) {
+        return this.authenticateUser(userAuth,true);
+    }
+
+    @NotNull
+    public UsergridResponse authenticateUser(@NotNull final UsergridUserAuth userAuth, final boolean setAsCurrentUser) {
+        UsergridResponse response = this.requestManager.authenticateUser(userAuth);
+        if( response.ok() && setAsCurrentUser ) {
+            this.setCurrentUser(response.user());
+        }
+        return response;
+    }
+
+    @NotNull
+    public UsergridResponse resetPassword(@NotNull final UsergridUser user, @NotNull final String oldPassword, @NotNull final String newPassword) {
+        String usernameOrEmail = user.usernameOrEmail();
+        if( usernameOrEmail == null ) {
+            return UsergridResponse.fromError(this,  "Error resetting password.", "The UsergridUser object must contain a valid username or email to reset the password.");
+        }
+        Map<String, Object> data = new HashMap<>();
+        data.put("newpassword", newPassword);
+        data.put("oldpassword", oldPassword);
+        String[] pathSegments = { "users", usernameOrEmail, "password"};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, data, this.authForRequests() ,pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse logoutCurrentUser()  {
+        UsergridUser currentUser = this.currentUser;
+        if( currentUser != null ) {
+            String uuidOrUsername = currentUser.uuidOrUsername();
+            UsergridUserAuth userAuth = currentUser.getUserAuth();
+            if( uuidOrUsername != null && userAuth != null ) {
+                String accessToken = userAuth.getAccessToken();
+                if( accessToken != null ) {
+                    return logoutUser(uuidOrUsername, accessToken);
+                }
+            }
+        }
+        return UsergridResponse.fromError(this,"UsergridClient's currentUser is not valid.", "UsergridClient's currentUser is null or has no uuid or username.");
+    }
+
+    @NotNull
+    public UsergridResponse logoutUserAllTokens(@NotNull final String uuidOrUsername) {
+        return logoutUser(uuidOrUsername, null);
+    }
+
+    @NotNull
+    public UsergridResponse logoutUser(@NotNull final String uuidOrUsername, @Nullable final String token){
+        String[] pathSegments = {"users", uuidOrUsername, ""};
+        int len = pathSegments.length;
+        Map<String, Object> param = new HashMap<>();
+        if(token != null){
+            pathSegments[len-1] = "revoketoken";
+            param.put("token",token);
+        }
+        else{
+            pathSegments[len-1] = "revoketokens";
+        }
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.PUT, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), param, null, this.authForRequests() , pathSegments);
+        UsergridResponse response = this.sendRequest(request);
+        UsergridUser currentUser = this.getCurrentUser();
+        if( currentUser != null && response.ok() ) {
+            if( uuidOrUsername.equalsIgnoreCase(currentUser.uuidOrUsername()) ) {
+                this.setCurrentUser(null);
+            }
+        }
+        return response;
+    }
+
+    @NotNull
+    public UsergridResponse sendRequest(@NotNull final UsergridRequest request) {
+        return this.requestManager.performRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse GET(@NotNull final String type, @NotNull final String uuidOrName) {
+        String[] pathSegments = {type, uuidOrName};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.GET, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse GET(@NotNull final String type) {
+        String[] pathSegments = {type};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.GET, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse GET(@NotNull final UsergridQuery query) {
+        String collectionName = query.getCollection();
+        if( collectionName == null ) {
+            return UsergridResponse.fromError(this,  "Query collection name missing.", "Query collection name is missing.");
+        }
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.GET, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), query, this.authForRequests() , collectionName);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse PUT(@NotNull final String type, @NotNull final String uuidOrName, @NotNull final Map<String, ?> jsonBody) {
+        String[] pathSegments = { type, uuidOrName };
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.PUT, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, jsonBody, this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse PUT(@NotNull final String type, @NotNull final Map<String, ?> jsonBody) {
+        String uuidOrName = null;
+        Object uuid = jsonBody.get(UsergridEntityProperties.UUID.toString());
+        if( uuid != null ) {
+            uuidOrName = uuid.toString();
+        } else {
+            Object name = jsonBody.get(UsergridEntityProperties.NAME.toString());
+            if( name != null ) {
+                uuidOrName = name.toString();
+            }
+        }
+        if( uuidOrName == null ) {
+            return UsergridResponse.fromError(this,  "jsonBody not valid..", "The `jsonBody` must contain a valid value for either `uuid` or `name`.");
+        }
+        String[] pathSegments = { type, uuidOrName };
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.PUT, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, jsonBody, this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse PUT(@NotNull final UsergridEntity entity) {
+        String entityUuidOrName = entity.uuidOrName();
+        if( entityUuidOrName == null ) {
+            return UsergridResponse.fromError(this,  "No UUID or name found.", "The entity object must have a `uuid` or `name` assigned.");
+        }
+        String[] pathSegments = { entity.getType(), entityUuidOrName };
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.PUT, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, entity, this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse PUT(@NotNull final UsergridQuery query, @NotNull final Map<String, ?> jsonBody) {
+        String collectionName = query.getCollection();
+        if( collectionName == null ) {
+            return UsergridResponse.fromError(this,  "Query collection name missing.", "Query collection name is missing.");
+        }
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.PUT, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, jsonBody, null, query, this.authForRequests(),collectionName);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse POST(final @NotNull UsergridEntity entity) {
+        String[] pathSegments = {entity.getType()};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, entity, this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse POST(@NotNull final List<UsergridEntity> entities) {
+        if( entities.isEmpty() ) {
+            return UsergridResponse.fromError(this,  "Unable to POST entities.", "entities array is empty.");
+        }
+        String[] pathSegments = {entities.get(0).getType()};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, entities, this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse POST(@NotNull final String type, @NotNull final String uuidOrName, @NotNull final Map<String, ?> jsonBody) {
+        String[] pathSegments = {type, uuidOrName};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, jsonBody, this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse POST(@NotNull final String type, @NotNull final Map<String, ?> jsonBody) {
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, jsonBody, this.authForRequests() , type);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse POST(@NotNull final String type, @NotNull final List<Map<String, ?>> jsonBodies) {
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), null, jsonBodies, this.authForRequests() , type);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse DELETE(@NotNull final UsergridEntity entity) {
+        String entityUuidOrName = entity.uuidOrName();
+        if( entityUuidOrName == null ) {
+            return UsergridResponse.fromError(this,  "No UUID or name found.", "The entity object must have a `uuid` or `name` assigned.");
+        }
+        String[] pathSegments = {entity.getType(), entityUuidOrName};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.DELETE, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse DELETE(@NotNull final String type, @NotNull final String uuidOrName) {
+        String[] pathSegments = {type, uuidOrName};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.DELETE, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse DELETE(@NotNull final UsergridQuery query) {
+        String collectionName = query.getCollection();
+        if( collectionName == null ) {
+            return UsergridResponse.fromError(this,  "Query collection name missing.", "Query collection name is missing.");
+        }
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.DELETE, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), query, this.authForRequests() , collectionName);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse connect(@NotNull final UsergridEntity entity, @NotNull final String relationship, @NotNull final UsergridEntity to) {
+        String entityUuidOrName = entity.uuidOrName();
+        String toUuidOrName = to.uuidOrName();
+        if( entityUuidOrName == null || toUuidOrName == null ) {
+            return UsergridResponse.fromError(this, "Invalid Entity Connection Attempt.", "One or both entities that are attempting to be connected do not contain a valid UUID or Name property.");
+        }
+        return this.connect(entity.getType(), entityUuidOrName, relationship, to.getType(), toUuidOrName);
+    }
+
+    @NotNull
+    public UsergridResponse connect(@NotNull final String entityType, @NotNull final String entityId, @NotNull final String relationship, @NotNull final String toType, @NotNull final String toName) {
+        String[] pathSegments = {entityType, entityId, relationship, toType, toName};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse connect(@NotNull final String entityType, @NotNull final String entityId, @NotNull final String relationship, @NotNull final String toId) {
+        String[] pathSegments = { entityType, entityId, relationship, toId};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse disconnect(@NotNull final String entityType, @NotNull final String entityId, @NotNull final String relationship, @NotNull final String fromUuid) {
+        String[] pathSegments = {entityType, entityId, relationship, fromUuid};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.DELETE, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse disconnect(@NotNull final String entityType, @NotNull final String entityId, @NotNull final String relationship, @NotNull final String fromType, @NotNull final String fromName) {
+        String[] pathSegments = {entityType, entityId, relationship, fromType, fromName};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.DELETE, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse disconnect(@NotNull final UsergridEntity entity, @NotNull final String relationship, @NotNull final UsergridEntity from) {
+        String entityUuidOrName = entity.uuidOrName();
+        String fromUuidOrName = from.uuidOrName();
+        if( entityUuidOrName == null || fromUuidOrName == null ) {
+            return UsergridResponse.fromError(this, "Invalid Entity Disconnect Attempt.", "One or both entities that are attempting to be disconnected do not contain a valid UUID or Name property.");
+        }
+        return this.disconnect(entity.getType(), entityUuidOrName, relationship, from.getType(), fromUuidOrName);
+    }
+
+    @NotNull
+    public UsergridResponse getConnections(@NotNull final UsergridDirection direction, @NotNull final UsergridEntity entity, @NotNull final String relationship) {
+        return this.getConnections(direction,entity,relationship,null);
+    }
+
+    @NotNull
+    public UsergridResponse getConnections(@NotNull final UsergridDirection direction, @NotNull final UsergridEntity entity, @NotNull final String relationship, @Nullable final UsergridQuery query) {
+        String entityUuidOrName = entity.uuidOrName();
+        if( entityUuidOrName == null ) {
+            return UsergridResponse.fromError(this, "Invalid Entity Get Connections Attempt.", "The entity must have a `uuid` or `name` assigned.");
+        }
+        return this.getConnections(direction,entity.getType(),entityUuidOrName,relationship,query);
+    }
+
+    @NotNull
+    public UsergridResponse getConnections(@NotNull final UsergridDirection direction, @NotNull final String type, @NotNull final String uuidOrName, @NotNull final String relationship, @Nullable final UsergridQuery query) {
+        String[] pathSegments = {type, uuidOrName, direction.connectionValue(), relationship};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.GET, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), query, this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+
+    @NotNull
+    public UsergridResponse getConnections(@NotNull final UsergridDirection direction, @NotNull final String uuid, @NotNull final String relationship, @Nullable final UsergridQuery query) {
+        String[] pathSegments = {uuid, direction.connectionValue(), relationship};
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.GET, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, this.clientAppUrl(), query, this.authForRequests() , pathSegments);
+        return this.sendRequest(request);
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/UsergridClientConfig.java b/src/main/java/org/apache/usergrid/java/client/UsergridClientConfig.java
new file mode 100644
index 0000000..f12f9ec
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/UsergridClientConfig.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client;
+
+import org.apache.usergrid.java.client.UsergridEnums.UsergridAuthMode;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class UsergridClientConfig {
+
+    // The organization identifier.
+    @NotNull public String orgId;
+
+    // The application identifier.
+    @NotNull public String appId;
+
+    // The base URL that all calls will be made with.
+    @NotNull public String baseUrl = UsergridClient.DEFAULT_BASE_URL;
+
+    // The `UsergridAuthMode` value used to determine what type of token will be sent, if any.
+    @NotNull public UsergridAuthMode authMode = UsergridAuthMode.USER;
+
+    @Nullable public UsergridAppAuth appAuth = null;
+
+    @SuppressWarnings("unused")
+    private UsergridClientConfig() {}
+
+    public UsergridClientConfig(@NotNull final String orgId, @NotNull final String appId) {
+        this.orgId = orgId;
+        this.appId = appId;
+    }
+
+    public UsergridClientConfig(@NotNull final String orgId, @NotNull final String appId, @NotNull final String baseUrl) {
+        this.orgId = orgId;
+        this.appId = appId;
+        this.baseUrl = baseUrl;
+    }
+
+    public UsergridClientConfig(@NotNull final String orgId, @NotNull final String appId, @NotNull final String baseUrl, @NotNull final UsergridAuthMode authMode) {
+        this.orgId = orgId;
+        this.appId = appId;
+        this.baseUrl = baseUrl;
+        this.authMode = authMode;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/UsergridEnums.java b/src/main/java/org/apache/usergrid/java/client/UsergridEnums.java
new file mode 100644
index 0000000..4e2a8b0
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/UsergridEnums.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client;
+
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@SuppressWarnings("unused")
+public class UsergridEnums {
+    public enum UsergridAuthMode {
+        NONE,
+        USER,
+        APP
+    }
+
+    public enum UsergridDirection {
+        IN("connecting"),
+        OUT("connections");
+
+        @NotNull private final String connectionValue;
+
+        UsergridDirection(@NotNull final String connectionValue) {
+            this.connectionValue = connectionValue;
+        }
+
+        @NotNull
+        public String connectionValue() {
+            return this.connectionValue;
+        }
+    }
+
+    public enum UsergridHttpMethod {
+        GET,
+        PUT,
+        POST,
+        DELETE;
+
+        @Nullable
+        public static UsergridHttpMethod fromString(@NotNull final String stringValue) {
+            try {
+                return UsergridHttpMethod.valueOf(stringValue.toUpperCase());
+            } catch(Exception e) {
+                return null;
+            }
+        }
+
+        @Override @NotNull
+        public String toString() {
+            return super.toString().toUpperCase();
+        }
+    }
+
+    public enum UsergridQueryOperator {
+        EQUAL("="),
+        GREATER_THAN(">"),
+        GREATER_THAN_EQUAL_TO(">="),
+        LESS_THAN("<"),
+        LESS_THAN_EQUAL_TO("<=");
+
+        @NotNull private final String operatorValue;
+
+        UsergridQueryOperator(@NotNull final String operatorValue) {
+            this.operatorValue = operatorValue;
+        }
+
+        @NotNull
+        public String operatorValue() {
+            return this.operatorValue;
+        }
+    }
+
+    public enum UsergridQuerySortOrder {
+        ASC,
+        DESC;
+
+        @Nullable
+        public static UsergridQuerySortOrder fromString(@NotNull final String stringValue) {
+            try {
+                return UsergridQuerySortOrder.valueOf(stringValue.toUpperCase());
+            } catch(Exception e) {
+                return null;
+            }
+        }
+
+        @Override @NotNull
+        public String toString() {
+            return super.toString().toLowerCase();
+        }
+    }
+
+    public enum UsergridEntityProperties {
+        TYPE,
+        UUID,
+        NAME,
+        CREATED,
+        MODIFIED,
+        LOCATION;
+
+        @Nullable
+        public static UsergridEntityProperties fromString(@NotNull final String stringValue) {
+            try {
+                return UsergridEntityProperties.valueOf(stringValue.toUpperCase());
+            } catch(Exception e) {
+                return null;
+            }
+        }
+
+        @Override @NotNull
+        public String toString() {
+            return super.toString().toLowerCase();
+        }
+
+        public boolean isMutableForEntity(@NotNull final UsergridEntity entity) {
+            switch(this) {
+                case LOCATION: {
+                    return true;
+                }
+                case NAME: {
+                    return entity.isUser();
+                }
+                case TYPE:
+                case UUID:
+                case CREATED:
+                case MODIFIED:
+                default: {
+                    return false;
+                }
+            }
+        }
+    }
+
+    public enum UsergridUserProperties {
+        NAME,
+        USERNAME,
+        PASSWORD,
+        EMAIL,
+        ACTIVATED,
+        DISABLED,
+        PICTURE;
+
+        @Nullable
+        public static UsergridUserProperties fromString(@NotNull final String stringValue) {
+            try {
+                return UsergridUserProperties.valueOf(stringValue.toUpperCase());
+            } catch(Exception e) {
+                return null;
+            }
+        }
+
+        @Override @NotNull
+        public String toString() {
+            return super.toString().toLowerCase();
+        }
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/UsergridRequest.java b/src/main/java/org/apache/usergrid/java/client/UsergridRequest.java
new file mode 100644
index 0000000..b16783e
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/UsergridRequest.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client;
+
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import org.apache.usergrid.java.client.UsergridEnums.UsergridHttpMethod;
+import org.apache.usergrid.java.client.auth.UsergridAuth;
+import org.apache.usergrid.java.client.query.UsergridQuery;
+import org.apache.usergrid.java.client.utils.JsonUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+
+@SuppressWarnings("unused")
+public class UsergridRequest {
+    @NotNull public static final MediaType APPLICATION_JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
+
+    @NotNull private UsergridHttpMethod method;
+    @NotNull private String baseUrl;
+    @NotNull private MediaType contentType;
+
+    @Nullable private UsergridQuery query;
+    @Nullable private Map<String, Object> headers;
+    @Nullable private Map<String, Object> parameters;
+    @Nullable private Object data;
+    @Nullable private UsergridAuth auth;
+    @Nullable private String[] pathSegments;
+
+    @NotNull
+    public UsergridHttpMethod getMethod() { return method; }
+    public void setMethod(@NotNull final UsergridHttpMethod method) { this.method = method; }
+
+    @NotNull
+    public String getBaseUrl() { return baseUrl; }
+    public void setBaseUrl(@NotNull final String baseUrl) { this.baseUrl = baseUrl; }
+
+    @NotNull
+    public MediaType getContentType() { return contentType; }
+    public void setContentType(@NotNull final MediaType contentType) { this.contentType = contentType; }
+
+    @Nullable
+    public UsergridQuery getQuery() { return query; }
+    public void setQuery(@Nullable final UsergridQuery query) { this.query = query; }
+
+    @Nullable
+    public Map<String,Object> getHeaders() { return headers; }
+    public void setHeaders(@Nullable final Map<String,Object> headers) { this.headers = headers; }
+
+    @Nullable
+    public Map<String,Object> getParameters() { return parameters; }
+    public void setParameters(@Nullable final Map<String,Object> parameters) { this.parameters = parameters; }
+
+    @Nullable
+    public Object getData() { return data; }
+    public void setData(@Nullable final Object data) { this.data = data; }
+
+    @Nullable
+    public UsergridAuth getAuth() { return auth; }
+    public void setAuth(@Nullable final UsergridAuth auth) { this.auth = auth; }
+
+    @Nullable
+    public String[] getPathSegments() { return pathSegments; }
+    public void setPathSegments(@Nullable final String[] pathSegments) { this.pathSegments = pathSegments; }
+
+    private UsergridRequest() {}
+
+    public UsergridRequest(@NotNull final UsergridHttpMethod method,
+                           @NotNull final MediaType contentType,
+                           @NotNull final String url,
+                           @Nullable final UsergridQuery query,
+                           @Nullable final UsergridAuth auth,
+                           @Nullable final String... pathSegments) {
+        this.method = method;
+        this.contentType = contentType;
+        this.baseUrl = url;
+        this.query = query;
+        this.auth = auth;
+        this.pathSegments = pathSegments;
+    }
+
+    public UsergridRequest(@NotNull final UsergridHttpMethod method,
+                           @NotNull final MediaType contentType,
+                           @NotNull final String url,
+                           @Nullable final UsergridAuth auth,
+                           @Nullable final String... pathSegments) {
+        this.method = method;
+        this.contentType = contentType;
+        this.baseUrl = url;
+        this.auth = auth;
+        this.pathSegments = pathSegments;
+    }
+
+    public UsergridRequest(@NotNull final UsergridHttpMethod method,
+                           @NotNull final MediaType contentType,
+                           @NotNull final String url,
+                           @Nullable final Map<String, Object> params,
+                           @Nullable final Object data,
+                           @Nullable final UsergridAuth auth,
+                           @Nullable final String... pathSegments) {
+        this.method = method;
+        this.contentType = contentType;
+        this.baseUrl = url;
+        this.parameters = params;
+        this.data = data;
+        this.headers = null;
+        this.query = null;
+        this.auth = auth;
+        this.pathSegments = pathSegments;
+    }
+
+    public UsergridRequest(@NotNull final UsergridHttpMethod method,
+                           @NotNull final MediaType contentType,
+                           @NotNull final String url,
+                           @Nullable final Map<String, Object> params,
+                           @Nullable final Object data,
+                           @Nullable final Map<String, Object> headers,
+                           @Nullable final UsergridQuery query,
+                           @Nullable final UsergridAuth auth,
+                           @Nullable final String... pathSegments) {
+        this.method = method;
+        this.contentType = contentType;
+        this.baseUrl = url;
+        this.parameters = params;
+        this.data = data;
+        this.headers = headers;
+        this.query = query;
+        this.auth = auth;
+        this.pathSegments = pathSegments;
+    }
+
+    @NotNull
+    public Request buildRequest() {
+        Request.Builder requestBuilder = new Request.Builder();
+        requestBuilder.url(this.constructUrl());
+        this.addHeaders(requestBuilder);
+        requestBuilder.method(this.method.toString(),this.constructRequestBody());
+        return requestBuilder.build();
+    }
+
+    @NotNull
+    protected HttpUrl constructUrl() {
+        String url = this.baseUrl;
+        if( this.query != null ) {
+            url += this.query.build(false);
+        }
+        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
+        if( this.pathSegments != null ) {
+            for( String path : this.pathSegments ) {
+                urlBuilder.addPathSegments(path);
+            }
+        }
+        if( this.parameters != null ) {
+            for (Map.Entry<String, Object> param : this.parameters.entrySet()) {
+                urlBuilder.addQueryParameter(param.getKey(),param.getValue().toString());
+            }
+        }
+        return urlBuilder.build();
+    }
+
+    protected void addHeaders(@NotNull final Request.Builder requestBuilder) {
+        requestBuilder.addHeader("User-Agent", UsergridRequestManager.USERGRID_USER_AGENT);
+        if (this.auth != null ) {
+            String accessToken = this.auth.getAccessToken();
+            if( accessToken != null ) {
+                requestBuilder.addHeader("Authorization", "Bearer " + accessToken);
+            }
+        }
+        if( this.headers != null ) {
+            for( Map.Entry<String,Object> header : this.headers.entrySet() ) {
+                requestBuilder.addHeader(header.getKey(),header.getValue().toString());
+            }
+        }
+    }
+
+    @Nullable
+    protected RequestBody constructRequestBody() {
+        RequestBody requestBody = null;
+        if (method == UsergridHttpMethod.POST || method == UsergridHttpMethod.PUT) {
+            String jsonString = "";
+            if( this.data != null ) {
+                jsonString = JsonUtils.toJsonString(this.data);
+            }
+            requestBody = RequestBody.create(this.contentType,jsonString);
+        }
+        return requestBody;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/UsergridRequestManager.java b/src/main/java/org/apache/usergrid/java/client/UsergridRequestManager.java
new file mode 100644
index 0000000..7099d42
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/UsergridRequestManager.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client;
+
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.apache.usergrid.java.client.UsergridEnums.UsergridHttpMethod;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.auth.UsergridAuth;
+import org.apache.usergrid.java.client.model.UsergridUser;
+import org.apache.usergrid.java.client.auth.UsergridUserAuth;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.util.Map;
+
+import static org.apache.usergrid.java.client.utils.ObjectUtils.isEmpty;
+
+public class UsergridRequestManager {
+
+    @NotNull public static String USERGRID_USER_AGENT = "usergrid-java/v" + Usergrid.UsergridSDKVersion;
+
+    @NotNull private final UsergridClient usergridClient;
+    @NotNull private final OkHttpClient httpClient;
+
+    public UsergridRequestManager(@NotNull final UsergridClient usergridClient) {
+        this.usergridClient = usergridClient;
+        this.httpClient = new OkHttpClient();
+    }
+
+    @NotNull
+    public UsergridResponse performRequest(@NotNull final UsergridRequest usergridRequest) {
+        Request request = usergridRequest.buildRequest();
+        UsergridResponse usergridResponse;
+        try {
+            Response response = this.httpClient.newCall(request).execute();
+            usergridResponse = UsergridResponse.fromResponse(this.usergridClient,usergridRequest,response);
+        } catch( IOException exception ) {
+            usergridResponse = UsergridResponse.fromException(this.usergridClient,exception);
+        }
+        return usergridResponse;
+    }
+
+    @NotNull
+    private UsergridResponse authenticate(@NotNull final UsergridAuth auth) {
+        Map<String, String> credentials = auth.credentialsMap();
+        String url = this.usergridClient.clientAppUrl();
+        if ( auth instanceof UsergridUserAuth){
+
+            UsergridUserAuth userAuth = (UsergridUserAuth) auth;
+            if( userAuth.isAdminUser()){
+
+                url = this.usergridClient.managementUrl();
+            }
+
+        }
+
+        UsergridRequest request = new UsergridRequest(UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, url, null, credentials, this.usergridClient.authForRequests(), "token");
+        UsergridResponse response = performRequest(request);
+        if (!isEmpty(response.getAccessToken()) && !isEmpty(response.getExpires())) {
+            auth.setAccessToken(response.getAccessToken());
+            auth.setExpiry(System.currentTimeMillis() + response.getExpires() - 5000);
+        }
+        return response;
+    }
+
+    @NotNull
+    public UsergridResponse authenticateApp(@NotNull final UsergridAppAuth appAuth) {
+        return this.authenticate(appAuth);
+    }
+
+    @NotNull
+    public UsergridResponse authenticateUser(@NotNull final UsergridUserAuth userAuth) {
+        UsergridResponse response = this.authenticate(userAuth);
+        UsergridUser responseUser = response.user();
+        if ( response.ok() && responseUser != null) {
+            responseUser.setUserAuth(userAuth);
+        }
+        return response;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/auth/UsergridAppAuth.java b/src/main/java/org/apache/usergrid/java/client/auth/UsergridAppAuth.java
new file mode 100644
index 0000000..a7ac64d
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/auth/UsergridAppAuth.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.auth;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+
+@SuppressWarnings("unused")
+public class UsergridAppAuth extends UsergridAuth {
+
+    @NotNull private String clientId;
+    @NotNull private String clientSecret;
+
+    @NotNull public String getClientId() { return clientId; }
+    public void setClientId(@NotNull final String clientId) { this.clientId = clientId; }
+
+    @NotNull private String getClientSecret() { return clientSecret; }
+    public void setClientSecret(@NotNull final String clientSecret) { this.clientSecret = clientSecret; }
+
+    @NotNull
+    @Override
+    public HashMap<String, String> credentialsMap() {
+        HashMap<String,String> credentials = super.credentialsMap();
+        credentials.put("grant_type", "client_credentials");
+        credentials.put("client_id", this.clientId);
+        credentials.put("client_secret", this.clientSecret);
+        return credentials;
+    }
+
+    public UsergridAppAuth() {
+        this("","");
+    }
+
+    public UsergridAppAuth(@JsonProperty("clientId") @NotNull final String clientId, @JsonProperty("clientSecret") @NotNull final String clientSecret) {
+        super();
+        this.clientId = clientId;
+        this.clientSecret = clientSecret;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/auth/UsergridAuth.java b/src/main/java/org/apache/usergrid/java/client/auth/UsergridAuth.java
new file mode 100644
index 0000000..1ed61da
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/auth/UsergridAuth.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.auth;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+
+@SuppressWarnings("unused")
+public class UsergridAuth {
+
+    @Nullable private String accessToken = null;
+    @Nullable private Long expiry = null;
+    private boolean usingToken = false;
+    private boolean isAdminUser = false;
+
+    public UsergridAuth() { }
+
+    public UsergridAuth(@JsonProperty("accessToken") @Nullable final String accessToken) {
+        this.usingToken = true;
+        setAccessToken(accessToken);
+    }
+
+    public UsergridAuth(@JsonProperty("accessToken") @Nullable final String accessToken, @JsonProperty("expiry") @Nullable final Long expiry) {
+        this.usingToken = true;
+        setAccessToken(accessToken);
+        setExpiry(expiry);
+    }
+
+    public void destroy() {
+        setAccessToken(null);
+        setExpiry(null);
+    }
+
+    @Nullable public String getAccessToken() { return accessToken; }
+    public void setAccessToken(@Nullable final String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    @Nullable public Long getExpiry() { return expiry; }
+    public void setExpiry(@Nullable final Long tokenExpiry) { this.expiry = tokenExpiry; }
+
+    public boolean isValidToken() { return (hasToken() && !isExpired()); }
+
+    public boolean hasToken() { return accessToken != null; }
+
+    public boolean isExpired() {
+        if (expiry != null) {
+            Long currentTime = System.currentTimeMillis() / 1000;
+            return ((expiry / 1000) < currentTime);
+        } else {
+            return !this.usingToken;
+        }
+    }
+
+    @NotNull
+    public HashMap<String,String> credentialsMap() {
+        return new HashMap<>();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/usergrid/java/client/auth/UsergridUserAuth.java b/src/main/java/org/apache/usergrid/java/client/auth/UsergridUserAuth.java
new file mode 100644
index 0000000..7cb42ad
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/auth/UsergridUserAuth.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.auth;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+
+@SuppressWarnings("unused")
+public class UsergridUserAuth extends UsergridAuth {
+
+    @NotNull private String username;
+    @NotNull private String password;
+    private boolean isAdminUser = false;
+
+    @NotNull public String getUsername() { return username; }
+    public void setUsername(@NotNull final String username) { this.username = username; }
+
+    @NotNull private String getPassword() { return password; }
+    public void setPassword(@NotNull final String password) { this.password = password; }
+
+    public boolean isAdminUser() { return isAdminUser; }
+
+    @NotNull
+    @Override
+    public HashMap<String, String> credentialsMap() {
+        HashMap<String,String> credentials = super.credentialsMap();
+        credentials.put("grant_type", "password");
+        credentials.put("username", this.username);
+        credentials.put("password", this.password);
+        return credentials;
+    }
+
+    public UsergridUserAuth() {
+        this("","");
+    }
+
+    public UsergridUserAuth(@JsonProperty("username") @NotNull final String username,
+                            @JsonProperty("password") @NotNull final String password) {
+        super();
+        this.username = username;
+        this.password = password;
+    }
+
+    public UsergridUserAuth(@JsonProperty("username") @NotNull final String username,
+                            @JsonProperty("password") @NotNull final String password,
+                            @JsonProperty("isAdminUser") final boolean isAdminUser) {
+        super();
+        this.username = username;
+        this.password = password;
+        this.isAdminUser = isAdminUser;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/exception/UsergridException.java b/src/main/java/org/apache/usergrid/java/client/exception/UsergridException.java
new file mode 100644
index 0000000..ff30a0d
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/exception/UsergridException.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.exception;
+
+import org.jetbrains.annotations.NotNull;
+
+@SuppressWarnings("unused")
+public class UsergridException extends RuntimeException {
+
+    private int responseCode;
+
+    public int getResponseCode() {
+        return responseCode;
+    }
+    public void setResponseCode(final int responseCode) { this.responseCode = responseCode; }
+
+    private UsergridException() {}
+
+    public UsergridException(@NotNull final String message) {
+        super(message);
+    }
+
+    public UsergridException(@NotNull final String message, @NotNull final Throwable cause) {
+        super(message, cause);
+    }
+
+    public UsergridException(@NotNull final String message, final int responseCode) {
+        super(message);
+        this.responseCode = responseCode;
+    }
+
+    public UsergridException(@NotNull final String message, @NotNull final Throwable cause, final int responseCode) {
+        super(message, cause);
+        this.responseCode = responseCode;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/model/UsergridDevice.java b/src/main/java/org/apache/usergrid/java/client/model/UsergridDevice.java
new file mode 100644
index 0000000..1833afb
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/model/UsergridDevice.java
@@ -0,0 +1,60 @@
+package org.apache.usergrid.java.client.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+
+@SuppressWarnings("unused")
+public class UsergridDevice extends UsergridEntity {
+    @NotNull public static String DEVICE_ENTITY_TYPE = "device";
+
+    @Nullable private String model;
+    @Nullable private String platform;
+    @Nullable private String osVersion;
+
+    public UsergridDevice() {
+        super(DEVICE_ENTITY_TYPE);
+    }
+
+    public UsergridDevice(@Nullable final String name) {
+        super(DEVICE_ENTITY_TYPE,name);
+    }
+
+    public UsergridDevice(@NotNull final Map<String, JsonNode> properties) {
+        super(DEVICE_ENTITY_TYPE,null,properties);
+    }
+
+    public UsergridDevice(@Nullable final String name, @NotNull final Map<String, JsonNode> properties) {
+        super(DEVICE_ENTITY_TYPE,name,properties);
+    }
+
+    @Nullable @JsonProperty("deviceModel")
+    public String getModel() {
+        return this.model;
+    }
+    @JsonProperty("deviceModel")
+    public void setModel(@Nullable final String model) {
+        this.model = model;
+    }
+
+    @Nullable @JsonProperty("devicePlatform")
+    public String getPlatform() {
+        return this.platform;
+    }
+    @JsonProperty("devicePlatform")
+    public void setPlatform(@Nullable final String platform) {
+        this.platform = platform;
+    }
+
+    @Nullable @JsonProperty("deviceOSVersion")
+    public String getOsVersion() {
+        return this.osVersion;
+    }
+    @JsonProperty("deviceOSVersion")
+    public void setOsVersion(@Nullable final String osVersion) {
+        this.osVersion = osVersion;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/usergrid/java/client/model/UsergridEntity.java b/src/main/java/org/apache/usergrid/java/client/model/UsergridEntity.java
new file mode 100644
index 0000000..3444de0
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/model/UsergridEntity.java
@@ -0,0 +1,487 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.model;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+import com.fasterxml.jackson.databind.node.*;
+import org.apache.usergrid.java.client.UsergridEnums.*;
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.UsergridClient;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.apache.usergrid.java.client.utils.JsonUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.util.*;
+
+import static org.apache.usergrid.java.client.utils.JsonUtils.*;
+
+@SuppressWarnings("unused")
+public class UsergridEntity {
+
+    @NotNull private static final HashMap<String,Class<? extends UsergridEntity>> subclassMappings = new HashMap<>();
+    @NotNull private static final ObjectMapper entityUpdateMapper = new ObjectMapper();
+    @NotNull private final ObjectReader entityUpdateReader = entityUpdateMapper.readerForUpdating(this);
+
+    static {
+        subclassMappings.put("user",UsergridUser.class);
+        subclassMappings.put("device",UsergridDevice.class);
+    }
+
+    @NotNull private String type;
+    @Nullable private String uuid;
+    @Nullable private String name;
+    @Nullable private Long created;
+    @Nullable private Long modified;
+
+    @NotNull private Map<String, JsonNode> properties = new HashMap<>();
+
+    public UsergridEntity(@JsonProperty("type") @NotNull final String type) {
+        this.type = type;
+    }
+
+    public UsergridEntity(@NotNull final String type, @Nullable final String name) {
+        this(type);
+        if( name != null ) {
+            this.name = name;
+        }
+    }
+
+    public UsergridEntity(@NotNull final String type, @Nullable final String name, @NotNull final Map<String, ?> properties) {
+        this(type,name);
+        this.updatePropertiesWithMap(properties);
+    }
+
+    @Nullable
+    public static Class<? extends UsergridEntity> customSubclassForType(@NotNull final String type) {
+        return UsergridEntity.subclassMappings.get(type);
+    }
+
+    public void copyAllProperties(@NotNull final UsergridEntity fromEntity) {
+        try {
+            this.updatePropertiesWithJsonNode(entityUpdateMapper.valueToTree(fromEntity));
+        } catch( IllegalArgumentException e ) { System.out.print("Usergrid Error: Unable to update properties from entity - " + fromEntity.toString()); }
+    }
+
+    public void updatePropertiesWithMap(@NotNull final Map<String,?> properties) {
+        try {
+            this.updatePropertiesWithJsonNode(entityUpdateMapper.valueToTree(properties));
+        } catch( IllegalArgumentException e ) { System.out.print("Usergrid Error: Unable to update properties from map - " + properties.toString()); }
+    }
+
+    public void updatePropertiesWithJsonNode(@NotNull final JsonNode node) {
+        try {
+            entityUpdateReader.readValue(node);
+        } catch( IOException e ) { System.out.print("Usergrid Error: Unable to update properties from jsonNode - " + node.toString()); }
+    }
+
+    public static void mapCustomSubclassToType(@NotNull final String type, @NotNull final Class<? extends UsergridEntity> subclass) {
+        UsergridEntity.subclassMappings.put(type,subclass);
+    }
+
+    @NotNull @Override public String toString() {
+        return toJsonString(this);
+    }
+    @NotNull public String toPrettyString() { return toPrettyJsonString(this); }
+    @NotNull public JsonNode toJsonObjectValue() {
+        return toJsonNode(this);
+    }
+    @SuppressWarnings("unchecked")
+    @NotNull public Map<String,?> toMapValue() { return toMap(this); }
+
+    @JsonIgnore
+    public boolean isUser() { return (this instanceof UsergridUser || this.getType().equalsIgnoreCase(UsergridUser.USER_ENTITY_TYPE)); }
+
+    @NotNull public String getType() { return this.type; }
+    private void setType(@NotNull final String type) { this.type = type; }
+
+    @Nullable public String getUuid() { return this.uuid; }
+    private void setUuid(@NotNull final String uuid) { this.uuid = uuid; }
+
+    @Nullable public String getName() { return this.name; }
+    protected void setName(@Nullable final String name) { this.name = name; }
+
+    @Nullable public Long getCreated() { return this.created; }
+    private void setCreated(@NotNull final Long created) { this.created = created; }
+
+    @Nullable public Long getModified() { return this.modified; }
+    private void setModified(@NotNull final Long modified) { this.modified = modified; }
+
+    public void setLocation(final double latitude, final double longitude) {
+        ObjectNode rootNode = JsonUtils.createObjectNode();
+        rootNode.put("latitude", latitude);
+        rootNode.put("longitude", longitude);
+        setObjectProperty(this.properties, "location", rootNode);
+    }
+
+    @Nullable
+    public String uuidOrName() {
+        String uuidOrName = this.getUuid();
+        if( uuidOrName == null ) {
+            uuidOrName = this.getName();
+        }
+        return uuidOrName;
+    }
+
+    @NotNull
+    public UsergridResponse reload() {
+        return this.reload(Usergrid.getInstance());
+    }
+
+    @NotNull
+    public UsergridResponse reload(@NotNull final UsergridClient client) {
+        String uuidOrName = this.uuidOrName();
+        if( uuidOrName == null ) {
+            return UsergridResponse.fromError(client,  "No UUID or name found.", "The entity object must have a `uuid` or `name` assigned.");
+        }
+        UsergridResponse response = client.GET(this.getType(), uuidOrName);
+        if( response.ok() ) {
+            UsergridEntity responseEntity = response.first();
+            if( responseEntity != null ) {
+                this.copyAllProperties(responseEntity);
+            }
+        }
+        return response;
+    }
+
+    @NotNull
+    public UsergridResponse save() {
+        return this.save(Usergrid.getInstance());
+    }
+
+    @NotNull
+    public UsergridResponse save(@NotNull final UsergridClient client) {
+        UsergridResponse response;
+        if( this.getUuid() != null ) {
+            response = client.PUT(this);
+        } else {
+            response = client.POST(this);
+        }
+        if( response.ok() ) {
+            UsergridEntity responseEntity = response.first();
+            if( responseEntity != null ) {
+                this.copyAllProperties(responseEntity);
+            }
+        }
+        return response;
+    }
+
+    @NotNull
+    public UsergridResponse remove() {
+        return this.remove(Usergrid.getInstance());
+    }
+
+    @NotNull
+    public UsergridResponse remove(@NotNull final UsergridClient client) {
+        return client.DELETE(this);
+    }
+
+    @NotNull
+    public UsergridResponse connect(@NotNull final String relationship, @NotNull final UsergridEntity toEntity) {
+        return this.connect(Usergrid.getInstance(), relationship, toEntity);
+    }
+
+    @NotNull
+    public UsergridResponse connect(@NotNull final UsergridClient client, @NotNull final String relationship, @NotNull final UsergridEntity toEntity) {
+        return client.connect(this,relationship,toEntity);
+    }
+
+    @NotNull
+    public UsergridResponse disconnect(@NotNull final String relationship, @NotNull final UsergridEntity fromEntity) {
+        return this.disconnect(Usergrid.getInstance(), relationship, fromEntity);
+    }
+
+    @NotNull
+    public UsergridResponse disconnect(@NotNull final UsergridClient client, @NotNull final String relationship, @NotNull final UsergridEntity fromEntity) {
+        return client.disconnect(this,relationship,fromEntity);
+    }
+
+    @NotNull
+    public UsergridResponse getConnections(@NotNull final UsergridDirection direction, @NotNull final String relationship) {
+        return this.getConnections(Usergrid.getInstance(),direction,relationship);
+    }
+
+    @NotNull
+    public UsergridResponse getConnections(@NotNull final UsergridClient client, @NotNull final UsergridDirection direction, @NotNull final String relationship) {
+        return client.getConnections(direction,this,relationship);
+    }
+
+    public void removeProperty(@NotNull final String name) {
+        putProperty(name, NullNode.getInstance());
+    }
+
+    public void removeProperties(@NotNull final List<String> names) {
+        for( String propertyName : names ) {
+            this.removeProperty(propertyName);
+        }
+    }
+
+    public void putProperty(@NotNull final String name, @NotNull final String value) {
+        this.putProperty(name, JsonNodeFactory.instance.textNode(value));
+    }
+    public void putProperty(@NotNull final String name, final boolean value) {
+        this.putProperty(name, JsonNodeFactory.instance.booleanNode(value));
+    }
+    public void putProperty(@NotNull final String name, @NotNull final List value) {
+        this.putProperty(name, JsonNodeFactory.instance.pojoNode(value));
+    }
+    public void putProperty(@NotNull final String name, final int value) {
+        this.putProperty(name, JsonNodeFactory.instance.numberNode(value));
+    }
+    public void putProperty(@NotNull final String name, final long value) {
+        this.putProperty(name, JsonNodeFactory.instance.numberNode(value));
+    }
+    public void putProperty(@NotNull final String name, final float value) {
+        this.putProperty(name, JsonNodeFactory.instance.numberNode(value));
+    }
+    public void putProperty(@NotNull final String name, @Nullable final JsonNode value) {
+        UsergridEntityProperties entityProperty = UsergridEntityProperties.fromString(name);
+        if( entityProperty != null && !entityProperty.isMutableForEntity(this)) {
+            return;
+        }
+
+        JsonNode valueNode = value;
+        if( valueNode == null ) {
+            valueNode = NullNode.getInstance();
+        }
+        this.updatePropertiesWithMap(Collections.singletonMap(name,valueNode));
+    }
+    public void putProperties(@NotNull final String jsonString) {
+        try {
+            JsonNode jsonNode = entityUpdateMapper.readTree(jsonString);
+            this.putProperties(jsonNode);
+        } catch( Exception ignore ) {}
+    }
+    public void putProperties(@NotNull final Map<String, Object> properties) {
+        try {
+            JsonNode jsonNode = entityUpdateMapper.valueToTree(properties);
+            this.putProperties(jsonNode);
+        } catch( Exception ignore ) {}
+    }
+    public void putProperties(@NotNull final JsonNode jsonNode) {
+        HashMap<String,JsonNode> propertiesToUpdate = new HashMap<>();
+        Iterator<Map.Entry<String,JsonNode>> keys = jsonNode.fields();
+        while (keys.hasNext()) {
+            Map.Entry<String,JsonNode> entry = keys.next();
+            String key = entry.getKey();
+            UsergridEntityProperties entityProperty = UsergridEntityProperties.fromString(key);
+            if( entityProperty == null || entityProperty.isMutableForEntity(this) ) {
+                propertiesToUpdate.put(key,entry.getValue());
+            }
+        }
+        if( !propertiesToUpdate.isEmpty() ) {
+            this.updatePropertiesWithMap(propertiesToUpdate);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void append(@NotNull final String name, @NotNull final Object value) {
+        this.append(name, (value instanceof List) ? (List<Object>) value : Collections.singletonList(value));
+    }
+
+    public void append(@NotNull final String name, @NotNull final List<Object> value) {
+        this.insert(name, value, Integer.MAX_VALUE);
+    }
+
+    @SuppressWarnings("unchecked")
+    public void insert(@NotNull final String name, @NotNull final Object value) {
+        this.insert(name, (value instanceof List) ? (List<Object>) value : Collections.singletonList(value), 0);
+    }
+
+    @SuppressWarnings("unchecked")
+    public void insert(@NotNull final String name, @NotNull final Object value, final int index) {
+        this.insert(name, (value instanceof List) ? (List<Object>) value : Collections.singletonList(value), index);
+    }
+
+    public void insert(@NotNull final String name, @NotNull final List<Object> value) {
+        this.insert(name,value,0);
+    }
+
+    public void insert(@NotNull final String name, @NotNull final List<Object> value, final int index) {
+        int indexToInsert = index;
+        if (indexToInsert < 0) {
+            indexToInsert = 0;
+        }
+        Object propertyValue = this.getEntityProperty(name);
+        if( propertyValue != null ) {
+            ArrayList<Object> propertyArrayValue = this.convertToList(propertyValue);
+            propertyArrayValue = this.insertIntoArray(propertyArrayValue,value,indexToInsert);
+            this.putProperty(name, propertyArrayValue);
+        } else {
+            this.putProperty(name, value);
+        }
+    }
+
+    public void pop(@NotNull final String name) {
+        ArrayList<Object> arrayToPop = this.getArrayToPopOrShift(name);
+        if( arrayToPop != null && !arrayToPop.isEmpty() ) {
+            arrayToPop.remove(arrayToPop.size() - 1);
+            this.putProperty(name, arrayToPop);
+        }
+    }
+
+    public void shift(@NotNull final String name) {
+        ArrayList<Object> arrayToShift = this.getArrayToPopOrShift(name);
+        if( arrayToShift != null && !arrayToShift.isEmpty() ) {
+            arrayToShift.remove(0);
+            this.putProperty(name, arrayToShift);
+        }
+    }
+
+    @Nullable
+    public <T> T getEntityProperty(@NotNull final String name) {
+        return JsonUtils.getProperty(this.properties, name);
+    }
+
+    @Nullable
+    public JsonNode getJsonNodeProperty(@NotNull final String name) {
+        return this.getProperties().get(name);
+    }
+
+    @Nullable
+    public String getStringProperty(@NotNull final String name) {
+        return JsonUtils.getStringProperty(this.getProperties(), name);
+    }
+
+    @Nullable
+    public Boolean getBooleanProperty(@NotNull final String name) {
+        Boolean booleanValue = null;
+        Object object = JsonUtils.getProperty(this.getProperties(), name);
+        if( object instanceof Boolean ) {
+            booleanValue = (Boolean)object;
+        }
+        return booleanValue;
+    }
+
+    @Nullable
+    public Number getNumberProperty(@NotNull final String name) {
+        Number numberValue = null;
+        Object object = JsonUtils.getProperty(this.getProperties(), name);
+        if( object instanceof Number ) {
+            numberValue = (Number)object;
+        }
+        return numberValue;
+    }
+
+    @Nullable
+    public Integer getIntegerProperty(@NotNull final String name) {
+        Integer integerValue = null;
+        Object object = JsonUtils.getProperty(this.getProperties(), name);
+        if( object instanceof Number ) {
+            integerValue = ((Number)object).intValue();
+        }
+        return integerValue;
+    }
+
+    @Nullable
+    public Float getFloatProperty(@NotNull final String name) {
+        Float floatValue = null;
+        Object object = JsonUtils.getProperty(this.getProperties(), name);
+        if( object instanceof Number ) {
+            floatValue = ((Number)object).floatValue();
+        }
+        return floatValue;
+    }
+
+    @Nullable
+    public Long getLongProperty(@NotNull final String name) {
+        Long longValue = null;
+        Object object = JsonUtils.getProperty(this.getProperties(), name);
+        if( object instanceof Number ) {
+            longValue = ((Number)object).longValue();
+        }
+        return longValue;
+    }
+
+    @JsonAnyGetter @NotNull
+    public Map<String, JsonNode> getProperties() {
+        return this.properties;
+    }
+
+    @JsonAnySetter
+    private void internalPutProperty(@NotNull final String name, @Nullable final JsonNode value) {
+        if (value == null) {
+            properties.put(name, NullNode.instance);
+        } else {
+            properties.put(name, value);
+        }
+    }
+
+    @Nullable
+    @SuppressWarnings("unchecked")
+    private ArrayList<Object> getArrayToPopOrShift(@NotNull final String name) {
+        Object entityProperty = getEntityProperty(name);
+        ArrayList<Object> arrayToPopOrShift = null;
+        if (entityProperty instanceof POJONode) {
+            Object objectValue = ((POJONode) entityProperty).getPojo();
+            if (objectValue instanceof List) {
+                arrayToPopOrShift = new ArrayList<>((List) objectValue);
+            } else {
+                arrayToPopOrShift = new ArrayList<>();
+                arrayToPopOrShift.add(objectValue);
+            }
+        } else if( entityProperty instanceof ArrayNode ) {
+            arrayToPopOrShift = JsonUtils.convertToArrayList((ArrayNode)entityProperty);
+        } else if( entityProperty instanceof List ) {
+            arrayToPopOrShift = new ArrayList<>((List) entityProperty);
+        }
+        return arrayToPopOrShift;
+    }
+
+    @NotNull
+    private ArrayList<Object> convertToList(@NotNull final Object value) {
+        ArrayList<Object> arrayList = new ArrayList<>();
+        if( value instanceof ArrayNode ) {
+            arrayList = JsonUtils.convertToArrayList((ArrayNode)value);
+        } else if (value instanceof POJONode) {
+            Object objectValue = ((POJONode) value).getPojo();
+            if( objectValue instanceof List ) {
+                arrayList.addAll((List)objectValue);
+            } else {
+                arrayList.add(objectValue);
+            }
+        } else if (value instanceof List) {
+            arrayList.addAll((List)value);
+        } else {
+            arrayList.add(value);
+        }
+        return arrayList;
+    }
+
+    @NotNull
+    private ArrayList<Object> insertIntoArray(@NotNull final List<Object> propertyArrayNode, @NotNull final List<Object> arrayToInsert, final int index) {
+        ArrayList<Object> mergedArray = new ArrayList<>();
+        if (propertyArrayNode.size() <= 0 || arrayToInsert.isEmpty()) {
+            mergedArray.addAll(arrayToInsert);
+        }  else if ( index <= 0 ) {
+            mergedArray.addAll(arrayToInsert);
+            mergedArray.addAll(propertyArrayNode);
+        } else if ( index > 0 ) {
+            mergedArray.addAll(propertyArrayNode);
+            if ( index > propertyArrayNode.size() ) {
+                mergedArray.addAll(arrayToInsert);
+            } else {
+                mergedArray.addAll(index,arrayToInsert);
+            }
+        }
+        return mergedArray;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/usergrid/java/client/model/UsergridUser.java b/src/main/java/org/apache/usergrid/java/client/model/UsergridUser.java
new file mode 100644
index 0000000..f967e46
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/model/UsergridUser.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.UsergridClient;
+import org.apache.usergrid.java.client.UsergridEnums.*;
+import org.apache.usergrid.java.client.auth.UsergridUserAuth;
+import org.apache.usergrid.java.client.query.UsergridQuery;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+
+@SuppressWarnings("unused")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class UsergridUser extends UsergridEntity {
+    @NotNull public final static String USER_ENTITY_TYPE = "user";
+
+    @Nullable private UsergridUserAuth userAuth = null;
+
+    @Nullable private String username;
+    @Nullable private String email;
+    @Nullable private String password;
+    @Nullable private String picture;
+
+    private boolean activated = false;
+    private boolean disabled = false;
+
+    public UsergridUser() {
+        super(USER_ENTITY_TYPE);
+    }
+
+    public UsergridUser(@NotNull final String username, @Nullable final String password) {
+        super(USER_ENTITY_TYPE);
+        setUsername(username);
+        setPassword(password);
+    }
+
+    public UsergridUser(@NotNull final String name, @NotNull final HashMap<String, Object> propertyMap) {
+        super(USER_ENTITY_TYPE,name);
+        putProperties(propertyMap);
+    }
+
+    public UsergridUser(@Nullable final String name, @Nullable final String username, @Nullable final String email, @Nullable final String password) {
+        super(USER_ENTITY_TYPE,name);
+        setUsername(username);
+        setEmail(email);
+        setPassword(password);
+    }
+
+    public void setName(@Nullable final String name) { super.setName(name); }
+
+    @Nullable public String getUsername() { return this.username; }
+    public void setUsername(@Nullable final String username) { this.username = username; }
+
+    @Nullable public String getEmail() { return this.email; }
+    public void setEmail(@Nullable final String email) { this.email = email; }
+
+    @Nullable public String getPassword() { return this.password; }
+    public void setPassword(@Nullable final String password) { this.password = password; }
+
+    @Nullable public String getPicture() { return this.picture; }
+    public void setPicture(@Nullable final String picture) { this.picture = picture; }
+
+    public boolean isActivated() { return this.activated; }
+    public void setActivated(final boolean activated) { this.activated = activated; }
+
+    public boolean isDisabled() { return this.disabled; }
+    public void setDisabled(final boolean disabled) { this.disabled = disabled; }
+
+    @JsonIgnore @Nullable public UsergridUserAuth getUserAuth() { return this.userAuth; }
+    @JsonIgnore public void setUserAuth(@Nullable final UsergridUserAuth userAuth) { this.userAuth = userAuth; }
+
+    @Nullable
+    public String uuidOrUsername() {
+        String uuidOrUsername = this.getUuid();
+        if( uuidOrUsername == null ) {
+            uuidOrUsername = this.getUsername();
+        }
+        return uuidOrUsername;
+    }
+
+    @Nullable
+    public String usernameOrEmail() {
+        String usernameOrEmail = this.getUsername();
+        if( usernameOrEmail == null ) {
+            usernameOrEmail = this.getEmail();
+        }
+        return usernameOrEmail;
+    }
+
+    public static boolean checkAvailable(@Nullable final String email, @Nullable final String username) {
+        return UsergridUser.checkAvailable(Usergrid.getInstance(), email, username);
+    }
+
+    public static boolean checkAvailable(@NotNull final UsergridClient client, @Nullable final String email, @Nullable final String username) {
+        if (email == null && username == null) {
+            throw new IllegalArgumentException("email and username both are null ");
+        }
+        UsergridQuery query = new UsergridQuery(USER_ENTITY_TYPE);
+        if (username != null) {
+            query.eq(UsergridUserProperties.USERNAME.toString(), username);
+        }
+        if (email != null) {
+            query.or().eq(UsergridUserProperties.EMAIL.toString(), email);
+        }
+        return client.GET(query).first() != null;
+    }
+
+    @NotNull
+    public UsergridResponse create() {
+        return this.create(Usergrid.getInstance());
+    }
+
+    @NotNull
+    public UsergridResponse create(@NotNull final UsergridClient client) {
+        UsergridResponse response = client.POST(this);
+        UsergridUser createdUser = response.user();
+        if( createdUser != null ) {
+            this.copyAllProperties(createdUser);
+        }
+        return response;
+    }
+
+    @NotNull
+    public UsergridResponse login(@NotNull final String username, @NotNull final String password) {
+        return this.login(Usergrid.getInstance(),username,password);
+    }
+
+    @NotNull
+    public UsergridResponse login(@NotNull final UsergridClient client, @NotNull final String username, @NotNull final String password) {
+        UsergridUserAuth userAuth = new UsergridUserAuth(username,password);
+        UsergridResponse response = client.authenticateUser(userAuth,false);
+        if( response.ok() ) {
+            this.userAuth = userAuth;
+        }
+        return response;
+    }
+
+    @NotNull
+    public UsergridResponse resetPassword(@NotNull final String oldPassword, @NotNull final String newPassword) {
+        return this.resetPassword(Usergrid.getInstance(),oldPassword,newPassword);
+    }
+
+    @NotNull
+    public UsergridResponse resetPassword(@NotNull final UsergridClient client, @NotNull final String oldPassword, @NotNull final String newPassword) {
+        return client.resetPassword(this,oldPassword,newPassword);
+    }
+
+    @NotNull
+    public UsergridResponse reauthenticate() {
+        return this.reauthenticate(Usergrid.getInstance());
+    }
+
+    @NotNull
+    public UsergridResponse reauthenticate(@NotNull final UsergridClient client) {
+        return this.userAuth == null ? UsergridResponse.fromError(client, "Invalid UsergridUserAuth.", "No UsergridUserAuth found on the UsergridUser.") : client.authenticateUser(this.userAuth, false);
+    }
+
+    @NotNull
+    public UsergridResponse logout() {
+        return this.logout(Usergrid.getInstance());
+    }
+
+    @NotNull
+    public UsergridResponse logout(@NotNull final UsergridClient client) {
+        UsergridResponse response;
+        String uuidOrUsername = this.uuidOrUsername();
+        String accessToken = (this.userAuth != null) ? this.userAuth.getAccessToken() : null;
+        if (uuidOrUsername == null || accessToken == null ) {
+            response = UsergridResponse.fromError(client,  "Logout Failed.", "UUID or Access Token not found on UsergridUser object.");
+        } else {
+            response = client.logoutUser(uuidOrUsername, accessToken);
+            if( response.ok() ) {
+                this.userAuth = null;
+            }
+        }
+        return response;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/query/UsergridQuery.java b/src/main/java/org/apache/usergrid/java/client/query/UsergridQuery.java
new file mode 100644
index 0000000..e8c78c2
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/query/UsergridQuery.java
@@ -0,0 +1,431 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.query;
+
+import org.apache.usergrid.java.client.UsergridEnums.UsergridQueryOperator;
+import org.apache.usergrid.java.client.UsergridEnums.UsergridQuerySortOrder;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.net.URLEncoder;
+import java.util.*;
+
+@SuppressWarnings("unused")
+public final class UsergridQuery {
+
+    @NotNull private final ArrayList<String> requirementStrings = new ArrayList<>();
+    @NotNull private final ArrayList<String> urlTerms = new ArrayList<>();
+    @NotNull private final HashMap<String, UsergridQuerySortOrder> orderClauses = new HashMap<>();
+    @NotNull private Integer limit = UsergridQuery.LIMIT_DEFAULT;
+    @Nullable private String cursor = null;
+    @Nullable private String fromStringValue = null;
+    @Nullable private String collectionName = null;
+
+    public UsergridQuery() {
+        this(null);
+    }
+
+    public UsergridQuery(@Nullable final String collectionName) {
+        this.collectionName = collectionName;
+        this.requirementStrings.add(UsergridQuery.EMPTY_STRING);
+    }
+
+    private static boolean isUUID(@NotNull final String string) {
+        try {
+            UUID uuid = UUID.fromString(string);
+            return true;
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    @NotNull
+    private static String encode(@NotNull final String stringValue) {
+        String escapedString;
+        try {
+            escapedString = URLEncoder.encode(stringValue, UTF8);
+        } catch (Exception e) {
+            escapedString = stringValue;
+        }
+        return escapedString;
+    }
+
+    @NotNull
+    public static String strJoin(@NotNull final List<String> array, @NotNull final String separator) {
+        StringBuilder stringBuilder = new StringBuilder();
+        for (int i = 0, il = array.size(); i < il; i++) {
+            if (i > 0) {
+                stringBuilder.append(separator);
+            }
+            stringBuilder.append(array.get(i));
+        }
+        return stringBuilder.toString();
+    }
+
+    @NotNull
+    public UsergridQuery fromString(@NotNull final String stringValue) {
+        this.fromStringValue = stringValue;
+        return this;
+    }
+
+    @Nullable
+    public String getType() {
+        return this.collectionName;
+    }
+
+    @Nullable
+    public String getCollectionName() {
+        return this.collectionName;
+    }
+
+    @Nullable
+    public String getCollection() {
+        return this.collectionName;
+    }
+
+    @NotNull
+    public UsergridQuery type(@Nullable final String type) {
+        this.collectionName = type;
+        return this;
+    }
+
+    @NotNull
+    public UsergridQuery collection(@Nullable final String collectionName) {
+        return this.type(collectionName);
+    }
+
+    @NotNull
+    public UsergridQuery collectionName(@Nullable final String collectionName) {
+        return this.type(collectionName);
+    }
+
+    @NotNull
+    public UsergridQuery cursor(@Nullable final String value) {
+        this.cursor = value;
+        return this;
+    }
+
+    @NotNull
+    public UsergridQuery limit(@NotNull final Integer limit) {
+        this.limit = limit;
+        return this;
+    }
+
+    @NotNull
+    private UsergridQuery addConditionalSeparator(@NotNull final String separator) {
+        if (!this.requirementStrings.get(0).isEmpty()) {
+            this.requirementStrings.add(0, separator);
+            this.requirementStrings.add(0, UsergridQuery.EMPTY_STRING);
+        }
+        return this;
+    }
+
+    @NotNull
+    public UsergridQuery and() {
+        return this.addConditionalSeparator(UsergridQuery.AND);
+    }
+
+    @NotNull
+    public UsergridQuery or() {
+        return this.addConditionalSeparator(UsergridQuery.OR);
+    }
+
+    @NotNull
+    public UsergridQuery not() {
+        return this.addConditionalSeparator(UsergridQuery.NOT);
+    }
+
+    @NotNull
+    public UsergridQuery sort(@NotNull final String term, @NotNull final UsergridQuerySortOrder sortOrder) {
+        this.orderClauses.put(term, sortOrder);
+        return this;
+    }
+
+    @NotNull
+    public UsergridQuery ascending(@NotNull final String term) {
+        return this.asc(term);
+    }
+
+    @NotNull
+    public UsergridQuery asc(@NotNull final String term) {
+        return this.sort(term, UsergridQuerySortOrder.ASC);
+    }
+
+    @NotNull
+    public UsergridQuery descending(@NotNull final String term) {
+        return this.desc(term);
+    }
+
+    @NotNull
+    public UsergridQuery desc(@NotNull final String term) {
+        return this.sort(term, UsergridQuerySortOrder.DESC);
+    }
+
+    @NotNull
+    public UsergridQuery contains(@NotNull final String term, @NotNull final String value) {
+        return this.containsWord(term, value);
+    }
+
+    @NotNull
+    public UsergridQuery containsString(@NotNull final String term, @NotNull final String value) {
+        return this.containsWord(term, value);
+    }
+
+    @NotNull
+    public UsergridQuery containsWord(@NotNull final String term, @NotNull final String value) {
+        return this.addRequirement(term + SPACE + CONTAINS + SPACE + ((UsergridQuery.isUUID(value)) ? EMPTY_STRING : APOSTROPHE) + value + ((UsergridQuery.isUUID(value)) ? EMPTY_STRING : APOSTROPHE));
+    }
+
+    @NotNull
+    public UsergridQuery filter(@NotNull final String term, @NotNull final Object value) {
+        return this.eq(term, value);
+    }
+
+    @NotNull
+    public UsergridQuery equals(@NotNull final String term, @NotNull final Object value) {
+        return this.eq(term, value);
+    }
+
+    @NotNull
+    public UsergridQuery eq(@NotNull final String term, @NotNull final Object value) {
+        return this.addOperationRequirement(term, UsergridQueryOperator.EQUAL, value);
+    }
+
+    @NotNull
+    public UsergridQuery greaterThan(@NotNull final String term, @NotNull final Object value) {
+        return this.gt(term, value);
+    }
+
+    @NotNull
+    public UsergridQuery gt(@NotNull final String term, @NotNull final Object value) {
+        return this.addOperationRequirement(term, UsergridQueryOperator.GREATER_THAN, value);
+    }
+
+    @NotNull
+    public UsergridQuery greaterThanOrEqual(@NotNull final String term, @NotNull final Object value) {
+        return this.gte(term, value);
+    }
+
+    @NotNull
+    public UsergridQuery gte(@NotNull final String term, @NotNull final Object value) {
+        return this.addOperationRequirement(term, UsergridQueryOperator.GREATER_THAN_EQUAL_TO, value);
+    }
+
+    @NotNull
+    public UsergridQuery lessThan(@NotNull final String term, @NotNull final Object value) {
+        return this.lt(term, value);
+    }
+
+    @NotNull
+    public UsergridQuery lt(@NotNull final String term, @NotNull final Object value) {
+        return this.addOperationRequirement(term, UsergridQueryOperator.LESS_THAN, value);
+    }
+
+    @NotNull
+    public UsergridQuery lessThanOrEqual(@NotNull final String term, @NotNull final Object value) {
+        return this.lte(term, value);
+    }
+
+    @NotNull
+    public UsergridQuery lte(@NotNull final String term, @NotNull final Object value) {
+        return this.addOperationRequirement(term, UsergridQueryOperator.LESS_THAN_EQUAL_TO, value);
+    }
+
+    @NotNull
+    public UsergridQuery locationWithin(final double distance, final double latitude, final double longitude) {
+        return this.addRequirement(LOCATION + SPACE + WITHIN + SPACE + distance + SPACE + OF + SPACE + latitude + SPACE + COMMA + longitude);
+    }
+
+    @NotNull
+    public UsergridQuery urlTerm(@NotNull final String term, @NotNull final String equalsValue) {
+        if (term.equalsIgnoreCase(QL)) {
+            this.ql(equalsValue);
+        } else {
+            this.urlTerms.add(UsergridQuery.encode(term) + EQUALS + UsergridQuery.encode(equalsValue));
+        }
+        return this;
+    }
+
+    @NotNull
+    public UsergridQuery ql(final String value) {
+
+        return value != null && !value.isEmpty() ? this.addRequirement(value) : this;
+
+    }
+
+    @NotNull
+    public UsergridQuery addRequirement(@NotNull final String requirement) {
+        String requirementString = this.requirementStrings.remove(0);
+        if (!requirement.isEmpty() && !requirementString.isEmpty()) {
+            requirementString += SPACE + AND + SPACE;
+        }
+        requirementString += requirement;
+        this.requirementStrings.add(0, requirementString);
+        return this;
+    }
+
+    @NotNull
+    public UsergridQuery addOperationRequirement(@NotNull final String term, @NotNull final UsergridQueryOperator operation, final int intValue) {
+        return this.addOperationRequirement(term, operation, Integer.valueOf(intValue));
+    }
+
+    @NotNull
+    public UsergridQuery addOperationRequirement(@NotNull final String term, @NotNull final UsergridQueryOperator operation, @NotNull final Object value) {
+        if (value instanceof String) {
+            String valueString = value.toString();
+            if (!UsergridQuery.isUUID(valueString)) {
+                valueString = APOSTROPHE + value + APOSTROPHE;
+            }
+            return addRequirement(term + SPACE + operation.operatorValue() + SPACE + valueString);
+        } else {
+            return addRequirement(term + SPACE + operation.operatorValue() + SPACE + value.toString());
+        }
+    }
+
+    @NotNull
+    private String constructOrderByString() {
+        String orderByString = EMPTY_STRING;
+        if (!this.orderClauses.isEmpty()) {
+            for (Map.Entry<String, UsergridQuerySortOrder> orderClause : this.orderClauses.entrySet()) {
+                if (!orderByString.isEmpty()) {
+                    orderByString += COMMA;
+                }
+                orderByString += orderClause.getKey() + SPACE + orderClause.getValue().toString();
+            }
+            if (!orderByString.isEmpty()) {
+                orderByString = SPACE + ORDER_BY + SPACE + orderByString;
+            }
+        }
+        return orderByString;
+    }
+
+    @NotNull
+    private String constructURLTermsString() {
+        String urlTermsString = EMPTY_STRING;
+        if (!this.urlTerms.isEmpty()) {
+            urlTermsString = UsergridQuery.strJoin(this.urlTerms, AMPERSAND);
+        }
+        return urlTermsString;
+    }
+
+    @NotNull
+    private String constructRequirementString() {
+        ArrayList<String> requirementStrings = new ArrayList<>(this.requirementStrings);
+        String firstString = requirementStrings.get(0);
+        if (firstString.isEmpty()) {
+            requirementStrings.remove(0);
+        }
+        String requirementsString = EMPTY_STRING;
+        if (!requirementStrings.isEmpty()) {
+            firstString = requirementStrings.get(0);
+            if (firstString.equalsIgnoreCase(OR) || firstString.equalsIgnoreCase(AND) || firstString.equalsIgnoreCase(NOT)) {
+                requirementStrings.remove(0);
+            }
+            if (!requirementStrings.isEmpty()) {
+                Collections.reverse(requirementStrings);
+                requirementsString = UsergridQuery.strJoin(requirementStrings, SPACE);
+            }
+        }
+        return requirementsString;
+    }
+
+    @NotNull
+    private String constructURLAppend() {
+        return this.constructURLAppend(true);
+    }
+
+    @NotNull
+    private String constructURLAppend(final boolean autoURLEncode) {
+        if (this.fromStringValue != null) {
+            String requirementsString = this.fromStringValue;
+            if (autoURLEncode) {
+                requirementsString = UsergridQuery.encode(requirementsString);
+            }
+            return QUESTION_MARK + QL + EQUALS + requirementsString;
+        }
+        String urlAppend = EMPTY_STRING;
+        if (this.limit != LIMIT_DEFAULT) {
+            urlAppend += LIMIT + EQUALS + this.limit.toString();
+        }
+        String urlTermsString = this.constructURLTermsString();
+        if (!urlTermsString.isEmpty()) {
+            if (!urlAppend.isEmpty()) {
+                urlAppend += AMPERSAND;
+            }
+            urlAppend += urlTermsString;
+        }
+        if (this.cursor != null && !this.cursor.isEmpty()) {
+            if (!urlAppend.isEmpty()) {
+                urlAppend += AMPERSAND;
+            }
+            urlAppend += CURSOR + EQUALS + this.cursor;
+        }
+
+        String requirementsString = this.constructRequirementString();
+
+        String orderByString = this.constructOrderByString();
+        if (!orderByString.isEmpty()) {
+            requirementsString += orderByString;
+        }
+        if (!requirementsString.isEmpty()) {
+            if (autoURLEncode) {
+                requirementsString = UsergridQuery.encode(requirementsString);
+            }
+            if (!urlAppend.isEmpty()) {
+                urlAppend += AMPERSAND;
+            }
+            urlAppend += QL + EQUALS + requirementsString;
+        }
+        if (!urlAppend.isEmpty()) {
+            urlAppend = QUESTION_MARK + urlAppend;
+        }
+        return urlAppend;
+    }
+
+    @NotNull
+    public String build() {
+        return this.build(true);
+    }
+
+    @NotNull
+    public String build(final boolean autoURLEncode) {
+        return this.constructURLAppend(autoURLEncode);
+    }
+
+    private static final int LIMIT_DEFAULT = 10;
+    @NotNull private static final String AMPERSAND = "&";
+    @NotNull private static final String AND = "and";
+    @NotNull private static final String APOSTROPHE = "'";
+    @NotNull private static final String COMMA = ",";
+    @NotNull private static final String CONTAINS = "contains";
+    @NotNull private static final String CURSOR = "cursor";
+    @NotNull private static final String EMPTY_STRING = "";
+    @NotNull private static final String EQUALS = "=";
+    @NotNull private static final String LIMIT = "limit";
+    @NotNull private static final String LOCATION = "location";
+    @NotNull private static final String NOT = "not";
+    @NotNull private static final String OF = "of";
+    @NotNull private static final String OR = "or";
+    @NotNull private static final String ORDER_BY = "order by";
+    @NotNull private static final String QL = "ql";
+    @NotNull private static final String QUESTION_MARK = "?";
+    @NotNull private static final String SELECT_ALL = "select *";
+    @NotNull private static final String SPACE = " ";
+    @NotNull private static final String UTF8 = "UTF-8";
+    @NotNull private static final String WHERE = "where";
+    @NotNull private static final String WITHIN = "within";
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/response/UsergridResponse.java b/src/main/java/org/apache/usergrid/java/client/response/UsergridResponse.java
new file mode 100644
index 0000000..ee649c4
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/response/UsergridResponse.java
@@ -0,0 +1,230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.response;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.databind.JsonNode;
+import okhttp3.Headers;
+import org.apache.usergrid.java.client.UsergridClient;
+import org.apache.usergrid.java.client.UsergridEnums;
+import org.apache.usergrid.java.client.UsergridRequest;
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.apache.usergrid.java.client.model.UsergridUser;
+import org.apache.usergrid.java.client.query.UsergridQuery;
+import org.apache.usergrid.java.client.utils.JsonUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+import static org.apache.usergrid.java.client.utils.JsonUtils.toJsonString;
+
+@SuppressWarnings("unused")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class UsergridResponse {
+
+    @Nullable private UsergridClient client;
+    @NotNull private Map<String, JsonNode> properties = new HashMap<>();
+
+    private int statusCode = 0;
+    @Nullable private JsonNode responseJson = null;
+    @Nullable private String cursor;
+    @Nullable private List<UsergridEntity> entities;
+    @Nullable private Map<String, String> headers;
+    @Nullable private UsergridQuery query;
+    @Nullable private UsergridResponseError responseError = null;
+
+    @Nullable private String accessToken;
+    @Nullable private Long expires;
+
+    public boolean ok() { return (statusCode > 0 && statusCode < 400); }
+    public int count()  { return (entities == null) ? 0 : entities.size(); }
+    public boolean hasNextPage() { return (cursor != null); }
+    @NotNull @Override public String toString() {
+        return toJsonString(this);
+    }
+
+    @Nullable public UsergridEntity first() { return (entities == null || entities.isEmpty()) ? null : entities.get(0); }
+    @Nullable public UsergridEntity entity() {
+        return first();
+    }
+    @Nullable public UsergridEntity last() { return (entities == null || entities.isEmpty()) ? null : entities.get(entities.size() - 1); }
+
+    @Nullable
+    public UsergridUser user() {
+        UsergridEntity entity = this.first();
+        if( entity != null && entity instanceof UsergridUser ) {
+            return (UsergridUser) entity;
+        }
+        return null;
+    }
+
+    @Nullable
+    public List<UsergridUser> users() {
+        ArrayList<UsergridUser> users = null;
+        if( entities != null && !entities.isEmpty() ) {
+            for( UsergridEntity entity : entities ) {
+                if( entity instanceof UsergridUser ) {
+                    if( users == null )  {
+                        users = new ArrayList<>();
+                    }
+                    users.add((UsergridUser)entity);
+                }
+            }
+        }
+        return users;
+    }
+
+    public int getStatusCode() { return this.statusCode; }
+
+    @Nullable @JsonIgnore
+    public UsergridClient getClient() {
+        return client;
+    }
+    @JsonIgnore public void setClient(@Nullable final UsergridClient client) { this.client = client; }
+
+    @Nullable @JsonIgnore
+    public JsonNode getResponseJson() {
+        return responseJson;
+    }
+    private void setResponseJson(@Nullable final JsonNode responseJson) {this.responseJson = responseJson; }
+
+    @Nullable @JsonIgnore
+    public UsergridQuery getQuery() {
+        return query;
+    }
+    private void setQuery(@Nullable final UsergridQuery query) { this.query = query; }
+
+    @Nullable
+    public UsergridResponseError getResponseError() {
+        return responseError;
+    }
+    private void setResponseError(@Nullable final UsergridResponseError responseError) { this.responseError = responseError; }
+
+    @Nullable
+    public Map<String, String> getHeaders() {
+        return headers;
+    }
+    private void setHeaders(@Nullable final Map<String, String> headers) { this.headers = headers; }
+
+    @Nullable
+    public List<UsergridEntity> getEntities() { return entities; }
+    private void setEntities(@NotNull final List<UsergridEntity> entities) { this.entities = entities; }
+
+    @Nullable @JsonProperty("cursor")
+    public String getCursor() {
+        return cursor;
+    }
+    @JsonProperty("cursor")
+    private void setCursor(@NotNull final String cursor) { this.cursor = cursor; }
+
+    @Nullable @JsonProperty("access_token")
+    public String getAccessToken() { return this.accessToken; }
+    @JsonProperty("access_token")
+    private void setAccessToken(@NotNull final String accessToken) { this.accessToken = accessToken; }
+
+    @Nullable @JsonProperty("expires_in")
+    public Long getExpires() { return this.expires; }
+    @JsonProperty("expires_in")
+    private void setExpires(@NotNull final Long expires) { this.expires = expires; }
+
+    @JsonProperty("user")
+    private void setUser(@NotNull final UsergridUser user) {
+        if( this.entities == null ) {
+            this.entities = new ArrayList<>();
+        }
+        this.entities.add(user);
+    }
+
+    @NotNull @JsonAnyGetter
+    public Map<String, JsonNode> getProperties() {
+        return properties;
+    }
+    @JsonAnySetter
+    private void setProperty(@NotNull final  String key, @NotNull final JsonNode value) {
+        properties.put(key, value);
+    }
+
+    @NotNull
+    public UsergridResponse loadNextPage() {
+        UsergridClient client = this.client;
+        UsergridEntity entity = this.first();
+        if( this.hasNextPage() && client != null && entity != null ) {
+            Map<String, Object> paramsMap = new HashMap<>();
+            paramsMap.put("cursor", getCursor());
+            UsergridRequest request = new UsergridRequest(UsergridEnums.UsergridHttpMethod.GET, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, client.clientAppUrl(), paramsMap, null, null, this.getQuery(), client.authForRequests() , entity.getType());
+            return client.sendRequest(request);
+        } else {
+            return UsergridResponse.fromError(client,"Error Loading Next Page.","Unable to load next page.");
+        }
+    }
+
+    @NotNull
+    public static UsergridResponse fromError(@Nullable final UsergridClient client, @NotNull final String errorName, @NotNull final String errorDescription) {
+        UsergridResponse response = new UsergridResponse();
+        response.client = client;
+        response.responseError = new UsergridResponseError(errorName,errorDescription);
+        return response;
+    }
+
+    @NotNull
+    public static UsergridResponse fromException(@Nullable final UsergridClient client, @NotNull final Exception ex) {
+        final UsergridResponse response = new UsergridResponse();
+        response.client = client;
+        final UsergridResponseError responseError = new UsergridResponseError();
+        responseError.setErrorDescription(ex.getMessage());
+        if( ex.getClass() != null ) {
+            responseError.setErrorName(ex.getClass().toString());
+        }
+        if( ex.getCause() != null ) {
+            responseError.setErrorException(ex.getCause().toString());
+        }
+        response.responseError = responseError;
+        return response;
+    }
+
+    @NotNull
+    public static UsergridResponse fromResponse(@NotNull final UsergridClient client, @NotNull final UsergridRequest request, @NotNull final okhttp3.Response requestResponse) {
+        UsergridResponse response;
+        JsonNode responseJson;
+        try {
+            String responseJsonString = requestResponse.body().string();
+            responseJson = JsonUtils.mapper.readTree(responseJsonString);
+        } catch ( Exception e ) {
+            return UsergridResponse.fromException(client,e);
+        }
+        if ( responseJson.has("error") )  {
+            response = new UsergridResponse();
+            response.responseError = JsonUtils.fromJsonNode(responseJson,UsergridResponseError.class);
+        } else {
+            response = JsonUtils.fromJsonNode(responseJson,UsergridResponse.class);
+        }
+        response.client = client;
+        response.responseJson = responseJson;
+        response.statusCode = requestResponse.code();
+
+        Headers responseHeaders = requestResponse.headers();
+        HashMap<String,String> headers = new HashMap<>();
+        for (int i = 0; i < responseHeaders.size(); i++) {
+            headers.put(responseHeaders.name(i),responseHeaders.value(i));
+        }
+
+        response.headers = headers;
+        response.query = request.getQuery();
+        return response;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/response/UsergridResponseError.java b/src/main/java/org/apache/usergrid/java/client/response/UsergridResponseError.java
new file mode 100644
index 0000000..387ae56
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/response/UsergridResponseError.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.response;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@SuppressWarnings("unused")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class UsergridResponseError {
+
+    @Nullable private String errorName;
+    @Nullable private String errorDescription;
+    @Nullable private String errorException;
+
+    @NotNull private final Map<String, JsonNode> properties = new HashMap<>();
+
+    public UsergridResponseError() {
+        this(null,null,null);
+    }
+    public UsergridResponseError(@Nullable final String errorName) {
+        this(errorName, null, null);
+    }
+    public UsergridResponseError(@Nullable final String errorName, @Nullable final String errorDescription) {
+        this(errorName,errorDescription,null);
+    }
+    public UsergridResponseError(@Nullable final String errorName, @Nullable final String errorDescription, @Nullable final String errorException) {
+        this.errorName = errorName;
+        this.errorDescription = errorDescription;
+        this.errorException = errorException;
+    }
+
+    @NotNull
+    @JsonAnyGetter
+    public Map<String, JsonNode> getProperties() {
+        return properties;
+    }
+
+    @JsonAnySetter
+    public void setProperty(@NotNull final String key, @NotNull final JsonNode value) {
+        properties.put(key, value);
+    }
+
+    @Nullable
+    @JsonProperty("error")
+    public String getErrorName() {
+        return errorName;
+    }
+
+    @JsonProperty("error")
+    public void setErrorName(@NotNull final String errorName) {
+        this.errorName = errorName;
+    }
+
+    @Nullable
+    @JsonProperty("exception")
+    public String getErrorException() {
+        return errorException;
+    }
+
+    @JsonProperty("exception")
+    public void setErrorException(@NotNull final String errorException) {
+        this.errorException = errorException;
+    }
+
+    @Nullable
+    @JsonProperty("error_description")
+    public String getErrorDescription() {
+        return errorDescription;
+    }
+
+    @JsonProperty("error_description")
+    public void setErrorDescription(@NotNull final String errorDescription) {
+        this.errorDescription = errorDescription;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/utils/JsonUtils.java b/src/main/java/org/apache/usergrid/java/client/utils/JsonUtils.java
new file mode 100644
index 0000000..dc1514b
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/utils/JsonUtils.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.utils;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.node.*;
+import org.apache.usergrid.java.client.exception.UsergridException;
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+
+@SuppressWarnings("unused")
+public final class JsonUtils {
+
+    @NotNull public static final ObjectMapper mapper = new ObjectMapper();
+
+    static {
+        SimpleModule module = new SimpleModule();
+        module.addDeserializer(UsergridEntity.class, new UsergridEntityDeserializer());
+        mapper.registerModule(module);
+    }
+
+    @NotNull
+    public static ObjectNode createObjectNode() {
+        return mapper.createObjectNode();
+    }
+
+    @Nullable
+    public static String getStringProperty(@NotNull final Map<String, JsonNode> properties, @NotNull final String name) {
+        JsonNode value = properties.get(name);
+        if (value != null) {
+            return value.asText();
+        }
+        return null;
+    }
+
+    @NotNull
+    public static ArrayList<Object> convertToArrayList(@NotNull final ArrayNode arrayNode) {
+        ArrayList<Object> arrayList = new ArrayList<>();
+        Iterator<JsonNode> iterator = arrayNode.elements();
+        while( iterator.hasNext() ) {
+            arrayList.add(iterator.next());
+        }
+        return arrayList;
+    }
+
+    @NotNull
+    public static String toJsonString(@NotNull final Object obj) {
+        try {
+            return mapper.writeValueAsString(obj);
+        } catch (JsonGenerationException e) {
+            throw new UsergridException("Unable to generate json", e);
+        } catch (JsonMappingException e) {
+            throw new UsergridException("Unable to map json", e);
+        } catch (IOException e) {
+            throw new UsergridException("IO error", e);
+        }
+    }
+
+    @NotNull
+    public static String toPrettyJsonString(@NotNull final Object obj) {
+        try {
+            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
+        } catch (JsonGenerationException e) {
+            throw new UsergridException("Unable to generate json", e);
+        } catch (JsonMappingException e) {
+            throw new UsergridException("Unable to map json", e);
+        } catch (IOException e) {
+            throw new UsergridException("IO error", e);
+        }
+    }
+
+    @NotNull
+    public static JsonNode toJsonNode(@NotNull final Object obj) {
+        return mapper.convertValue(obj, JsonNode.class);
+    }
+
+    @NotNull
+    public static Map toMap(@NotNull final Object obj) {
+        return mapper.convertValue(obj,Map.class);
+    }
+
+    @NotNull
+    public static <T> T fromJsonNode(@NotNull final JsonNode json, @NotNull final Class<T> c) {
+        try {
+            JsonParser jp = json.traverse();
+            return mapper.readValue(jp, c);
+        } catch (JsonGenerationException e) {
+            throw new UsergridException("Unable to generate json", e);
+        } catch (JsonMappingException e) {
+            throw new UsergridException("Unable to map json", e);
+        } catch (IOException e) {
+            throw new UsergridException("IO error", e);
+        }
+    }
+
+    public static void setObjectProperty(@NotNull final Map<String, JsonNode> properties, @NotNull final String name, @Nullable final ObjectNode value) {
+        if (value == null) {
+            properties.remove(name);
+        } else {
+            properties.put(name, value);
+        }
+    }
+
+    @Nullable
+    @SuppressWarnings("unchecked")
+    public static <T> T getProperty(@NotNull final Map<String, JsonNode> properties, @NotNull final String name) {
+        JsonNode value = properties.get(name);
+        if( value == null ) {
+            return null;
+        } else if (value instanceof TextNode) {
+            return (T) value.asText();
+        } else if (value instanceof LongNode) {
+            Long valueLong = value.asLong();
+            return (T) valueLong;
+        } else if (value instanceof BooleanNode) {
+            Boolean valueBoolean = value.asBoolean();
+            return (T) valueBoolean;
+        } else if (value instanceof IntNode) {
+            Integer valueInteger = value.asInt();
+            return (T) valueInteger;
+        } else if (value instanceof FloatNode) {
+            return (T) Float.valueOf(value.toString());
+        } else {
+            return (T) value;
+        }
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/utils/MapUtils.java b/src/main/java/org/apache/usergrid/java/client/utils/MapUtils.java
new file mode 100644
index 0000000..cbf6d51
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/utils/MapUtils.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.utils;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("unused")
+public final class MapUtils {
+
+    @NotNull
+    public static <T> Map<String, T> newMapWithoutKeys(@NotNull  final Map<String, T> map, @NotNull final List<String> keys) {
+        Map<String, T> newMap = new HashMap<>();
+        for (String key : keys) {
+            newMap.remove(key);
+        }
+        return newMap;
+    }
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/utils/ObjectUtils.java b/src/main/java/org/apache/usergrid/java/client/utils/ObjectUtils.java
new file mode 100644
index 0000000..1d05405
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/utils/ObjectUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.utils;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+
+public final class ObjectUtils {
+
+    public static boolean isEmpty(@Nullable final Object s) {
+        if (s == null) {
+            return true;
+        }
+        if ((s instanceof String) && (((String) s).trim().length() == 0)) {
+            return true;
+        }
+        if (s instanceof Map) {
+            return ((Map<?, ?>) s).isEmpty();
+        }
+        return false;
+    }
+
+}
diff --git a/src/main/java/org/apache/usergrid/java/client/utils/UsergridEntityDeserializer.java b/src/main/java/org/apache/usergrid/java/client/utils/UsergridEntityDeserializer.java
new file mode 100644
index 0000000..5daeace
--- /dev/null
+++ b/src/main/java/org/apache/usergrid/java/client/utils/UsergridEntityDeserializer.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.java.client.utils;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+
+public final class UsergridEntityDeserializer extends JsonDeserializer<UsergridEntity> {
+
+    @NotNull private static final ObjectMapper objectMapper = new ObjectMapper();
+
+    @NotNull
+    public UsergridEntity deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
+        UsergridEntity entity = UsergridEntityDeserializer.objectMapper.readValue(jsonParser,UsergridEntity.class);
+        Class<? extends UsergridEntity> entitySubClass = UsergridEntity.customSubclassForType(entity.getType());
+        if( entitySubClass != null ) {
+            entity = JsonUtils.mapper.convertValue(entity,entitySubClass);
+        }
+        return entity;
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/ClientAuthFallBackTestCase.java b/src/test/java/org/apache/usergrid/client/ClientAuthFallBackTestCase.java
new file mode 100644
index 0000000..944aaef
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/ClientAuthFallBackTestCase.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.*;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.query.UsergridQuery;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertTrue;
+
+public class ClientAuthFallBackTestCase {
+
+    private static UsergridQuery usersQuery = new UsergridQuery("users").desc("created");
+
+    @Before
+    public void before() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL, SDKTestConfiguration.authFallBack);
+        Usergrid.authenticateApp(new UsergridAppAuth(SDKTestConfiguration.APP_CLIENT_ID, SDKTestConfiguration.APP_CLIENT_SECRET));
+
+        String[] segments = {"roles","guest","permissions"};
+        Map<String, Object> params = new HashMap<>();
+        params.put("permission","get,post,put,delete:/**");
+        UsergridRequest request = new UsergridRequest(UsergridEnums.UsergridHttpMethod.DELETE, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, Usergrid.clientAppUrl(), params, null, Usergrid.authForRequests(), segments);
+        Usergrid.sendRequest(request);
+    }
+
+    @After
+    public void after() {
+        Usergrid.setAuthMode(UsergridEnums.UsergridAuthMode.APP);
+        String[] segments = {"roles","guest","permissions"};
+        Map<String, Object> params = new HashMap<>();
+        params.put("permission","get,post,put,delete:/**");
+        UsergridRequest request = new UsergridRequest(UsergridEnums.UsergridHttpMethod.POST, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE, Usergrid.clientAppUrl(), params, null, Usergrid.authForRequests(), segments);
+        Usergrid.sendRequest(request);
+        Usergrid.reset();
+    }
+
+    @Test
+    public void authFallBackNONETest() {
+        Usergrid.setAuthMode(UsergridEnums.UsergridAuthMode.NONE);
+        UsergridResponse resp = Usergrid.GET(usersQuery);
+        assertTrue("The returned response should have error", resp.getResponseError() != null);
+    }
+
+    @Test
+    public void authFallBackAPPTest() {
+        Usergrid.setAuthMode(UsergridEnums.UsergridAuthMode.APP);
+        UsergridResponse resp = Usergrid.GET(usersQuery);
+        assertTrue("The returned response should not have error", resp.getResponseError() == null);
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/ClientAuthTestCase.java b/src/test/java/org/apache/usergrid/client/ClientAuthTestCase.java
new file mode 100644
index 0000000..79e1bbc
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/ClientAuthTestCase.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.UsergridEnums.*;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.auth.UsergridUserAuth;
+import org.apache.usergrid.java.client.model.UsergridUser;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class ClientAuthTestCase {
+
+    @Before
+    public void before() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL);
+    }
+
+    @After
+    public void after() {
+        Usergrid.reset();
+    }
+
+    @Test
+    public void clientAuth_APP() {
+        Usergrid.setAuthMode(UsergridAuthMode.APP);
+        UsergridAppAuth appAuth = new UsergridAppAuth(SDKTestConfiguration.APP_CLIENT_ID, SDKTestConfiguration.APP_CLIENT_SECRET);
+        UsergridResponse response = Usergrid.authenticateApp(appAuth);
+        assertTrue("response status is OK", response.ok());
+        assertNull("no error thrown", response.getResponseError());
+        assertTrue("appAuth.isValidToken should be true", appAuth.isValidToken());
+        assertNotNull("should have a valid token", appAuth.getAccessToken());
+        assertNotNull("should have an expiry", appAuth.getExpiry());
+        assertEquals("client.appAuth.token should be set to the token returned from Usergrid", Usergrid.getAppAuth(), appAuth);
+        assertTrue("should have a token that is not empty", appAuth.getAccessToken().length() > 0);
+        assertTrue("client.appAuth.expiry should be set to a future date", appAuth.getExpiry() > System.currentTimeMillis());
+    }
+
+    @Test
+    public void clientAuth_USER() {
+        Usergrid.setAuthMode(UsergridAuthMode.USER);
+        UsergridUserAuth userAuth = new UsergridUserAuth(SDKTestConfiguration.APP_UserName, SDKTestConfiguration.APP_Password);
+        UsergridResponse response = Usergrid.authenticateUser(userAuth);
+        assertTrue("response status is OK", response.ok());
+        assertNull("no error thrown", response.getResponseError());
+        assertTrue("appAuth.isValidToken should be true", userAuth.isValidToken());
+        assertNotNull("should have a token", userAuth.getAccessToken());
+        assertNotNull("should have an expiry", userAuth.getExpiry());
+
+        UsergridUser currentUser = Usergrid.getCurrentUser();
+        assertNotNull("client.currentUser should not be null", currentUser);
+        assertNotNull("client.currentUser().getUserAuth() should not be null", currentUser.getUserAuth());
+        assertEquals("client.currentUser().userAuth should be the same as userAuth", currentUser.getUserAuth(), userAuth);
+        assertTrue("should have a token that is not empty", userAuth.getAccessToken().length() > 0);
+        assertTrue("client.currentUser().userAuth.getExpiry() should be set to a future date", userAuth.getExpiry() > System.currentTimeMillis());
+        assertEquals("client.authForRequests() should be the same as userAuth", Usergrid.authForRequests(), userAuth);
+    }
+
+    @Test
+    public void clientAuth_NONE() {
+        Usergrid.setAuthMode(UsergridAuthMode.NONE);
+        UsergridUserAuth userAuth = new UsergridUserAuth(SDKTestConfiguration.APP_UserName, SDKTestConfiguration.APP_Password);
+        Usergrid.authenticateUser(userAuth);
+        assertNull("no auth should be returned from client.authForRequests", Usergrid.authForRequests());
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/ClientConnectionsTestCase.java b/src/test/java/org/apache/usergrid/client/ClientConnectionsTestCase.java
new file mode 100644
index 0000000..72b88dd
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/ClientConnectionsTestCase.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.UsergridEnums.UsergridDirection;
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class ClientConnectionsTestCase {
+
+    @Before
+    public void before() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL, SDKTestConfiguration.authFallBack);
+        UsergridAppAuth appAuth = new UsergridAppAuth(SDKTestConfiguration.APP_CLIENT_ID, SDKTestConfiguration.APP_CLIENT_SECRET);
+        Usergrid.authenticateApp(appAuth);
+    }
+
+    @After
+    public void after() {
+        Usergrid.reset();
+    }
+
+    @Test
+    public void clientConnect() {
+        String collectionName = "testClientConnection" + System.currentTimeMillis();
+
+        UsergridEntity entityOne = new UsergridEntity(collectionName,"john");
+        entityOne.putProperty("place","San Jose");
+        entityOne.save();
+        assertNotNull(entityOne.getUuid());
+
+        UsergridEntity entityTwo = new UsergridEntity(collectionName,"amici");
+        entityOne.putProperty("place","San Jose");
+        entityTwo.save();
+        assertNotNull(entityTwo.getUuid());
+
+        //should connect entities by passing UsergridEntity objects as parameters
+        Usergrid.connect(entityOne, "likes", entityTwo);
+
+        UsergridEntity responseEntity = Usergrid.getConnections(UsergridDirection.OUT, entityOne, "likes").first();
+        assertNotNull(responseEntity);
+        assertEquals("both entities name should be same", entityTwo.getName(),responseEntity.getName());
+        assertEquals("both entities uuid should be same", entityTwo.getUuid(),responseEntity.getUuid());
+
+        //should connect entities by passing a source UsergridEntity object and a target uuid.
+        Usergrid.connect(entityOne.getType(), entityOne.getUuid(), "visited", entityTwo.getUuid());
+
+        responseEntity = Usergrid.getConnections(UsergridDirection.OUT, entityOne, "visited").first();
+        assertNotNull(responseEntity);
+        assertEquals("both entities name should be same", entityTwo.getName(),responseEntity.getName());
+        assertEquals("both entities uuid should be same", entityTwo.getUuid(),responseEntity.getUuid());
+
+        //should connect entities by passing source type, source uuid, and target uuid as parameters
+        Usergrid.connect(entityTwo.getType(), entityTwo.getUuid(), "visitor", entityOne.getUuid());
+
+        responseEntity = Usergrid.getConnections(UsergridDirection.OUT, entityTwo, "visitor").first();
+        assertNotNull(responseEntity);
+        assertEquals("both entities name should be same", entityOne.getName(),responseEntity.getName());
+        assertEquals("both entities uuid should be same", entityOne.getUuid(),responseEntity.getUuid());
+
+        //should connect entities by passing source type, source name, target type, and target name as parameters
+        assertNotNull(entityOne.getName());
+        assertNotNull(entityTwo.getName());
+        Usergrid.connect(entityTwo.getType(), entityTwo.getName(), "welcomed", entityOne.getType(), entityOne.getName());
+
+        responseEntity = Usergrid.getConnections(UsergridDirection.OUT, entityTwo, "welcomed").first();
+        assertNotNull(responseEntity);
+        assertEquals("both entities name should be same", entityOne.getName(),responseEntity.getName());
+        assertEquals("both entities uuid should be same", entityOne.getUuid(),responseEntity.getUuid());
+
+        //should connect entities by passing source type, source name, target type, and target name as parameters
+        Usergrid.connect(entityTwo.getType(), entityTwo.getName(), "invalidLink", "invalidName");
+        responseEntity = Usergrid.getConnections(UsergridDirection.OUT, entityTwo, "invalidLink").first();
+        assertNull("response entity should be null.", responseEntity);
+    }
+
+    @Test
+    public void clientGetConnect() {
+        String collectionName = "testClientGetConnection" + System.currentTimeMillis();
+
+        //should set properties for a given object, overwriting properties that exist and creating those that don\'t
+        UsergridEntity entityOne = new UsergridEntity(collectionName, "john");
+        entityOne.putProperty("place","San Jose");
+        entityOne.save();
+
+        //should set properties for a given object, overwriting properties that exist and creating those that don\'t
+        UsergridEntity entityTwo = new UsergridEntity(collectionName, "amici");
+        entityTwo.putProperty("place","San Jose");
+        entityTwo.save();
+
+        //should connect entities by passing UsergridEntity objects as parameters
+        Usergrid.connect(entityOne, "likes", entityTwo);
+        Usergrid.connect(entityOne, "visited", entityTwo);
+
+        UsergridEntity responseEntity = Usergrid.getConnections(UsergridDirection.OUT, entityOne, "likes").first();
+        assertNotNull(responseEntity);
+        assertEquals("both entities name should be same", entityTwo.getName(),responseEntity.getName());
+        assertEquals("both entities uuid should be same", entityTwo.getUuid(),responseEntity.getUuid());
+
+        responseEntity = Usergrid.getConnections(UsergridDirection.IN, entityTwo, "visited").first();
+        assertNotNull(responseEntity);
+        assertEquals("both entities name should be same", entityOne.getName(),responseEntity.getName());
+        assertEquals("both entities uuid should be same", entityOne.getUuid(),responseEntity.getUuid());
+
+    }
+
+    @Test
+    public void clientDisConnect() {
+        String collectionName = "testClientGetConnection" + System.currentTimeMillis();
+
+        //should set properties for a given object, overwriting properties that exist and creating those that don\'t
+        UsergridEntity entityOne = new UsergridEntity(collectionName,"john");
+        entityOne.putProperty("place","San Jose");
+        entityOne.save();
+        assertNotNull(entityOne.getName());
+        assertNotNull(entityOne.getUuid());
+
+        //should set properties for a given object, overwriting properties that exist and creating those that don\'t
+        UsergridEntity entityTwo = new UsergridEntity(collectionName, "amici");
+        entityTwo.putProperty("place","San Jose");
+        entityTwo.save();
+        assertNotNull(entityTwo.getName());
+        assertNotNull(entityTwo.getUuid());
+
+        //should connect entities by passing UsergridEntity objects as parameters
+        Usergrid.connect(entityOne, "likes", entityTwo);
+        Usergrid.connect(entityOne, "visited", entityTwo);
+        Usergrid.connect(entityOne, "twice", entityTwo);
+        Usergrid.connect(entityOne, "thrice", entityTwo);
+
+        //should disConnect entities by passing UsergridEntity objects as parameters
+        Usergrid.disconnect(entityOne, "likes", entityTwo);
+        UsergridEntity responseEntity = Usergrid.getConnections(UsergridDirection.IN, entityTwo, "likes").first();
+        assertNull("responseEntity should be null", responseEntity);
+
+        //should disConnect entities by passing source type, source uuid, and target uuid as parameters
+        Usergrid.disconnect(entityOne.getType(), entityOne.getUuid(), "visited", entityTwo.getUuid());
+        responseEntity = Usergrid.getConnections(UsergridDirection.OUT, entityOne, "visited").first();
+        assertNull("responseEntity should be null", responseEntity);
+
+        //should disConnect entities by passing source type, source name, target type, and target name as parameters
+        Usergrid.disconnect(entityOne.getType(), entityOne.getName(), "twice", entityTwo.getType(), entityTwo.getName());
+        responseEntity = Usergrid.getConnections(UsergridDirection.OUT, entityOne, "twice").first();
+        assertNull("responseEntity should be null", responseEntity);
+
+        //should fail to disConnect entities when specifying target name without type
+        Usergrid.disconnect(entityTwo.getType(), entityTwo.getName(), "thrice", entityOne.getName());
+        responseEntity = Usergrid.getConnections(UsergridDirection.OUT, entityTwo, "thrice").first();
+        assertNull("both entities name should be same",responseEntity);
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/ClientRestTestCase.java b/src/test/java/org/apache/usergrid/client/ClientRestTestCase.java
new file mode 100644
index 0000000..b01a167
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/ClientRestTestCase.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.Assert.*;
+
+public class ClientRestTestCase {
+
+    final String collectionName = "testClientConnection" + System.currentTimeMillis();
+
+    @Before
+    public void before()  {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL, SDKTestConfiguration.authFallBack);
+        UsergridAppAuth appAuth = new UsergridAppAuth(SDKTestConfiguration.APP_CLIENT_ID, SDKTestConfiguration.APP_CLIENT_SECRET);
+        Usergrid.authenticateApp(appAuth);
+        createCollectionAndEntity();
+    }
+
+    @After
+    public void after() {
+        Usergrid.reset();
+    }
+
+    public void createCollectionAndEntity()  {
+        UsergridEntity entityOne = new UsergridEntity(collectionName,"john");
+        entityOne.putProperty("place", "San Jose");
+        entityOne.save();
+
+        UsergridEntity entityTwo = new UsergridEntity(collectionName,"amici");
+        entityTwo.putProperty("place", "San Jose");
+        entityTwo.save();
+
+        assertNotNull(entityOne.getUuid());
+        assertNotNull(entityTwo.getUuid());
+
+        Usergrid.connect(entityOne, "likes", entityTwo);
+        Usergrid.connect(entityOne.getType(), entityOne.getUuid(), "visited", entityTwo.getUuid());
+    }
+
+    @Test
+    public void clientGET() {
+        // Retrieve the response.
+        UsergridResponse response = Usergrid.GET(collectionName, "john");
+        assertTrue("response should be ok", response.ok());
+        assertNull("no error thrown", response.getResponseError());
+
+        assertNotNull(response.getEntities());
+        assertTrue("response entities is an Array", response.getEntities().getClass() == ArrayList.class);
+
+        // response.first should exist and have a valid uuid
+        UsergridEntity firstEntity = response.first();
+        assertNotNull(firstEntity);
+        assertNotNull("first entity is not null and has uuid", firstEntity.getUuid());
+
+        // response.entity should exist, equals the first entity, and have a valid uuid
+        UsergridEntity responseEntity = response.entity();
+        assertNotNull(responseEntity);
+        assertEquals(firstEntity, responseEntity);
+        assertNotNull("entity is not null and has uuid", responseEntity.getUuid());
+
+        // response.last should exist and have a valid uuid
+        UsergridEntity lastEntity = response.last();
+        assertNotNull(lastEntity);
+        assertNotNull("last entity is not null and has uuid", lastEntity.getUuid());
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/EntityTestCase.java b/src/test/java/org/apache/usergrid/client/EntityTestCase.java
new file mode 100644
index 0000000..42c3054
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/EntityTestCase.java
@@ -0,0 +1,676 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.TextNode;
+import org.apache.usergrid.java.client.UsergridEnums.UsergridDirection;
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.apache.usergrid.java.client.query.UsergridQuery;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+public class EntityTestCase {
+
+    @Before
+    public void before() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL, SDKTestConfiguration.authFallBack);
+        Usergrid.authenticateApp(new UsergridAppAuth(SDKTestConfiguration.APP_CLIENT_ID, SDKTestConfiguration.APP_CLIENT_SECRET));
+    }
+
+    @After
+    public void after() {
+        Usergrid.reset();
+    }
+
+    @Test
+    public void testEntityCreationSuccess() {
+        String collectionName = "ect" + System.currentTimeMillis();
+        String entityName = "testEntity1";
+
+        HashMap<String,JsonNode> map = new HashMap<>();
+        map.put("name",new TextNode(entityName));
+        map.put("color",new TextNode("red"));
+        map.put("shape",new TextNode("square"));
+
+        UsergridEntity entity = new UsergridEntity(collectionName,null,map);
+        UsergridResponse response = entity.save();
+        assertNull(response.getResponseError());
+
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The returned entity is null!", eLookUp);
+        assertEquals("entities has the correct type", eLookUp.getType(),collectionName);
+        assertEquals("entities has the correct name", eLookUp.getName(),entityName);
+        assertEquals("entities has the correct color", eLookUp.getStringProperty("color"),"red");
+        assertEquals("entities has the correct shape", eLookUp.getStringProperty("shape"),"square");
+    }
+
+    @Test
+    public void testDuplicateEntityNameFailure() {
+        String collectionName = "testDuplicateEntityNameFailure" + System.currentTimeMillis();
+
+        UsergridEntity entity = new UsergridEntity(collectionName,"test3");
+        UsergridResponse response = Usergrid.POST(entity);
+        assertNull("First entity create should have succeeded.", response.getResponseError());
+
+        response = Usergrid.POST(entity);
+        assertNotNull("Second entity create should not succeed!", response.getResponseError());
+    }
+
+    @Test
+    public void testEntityLookupByName() {
+        String collectionName = "testEntityLookupByName" + System.currentTimeMillis();
+        String entityName = "testEntity4";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.save();
+
+        UsergridEntity eLookup = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The returned entity is null!", eLookup);
+        assertEquals("The returned entity does not have the same UUID", entity.getUuid(),eLookup.getUuid());
+    }
+
+    @Test
+    public void testEntityLookupByUUID() {
+        String collectionName = "testEntityLookupByUUID" + System.currentTimeMillis();
+        String entityName = "testEntity5";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.save();
+        assertNotNull(entity.getUuid());
+
+        UsergridEntity eLookup = Usergrid.GET(collectionName, entity.getUuid()).first();
+        assertNotNull("The returned entity is null!", eLookup);
+        assertEquals("The returned entity does not have the same UUID", entity.getUuid(),eLookup.getUuid());
+    }
+
+    @Test
+    public void testEntityLookupByQuery() {
+        String collectionName = "testEntityLookupByQuery" + System.currentTimeMillis();
+        String entityName = "testEntity6";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.putProperty("color","red");
+        entity.putProperty("shape","square");
+        entity.save();
+
+        SDKTestUtils.indexSleep();
+
+        UsergridQuery query = new UsergridQuery(collectionName).eq("color", "red");
+        UsergridEntity eLookup = Usergrid.GET(query).first();
+
+        assertNotNull("The entity was not returned on lookup", eLookup);
+        assertEquals("The returned entity does not have the same UUID", entity.getUuid(),eLookup.getUuid());
+
+        query = new UsergridQuery(collectionName).eq("name", entityName);
+        eLookup = Usergrid.GET(query).first();
+
+        assertNotNull("The entity was not returned on lookup", eLookup);
+        assertEquals("The returned entity does not have the same UUID", entity.getUuid(),eLookup.getUuid());
+
+        query = new UsergridQuery(collectionName).eq("shape", "square");
+        eLookup = Usergrid.GET(query).first();
+
+        assertNotNull("The entity was not returned on lookup", eLookup);
+        assertEquals("The returned entity does not have the same UUID", entity.getUuid(),eLookup.getUuid());
+
+        query = new UsergridQuery(collectionName).eq("shape", "circle");
+        eLookup = Usergrid.GET(query).first();
+
+        assertNull("The entity was not expected to be returned on lookup", eLookup);
+    }
+
+    @Test
+    public void testEntityUpdate() {
+        String collectionName = "testEntityLookupByUUID" + System.currentTimeMillis();
+        String entityName = "testEntity7";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.putProperty("color","red");
+        entity.putProperty("shape","square");
+        entity.putProperty("orientation","up");
+        entity.save();
+
+        SDKTestUtils.sleep(1000);
+
+        UsergridQuery query = new UsergridQuery(collectionName).eq("orientation", "up");
+        UsergridEntity eLookup = Usergrid.GET(query).first();
+        assertNotNull(eLookup);
+
+        assertEquals("The returned entity does not have the same UUID when querying by field", entity.getUuid(),eLookup.getUuid());
+
+        entity.putProperty("orientation", "down");
+        entity.save();
+        assertNotNull(entity.getUuid());
+
+        eLookup = Usergrid.GET(collectionName, entity.getUuid()).first();
+        assertNotNull(eLookup);
+
+        assertEquals("The returned entity does not have the same UUID", entity.getUuid(),eLookup.getUuid());
+        assertEquals("The field was not updated!", eLookup.getStringProperty("orientation"),"down");
+
+        SDKTestUtils.sleep(1000);
+
+        query = new UsergridQuery(collectionName).eq("orientation", "up");
+        eLookup = Usergrid.GET(query).first();
+
+        assertNull("The entity was returned for old value!", eLookup);
+    }
+
+    @Test
+    public void testEntityDelete() {
+        String collectionName = "testEntityDelete" + System.currentTimeMillis();
+        String entityName = "testEntity8";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.putProperty("color","red");
+        entity.putProperty("shape","square");
+        entity.putProperty("orientation","up");
+        entity.save();
+
+        SDKTestUtils.indexSleep();
+
+        assertNotNull(entity.getUuid());
+        assertNotNull(entity.getName());
+
+        UsergridQuery query = new UsergridQuery(collectionName).eq("orientation", "up");
+        UsergridEntity eLookup = Usergrid.GET(query).first();
+
+        assertNotNull("The returned entity was null!", eLookup);
+        assertEquals("The returned entity does not have the same UUID when querying by field", entity.getUuid(),eLookup.getUuid());
+
+        Usergrid.DELETE(entity);
+
+        eLookup = Usergrid.GET(collectionName, entity.getUuid()).first();
+        assertNull("The entity was not expected to be returned by UUID", eLookup);
+
+        eLookup = Usergrid.GET(collectionName, entity.getName()).first();
+        assertNull("The entity was not expected to be returned by getName", eLookup);
+
+        query = new UsergridQuery(collectionName).eq("color", "red");
+        eLookup = Usergrid.GET(query).first();
+        assertNull("The entity was not expected to be returned", eLookup);
+
+        query = new UsergridQuery(collectionName).eq("shape", "square");
+        eLookup = Usergrid.GET(query).first();
+        assertNull("The entity was not expected to be returned", eLookup);
+
+        query = new UsergridQuery(collectionName).eq("orientation", "up");
+        eLookup = Usergrid.GET(query).first();
+        assertNull("The entity was not expected to be returned", eLookup);
+    }
+
+    @Test
+    public void testEntityPutPropertyAndSave() {
+        String collectionName = "testEntityPutProperty" + System.currentTimeMillis();
+        String entityName = "testEntity9";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.putProperty("color","red");
+        entity.putProperty("shape","square");
+        entity.putProperty("orientation","up");
+        entity.putProperty("sides", 4);
+        entity.save();
+
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, entityName).first();
+
+        //Check if the property was added correctly
+        assertNotNull("The entity returned is not null.", eLookUp);
+        assertEquals("The entity putProperty() was successful ", eLookUp.getStringProperty("orientation"),"up");
+        assertEquals("The entity putProperty() was successful ", eLookUp.getIntegerProperty("sides"), new Integer(4));
+
+        //Overwrite the property if it exists.
+        entity.putProperty("orientation", "horizontal");
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The returned entity was null!", eLookUp);
+        assertEquals("The entity putProperty() was successful ", eLookUp.getStringProperty("orientation"),"horizontal");
+
+        //should not be able to set the name key (name is immutable)
+        entity.putProperty("name","entityNew");
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The returned entity was null!", eLookUp);
+        assertEquals("The entity putProperty() was successful ", eLookUp.getName(),"testEntity9");
+    }
+
+    @Test
+    public void testEntityPutProperties() {
+        String collectionName = "testEntityProperties" + System.currentTimeMillis();
+        String entityName = "testEntity9";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.putProperty("color","black");
+        entity.putProperty("orientation","up");
+        entity.save();
+
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+        assertEquals("The entity putProperty() was successful ", eLookUp.getStringProperty("orientation"),"up");
+        assertEquals("overwrite existing property", eLookUp.getStringProperty("color"),"black");
+    }
+
+    @Test
+    public void testEntityRemovePropertiesAndSave() {
+        String collectionName = "testEntityProperties" + System.currentTimeMillis();
+
+        Map<String, String> fields = new HashMap<>(3);
+        fields.put("color", "red");
+
+        String entityName = "testEntity9";
+
+        //should set properties for a given object, overwriting properties that exist and creating those that don\'t
+        UsergridEntity entity = SDKTestUtils.createEntity(collectionName, entityName, fields);
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("shape", "square");
+        properties.put("orientation", "up");
+        properties.put("color", "black");
+        entity.putProperties(properties);
+        entity.save();
+
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, "testEntity9").first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        String[] removeProperties = {"shape", "color"};
+        entity.removeProperties(Arrays.asList(removeProperties));
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, "testEntity9").first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+        assertTrue("overwrite existing property", eLookUp.getStringProperty("color") == null);
+        assertTrue("overwrite existing property", eLookUp.getStringProperty("shape") == null);
+
+    }
+
+    @Test
+    public void testEntityRemoveProperty() {
+        String collectionName = "testEntityProperties" + System.currentTimeMillis();
+
+        Map<String, String> fields = new HashMap<>(3);
+        fields.put("color", "red");
+
+        String entityName = "testEntity11";
+
+        //should set properties for a given object, overwriting properties that exist and creating those that don\'t
+        UsergridEntity entity = SDKTestUtils.createEntity(collectionName, entityName, fields);
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("shape", "square");
+        properties.put("orientation", "up");
+        properties.put("color", "black");
+        entity.putProperties(properties);
+        entity.save();
+
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, "testEntity11").first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        entity.removeProperty("color");
+        entity.removeProperty("shape");
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, "testEntity11").first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+        assertTrue("overwrite existing property", eLookUp.getStringProperty("color") == null);
+        assertTrue("overwrite existing property", eLookUp.getStringProperty("shape") == null);
+
+    }
+
+    @Test
+    public void testEntityAppendInArray() {
+        String collectionName = "testEntityProperties" + System.currentTimeMillis();
+        String entityName = "testEntity1";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.save();
+
+        ArrayList<Object> lenArr = new ArrayList<>();
+        lenArr.add(1);
+        lenArr.add(2);
+        lenArr.add(3);
+        lenArr.add(4);
+        entity.insert("lenArray", lenArr);
+        entity.save();
+
+        lenArr = new ArrayList<>();
+        lenArr.add(6);
+        lenArr.add(7);
+        entity.append("lenArray", lenArr);
+        entity.save();
+
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        ArrayNode toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add(1).add(2).add(3).add(4).add(6).add(7);
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("lenArray"),toCompare);
+    }
+
+    @Test
+    public void testEntityPrependInArray() {
+        String collectionName = "testEntityProperties" + System.currentTimeMillis();
+        String entityName = "testEntity1";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.save();
+
+        ArrayList<Object> lenArr = new ArrayList<>();
+        lenArr.add(1);
+        lenArr.add(2);
+        lenArr.add(3);
+        lenArr.add(4);
+        entity.putProperty("lenArray", lenArr);
+        entity.save();
+
+        lenArr = new ArrayList<>();
+        lenArr.add(6);
+        lenArr.add(7);
+
+        entity.insert("lenArray", lenArr, 0);
+        entity.save();
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        ArrayNode toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add(6).add(7).add(1).add(2).add(3).add(4);
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("lenArray"),toCompare);
+    }
+
+    @Test
+    public void testEntityPopInArray() {
+        String collectionName = "testEntityProperties" + System.currentTimeMillis();
+        String entityName = "testEntity1";
+
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.save();
+
+        ArrayList<Object> lenArr = new ArrayList<>();
+        lenArr.add(1);
+        lenArr.add(2);
+        lenArr.add(3);
+        entity.putProperty("lenArray", lenArr);
+        entity.save();
+
+        // should remove the last value of an existing array
+        entity.pop("lenArray");
+        entity.save();
+
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        ArrayNode toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add(1).add(2);
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("lenArray"),toCompare);
+
+        // value should remain unchanged if it is not an array
+        entity.putProperty("foo", "test1");
+        entity.save();
+
+        entity.pop("foo");
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+        assertEquals("foo should equal test1.", eLookUp.getStringProperty("foo"), "test1");
+
+        //should gracefully handle empty arrays
+        ArrayList<Object> lenArr2 = new ArrayList<>();
+        entity.putProperty("foo", lenArr2);
+        entity.save();
+        entity.pop("foo");
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        toCompare = new ArrayNode(JsonNodeFactory.instance);
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("foo"),toCompare);
+    }
+
+    @Test
+    public void testEntityShiftInArray() {
+        String collectionName = "testEntityProperties" + System.currentTimeMillis();
+        String entityName = "testEntity1";
+
+        //should remove the last value of an existing array
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.save();
+
+        ArrayList<Object> lenArr = new ArrayList<>();
+        lenArr.add(1);
+        lenArr.add(2);
+        lenArr.add(3);
+        entity.putProperty("lenArray", lenArr);
+        entity.save();
+
+        entity.shift("lenArray");
+        entity.save();
+
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        ArrayNode toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add(2).add(3);
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("lenArray"),toCompare);
+
+        //value should remain unchanged if it is not an array
+        entity.putProperty("foo", "test1");
+        entity.shift("foo");
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+        assertEquals("The entity returned is not null.", eLookUp.getStringProperty("foo"), "test1");
+
+        //should gracefully handle empty arrays
+        ArrayList<Object> lenArr2 = new ArrayList<>();
+        entity.putProperty("foo", lenArr2);
+        entity.shift("foo");
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("foo"), new ArrayNode(JsonNodeFactory.instance));
+    }
+
+    @Test
+    public void testEntityInsertInArray() {
+        String collectionName = "testEntityProperties" + System.currentTimeMillis();
+        String entityName = "testEntity1";
+
+        //should set properties for a given object, overwriting properties that exist and creating those that don\'t
+        UsergridEntity entity = new UsergridEntity(collectionName,entityName);
+        entity.save();
+
+        ArrayList<Object> lenArr = new ArrayList<>();
+        lenArr.add(1);
+        lenArr.add(2);
+        lenArr.add(3);
+        lenArr.add(4);
+        entity.putProperty("lenArray", lenArr);
+        entity.save();
+
+        ArrayList<Object> lenArr2 = new ArrayList<>();
+        lenArr2.add(6);
+        lenArr2.add(7);
+
+        entity.insert("lenArray", lenArr2, 6);
+        entity.save();
+
+        UsergridEntity eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        ArrayNode toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add(1).add(2).add(3).add(4).add(6).add(7);
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("lenArray"),toCompare);
+
+        //should merge an array of values into an existing array at the specified index
+        lenArr = new ArrayList<>();
+        lenArr.add(1);
+        lenArr.add(2);
+        lenArr.add(3);
+        lenArr.add(4);
+
+        entity.putProperty("lenArray", lenArr);
+        entity.save();
+
+        lenArr2 = new ArrayList<>();
+        lenArr2.add(5);
+        lenArr2.add(6);
+        lenArr2.add(7);
+        lenArr2.add(8);
+
+        entity.insert("lenArray", lenArr2, 2);
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add(1).add(2).add(5).add(6).add(7).add(8).add(3).add(4);
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("lenArray"),toCompare);
+
+        //should convert an existing value into an array when inserting a second value
+        entity.putProperty("foo", "test");
+        entity.insert("foo", "test1", 1);
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add("test").add("test1");
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("foo"),toCompare);
+
+        //should create a new array when a property does not exist
+        entity.insert("foo1", "test2", 1);
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add("test2");
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("foo1"),toCompare);
+
+        //should gracefully handle index out of positive range
+        entity.putProperty("ArrayIndex", "test1");
+        entity.insert("ArrayIndex", "test2", 1000);
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add("test1").add("test2");
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("ArrayIndex"),toCompare);
+
+        //should gracefully handle index out of negative range
+        entity.insert("ArrayIndex", "test3", -1000);
+        entity.save();
+
+        eLookUp = Usergrid.GET(collectionName, entityName).first();
+        assertNotNull("The entity returned is not null.", eLookUp);
+
+        toCompare = new ArrayNode(JsonNodeFactory.instance);
+        toCompare.add("test3").add("test1").add("test2");
+        assertEquals("The two arrays should be equal.", eLookUp.getJsonNodeProperty("ArrayIndex"),toCompare);
+    }
+
+    @Test
+    public void testEntityConnectDisconnectGetConnections() {
+        String collectionName = "testEntityProperties" + System.currentTimeMillis();
+        String entityOneName = "testEntity1";
+        String entityTwoName = "testEntity2";
+
+        UsergridEntity entityOne = new UsergridEntity(collectionName,entityOneName);
+        entityOne.putProperty("color","red");
+        entityOne.putProperty("shape","square");
+        entityOne.save();
+
+        UsergridEntity entityTwo = new UsergridEntity(collectionName,entityTwoName);
+        entityTwo.putProperty("color","green");
+        entityTwo.putProperty("shape","circle");
+        entityTwo.save();
+
+        assertNotNull(entityOne.getUuid());
+        assertNotNull(entityTwo.getUuid());
+        assertNotNull(entityOne.getName());
+        assertNotNull(entityTwo.getName());
+        assertNotNull(entityOne.uuidOrName());
+        assertNotNull(entityTwo.uuidOrName());
+
+        //should connect entities by passing a target UsergridEntity object as a parameter
+        entityOne.connect("likes", entityTwo);
+        entityOne.save();
+
+        UsergridEntity eLookUpConnectedEntity = entityOne.getConnections(UsergridDirection.OUT, "likes").first();
+        assertNotNull("The connected entity returned is not null.", eLookUpConnectedEntity);
+
+        assertEquals("The entity name should be equals.", eLookUpConnectedEntity.getName(),entityTwoName);
+
+        eLookUpConnectedEntity = entityTwo.getConnections(UsergridDirection.IN, "likes").first();
+        assertNotNull("The connected entity returned is not null.", eLookUpConnectedEntity);
+        assertEquals("The entity name should be equals.", eLookUpConnectedEntity.getName(),entityOneName);
+
+        entityOne.disconnect("likes", entityTwo);
+        entityOne.save();
+
+        eLookUpConnectedEntity = entityTwo.getConnections(UsergridDirection.IN, "likes").first();
+        assertNull("The entity returned is not null.", eLookUpConnectedEntity);
+
+        //should connect entities by passing target uuid as a parameter
+        Usergrid.connect(entityOne.getType(),entityOne.getUuid(),"visited",entityTwo.getUuid());
+        entityOne.save();
+
+        eLookUpConnectedEntity = entityOne.getConnections(UsergridDirection.OUT, "visited").first();
+        assertNotNull("The connected entity returned is not null.", eLookUpConnectedEntity);
+        assertEquals("The entity name should be equals.", eLookUpConnectedEntity.getName(),entityTwoName);
+
+        Usergrid.disconnect(entityOne.getType(),entityOne.getUuid(),"visited",entityTwo.getUuid());
+        entityOne.save();
+
+        eLookUpConnectedEntity = entityOne.getConnections(UsergridDirection.OUT, "visited").first();
+        assertNull("The entity returned is not null.", eLookUpConnectedEntity);
+
+        //should connect entities by passing target type and name as parameters
+        Usergrid.connect(entityOne.getType(),entityOne.getUuid(),"revisit",entityTwo.getType(),entityTwo.getName());
+        entityOne.save();
+
+        eLookUpConnectedEntity = entityOne.getConnections(UsergridDirection.OUT, "revisit").first();
+        assertNotNull("The connected entity returned is not null.", eLookUpConnectedEntity);
+        assertEquals("The entity name should be equals.", eLookUpConnectedEntity.getName(),entityTwoName);
+
+        Usergrid.disconnect(entityOne.getType(),entityOne.getUuid(),"revisit",entityTwo.getType(),entityTwo.getName());
+        entityOne.save();
+
+        eLookUpConnectedEntity = entityOne.getConnections(UsergridDirection.OUT, "revisit").first();
+        assertNull("The entity returned is not null.", eLookUpConnectedEntity);
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/QueryTestCase.java b/src/test/java/org/apache/usergrid/client/QueryTestCase.java
new file mode 100644
index 0000000..f013134
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/QueryTestCase.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.DoubleNode;
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.apache.usergrid.java.client.query.UsergridQuery;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+public class QueryTestCase {
+
+    public static final String COLLECTION = "shapes";
+
+    public static float distFrom(float lat1, float lng1, float lat2, float lng2) {
+        double earthRadius = 6371000; //meters
+        double dLat = Math.toRadians(lat2 - lat1);
+        double dLng = Math.toRadians(lng2 - lng1);
+        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
+        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+        return (float) (earthRadius * c);
+    }
+
+    @Before
+    public void before() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL, SDKTestConfiguration.authFallBack);
+        Usergrid.authenticateApp(new UsergridAppAuth(SDKTestConfiguration.APP_CLIENT_ID, SDKTestConfiguration.APP_CLIENT_SECRET));
+    }
+
+    @After
+    public void after() {
+        Usergrid.reset();
+    }
+
+    /**
+     * Test a basic set of queries where there is inclusion and exclusion based on
+     * two fields
+     */
+    @Test
+    public void testBasicQuery() {
+
+        UsergridQuery qDelete = new UsergridQuery(COLLECTION);
+        Usergrid.DELETE(qDelete);
+
+        Map<String, UsergridEntity> entityMapByUUID = SDKTestUtils.createColorShapes(COLLECTION);
+        Map<String, UsergridEntity> entityMapByName = new HashMap<>(entityMapByUUID.size());
+
+        for (Map.Entry<String, UsergridEntity> uuidEntity : entityMapByUUID.entrySet()) {
+            entityMapByName.put(uuidEntity.getValue().getName(), uuidEntity.getValue());
+        }
+
+        SDKTestUtils.indexSleep();
+
+        Map<String, String> fields = new HashMap<>(7);
+        fields.put("red", "square");
+        fields.put("blue", "circle");
+        fields.put("yellow", "triangle");
+
+        for (Map.Entry<String, String> entry : fields.entrySet()) {
+            UsergridEntity targetEntity = entityMapByName.get(entry.getKey() + entry.getValue());
+
+            UsergridResponse response = Usergrid.GET(new UsergridQuery(COLLECTION).eq("color", entry.getKey()));
+            assertNotNull("entities returned should not be null.", response.getEntities());
+            assertTrue("query for " + entry.getKey() + " shape should return 1, not: " + response.getEntities().size(), response.getEntities().size() == 1);
+
+            UsergridEntity responseEntity = response.first();
+            assertNotNull("first entity should not be null.", responseEntity);
+            assertEquals("query for " + entry.getKey() + " shape should the right UUID", responseEntity.getUuid(),targetEntity.getUuid());
+        }
+        Usergrid.DELETE(qDelete);
+    }
+
+    /**
+     * Test that geolocation is working as expected with different ranges and radius
+     * also test that results are sorted ascending by distance from the specified point
+     */
+    @Test
+    public void testGeoQuery() {
+
+        String collectionName = "sdkTestLocation";
+
+        UsergridQuery deleteQuery = new UsergridQuery(collectionName);
+        Usergrid.DELETE(deleteQuery);
+
+        ArrayList<UsergridEntity> entities = new ArrayList<>();
+        UsergridEntity apigeeOffice = new UsergridEntity(collectionName,"Apigee Office");
+        apigeeOffice.setLocation(37.334115, -121.894340);
+        entities.add(apigeeOffice);
+
+        UsergridEntity amicis = new UsergridEntity(collectionName,"Amicis");
+        amicis.setLocation(37.335616, -121.894168);
+        entities.add(amicis);
+
+        UsergridEntity sanPedroMarket = new UsergridEntity(collectionName,"SanPedroMarket");
+        sanPedroMarket.setLocation(37.336499, -121.894356);
+        entities.add(sanPedroMarket);
+
+        UsergridEntity saintJamesPark = new UsergridEntity(collectionName,"saintJamesPark");
+        saintJamesPark.setLocation(37.339079, -121.891422);
+        entities.add(saintJamesPark);
+
+        UsergridEntity sanJoseNews = new UsergridEntity(collectionName,"sanJoseNews");
+        sanJoseNews.setLocation(37.337812, -121.890784);
+        entities.add(sanJoseNews);
+
+        UsergridEntity deAnza = new UsergridEntity(collectionName,"deAnza");
+        deAnza.setLocation(37.334370, -121.895081);
+        entities.add(deAnza);
+
+        Usergrid.POST(entities);
+
+        SDKTestUtils.indexSleep();
+
+        float centerLat = 37.334110f;
+        float centerLon = -121.894340f;
+
+        // Test a large distance
+        UsergridResponse queryResponse = Usergrid.GET(new UsergridQuery(collectionName).locationWithin(611.00000, centerLat, centerLon));
+        assertNotNull(queryResponse.getEntities());
+
+        float lastDistanceFrom = 0;
+        for (UsergridEntity entity : queryResponse.getEntities()) {
+
+            JsonNode locationNode = entity.getEntityProperty("location");
+            assertNotNull("location node should not be null", locationNode);
+
+            DoubleNode lat = (DoubleNode) locationNode.get("latitude");
+            DoubleNode lon = (DoubleNode) locationNode.get("longitude");
+
+            float distanceFrom = distFrom(centerLat, centerLon, lat.floatValue(), lon.floatValue());
+            System.out.println("Entity " + entity.getName() + " is " + distanceFrom + " away");
+
+            assertTrue("Entity " + entity.getName() + " was included but is not within specified distance (" + distanceFrom + ")", distanceFrom <= 611.0);
+
+            if (lastDistanceFrom != 0) {
+                assertTrue("GEO results are not sorted by distance ascending: expected " + lastDistanceFrom + " <= " + distanceFrom, lastDistanceFrom <= distanceFrom);
+            }
+
+            lastDistanceFrom = distanceFrom;
+        }
+
+        // Test a small distance
+        queryResponse = Usergrid.GET(new UsergridQuery(collectionName).locationWithin(150, centerLat, centerLon));
+        assertNotNull(queryResponse.getEntities());
+
+        lastDistanceFrom = 0;
+        for (UsergridEntity entity : queryResponse.getEntities()) {
+
+            JsonNode locationNode = entity.getEntityProperty("location");
+            assertNotNull("location node should not be null", locationNode);
+
+            DoubleNode lat = (DoubleNode) locationNode.get("latitude");
+            DoubleNode lon = (DoubleNode) locationNode.get("longitude");
+
+            float distanceFrom = distFrom(centerLat, centerLon, lat.floatValue(), lon.floatValue());
+            System.out.println("Entity " + entity.getName() + " is " + distanceFrom + " away");
+
+            assertTrue("Entity " + entity.getName() + " was included but is not within specified distance (" + distanceFrom + ")", distanceFrom <= 150);
+
+            if (lastDistanceFrom != 0) {
+                assertTrue("GEO results are not sorted by distance ascending: expected " + lastDistanceFrom + " <= " + distanceFrom, lastDistanceFrom <= distanceFrom);
+            }
+
+            lastDistanceFrom = distanceFrom;
+        }
+
+        Usergrid.DELETE(deleteQuery);
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/SDKTestConfiguration.java b/src/test/java/org/apache/usergrid/client/SDKTestConfiguration.java
new file mode 100644
index 0000000..e92e7be
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/SDKTestConfiguration.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.UsergridEnums.UsergridAuthMode;
+
+public class SDKTestConfiguration {
+    public static final String APP_CLIENT_ID = "b3U6THNcevskEeOQZLcUROUUVA"; //"YXA6_j0WsfFCEeWKoy6txsCOfA" ;
+    public static final String APP_CLIENT_SECRET = "b3U6RZHYznP28xieBzQPackFPmmnevU"; //"YXA6jg8x4wjq1AAyQBKtn4bRd1l0gJ8"; //
+
+    public static final String APP_UserName = "javaSDK"; //"test";// //"b3U66ne33W4OEeWXmAIj6QFb-Q";
+    public static final String APP_Password = "Apigee123"; //"test";//"b3U6PxbpQiTrXKCWu0n1CjK1uTZXuG4";
+    public static final String USERGRID_URL = "https://api.usergrid.com/";
+    public static final String ORG_NAME = "rwalsh";
+    public static final String APP_NAME = "sdk.demo";
+
+    public static UsergridAuthMode authFallBack = UsergridAuthMode.APP;
+
+//  public static final String APP_CLIENT_ID = "YXA61n2kpFffEeWs9QLknKqhHw";
+//  public static final String APP_CLIENT_SECRET = "YXA69_aRW1IHLgMTUUYSitsGwOLY8uQ";
+//  public static final String USERGRID_URL = "https://fhirsandbox-prod.apigee.net/appservices";
+//  public static final String ORG_NAME = "usergrid";
+//  public static final String APP_NAME = "sandbox";
+}
diff --git a/src/test/java/org/apache/usergrid/client/SDKTestUtils.java b/src/test/java/org/apache/usergrid/client/SDKTestUtils.java
new file mode 100644
index 0000000..fc5a039
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/SDKTestUtils.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class SDKTestUtils {
+
+
+    public static Map<String, UsergridEntity> createColorShapes(String collection) {
+
+        Map<String, Map<String, String>> entityMap = new HashMap<>(7);
+
+        Map<String, String> fields = new HashMap<>(3);
+        fields.put("color", "red");
+        fields.put("shape", "square");
+
+        entityMap.put("redsquare", fields);
+
+        fields = new HashMap<>(3);
+        fields.put("color", "blue");
+        fields.put("shape", "circle");
+
+        entityMap.put("bluecircle", fields);
+
+        fields = new HashMap<>(3);
+        fields.put("color", "yellow");
+        fields.put("shape", "triangle");
+
+        entityMap.put("yellowtriangle", fields);
+
+        return createEntities(collection, entityMap);
+    }
+
+    public static Map<String, UsergridEntity> createEntities(final String collection,
+                                                             final Map<String, Map<String, String>> entities) {
+
+        Map<String, UsergridEntity> entityMap = new HashMap<>();
+
+        for (Map.Entry<String, Map<String, String>> entity : entities.entrySet()) {
+
+            UsergridEntity e = createEntity(collection, entity.getKey(), entity.getValue());
+            entityMap.put(e.getUuid(), e);
+        }
+
+        return entityMap;
+    }
+
+    public static UsergridEntity createEntity(final String collection,
+                                              final String name,
+                                              final Map<String, String> fields) {
+
+        UsergridEntity e = new UsergridEntity(collection, name);
+
+        if( fields != null ) {
+            for (Map.Entry<String, String> field : fields.entrySet()) {
+                e.putProperty(field.getKey(), field.getValue());
+            }
+        }
+
+        UsergridResponse r = Usergrid.getInstance().POST(e);
+
+        if (r.getResponseError() != null) {
+            assertTrue("UUID should not be null", e.getUuid() != null);
+            if( fields != null ) {
+                for (Map.Entry<String, String> field : fields.entrySet()) {
+                    assertEquals("attempted to set a property which did not persist on the entity", e.getStringProperty(field.getKey()),field.getValue());
+                }
+            }
+        }
+
+        return r.first();
+    }
+
+    public static void sleep(long millis) {
+        try {
+            Thread.sleep(millis);
+        } catch (InterruptedException ignore) {
+            ignore.printStackTrace();
+        }
+    }
+
+    public static void indexSleep() {
+        sleep(1000);
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/UsergridClientAuthTestCase.java b/src/test/java/org/apache/usergrid/client/UsergridClientAuthTestCase.java
new file mode 100644
index 0000000..82ca3c9
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/UsergridClientAuthTestCase.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.UsergridClient;
+import org.apache.usergrid.java.client.UsergridEnums;
+import org.apache.usergrid.java.client.UsergridRequest;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.model.UsergridEntity;
+import org.apache.usergrid.java.client.model.UsergridUser;
+import org.apache.usergrid.java.client.auth.UsergridUserAuth;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.List;
+
+public class UsergridClientAuthTestCase {
+
+    @After
+    public void after() {
+        Usergrid.reset();
+    }
+
+    @Test
+    public void clientAppInit() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL, SDKTestConfiguration.authFallBack);
+        Usergrid.authenticateApp(new UsergridAppAuth(SDKTestConfiguration.APP_CLIENT_ID, SDKTestConfiguration.APP_CLIENT_SECRET));
+
+        //should fall back to using no authentication when currentUser is not authenticated and authFallback is set to NONE
+        UsergridClient client = Usergrid.getInstance();
+//        client.config.authMode = UsergridEnums.UsergridAuthMode.NONE;
+
+        String[] segments = {client.getOrgId(), client.getAppId(), "users"};
+        UsergridRequest request = new UsergridRequest(UsergridEnums.UsergridHttpMethod.GET, UsergridRequest.APPLICATION_JSON_MEDIA_TYPE,
+                client.getBaseUrl(), null, null, null, null, client.authForRequests(), segments);
+        client.sendRequest(request);
+    }
+
+    @Test
+    public void clientUserInit() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL);
+        Usergrid.authenticateUser(new UsergridUserAuth(SDKTestConfiguration.APP_UserName, SDKTestConfiguration.APP_Password));
+        UsergridResponse getResponse = Usergrid.GET("user","eb8145ea-e171-11e5-a5e5-2bc0953f9fe6");
+        if( getResponse.getEntities() != null ) {
+            UsergridEntity entity = getResponse.first();
+            if( entity instanceof UsergridUser) {
+                UsergridUser user = (UsergridUser) entity;
+                System.out.print(user.toString());
+            }
+            List<UsergridUser> users = getResponse.users();
+            if( users != null ) {
+                System.out.print(users.get(0).toString());
+            }
+        }
+
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/UsergridInitTestCase.java b/src/test/java/org/apache/usergrid/client/UsergridInitTestCase.java
new file mode 100644
index 0000000..980a3e7
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/UsergridInitTestCase.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.UsergridClient;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.auth.UsergridUserAuth;
+import org.junit.After;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+public class UsergridInitTestCase {
+
+    @After
+    public void after() {
+        Usergrid.reset();
+    }
+
+    @Test
+    public void testInitAppUsergrid() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL);
+        Usergrid.authenticateApp(new UsergridAppAuth(SDKTestConfiguration.APP_CLIENT_ID, SDKTestConfiguration.APP_CLIENT_SECRET));
+        assertTrue("usergrid should be an instance of usergrid client", Usergrid.getInstance().getClass() == UsergridClient.class);
+    }
+
+    @Test
+    public void testInitUserUsergrid() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL);
+        Usergrid.authenticateUser(new UsergridUserAuth(SDKTestConfiguration.APP_UserName, SDKTestConfiguration.APP_Password));
+        assertTrue("usergrid should be an instance of usergrid client", Usergrid.getInstance().getClass() == UsergridClient.class);
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/UsergridResponseErrorTestCase.java b/src/test/java/org/apache/usergrid/client/UsergridResponseErrorTestCase.java
new file mode 100644
index 0000000..3533805
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/UsergridResponseErrorTestCase.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+public class UsergridResponseErrorTestCase {
+
+    @Before
+    public void before() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL, SDKTestConfiguration.authFallBack);
+        UsergridAppAuth appAuth = new UsergridAppAuth(SDKTestConfiguration.APP_CLIENT_ID, SDKTestConfiguration.APP_CLIENT_SECRET);
+        Usergrid.authenticateApp(appAuth);
+    }
+
+    @After
+    public void after() {
+        Usergrid.reset();
+    }
+
+    @Test
+    public void testEntityCreationSuccess() {
+        String collectionName = "ect" + System.currentTimeMillis();
+
+        Map<String, String> fields = new HashMap<>(3);
+        fields.put("color", "red");
+        fields.put("shape", "square");
+
+        SDKTestUtils.createEntity(collectionName, "testEntity1", fields);
+        UsergridResponse eLookUp = Usergrid.GET(collectionName, "testEntity1");
+        assertNull("The returned entity is null!", eLookUp.getResponseError());
+
+        UsergridResponse response = Usergrid.GET(collectionName, "testEntityThatShouldNotExist");
+        assertFalse("Response returned should not be ok.",response.ok());
+        assertTrue("StatusCode equals than 404", response.getStatusCode() == 404);
+        assertNotNull("The returned entity is null!", response.getResponseError());
+    }
+}
diff --git a/src/test/java/org/apache/usergrid/client/UsergridResponseTestCase.java b/src/test/java/org/apache/usergrid/client/UsergridResponseTestCase.java
new file mode 100644
index 0000000..e158d85
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/UsergridResponseTestCase.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.UsergridEnums;
+import org.apache.usergrid.java.client.auth.UsergridUserAuth;
+import org.apache.usergrid.java.client.response.UsergridResponse;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class UsergridResponseTestCase {
+
+    @Before
+    public void before() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL, UsergridEnums.UsergridAuthMode.USER);
+        Usergrid.authenticateUser(new UsergridUserAuth(SDKTestConfiguration.APP_UserName, SDKTestConfiguration.APP_Password));
+    }
+
+    @After
+    public void after() {
+        Usergrid.reset();
+    }
+
+    @Test
+    public void testLogoutUser() {
+        String collectionName = "ect" + System.currentTimeMillis();
+
+        Map<String, String> fields = new HashMap<>(3);
+        fields.put("color", "red");
+        fields.put("shape", "square");
+
+        SDKTestUtils.createEntity(collectionName, "testEntity1", fields);
+        UsergridResponse response = Usergrid.GET(collectionName, "testEntity1");
+        Object instanceObj = response.getStatusCode();
+        assertTrue("The returned statusCode is and object of integer", instanceObj instanceof Integer);
+        instanceObj = response.ok();
+        assertTrue("The returned statusCode is and object of boolean", instanceObj instanceof Boolean);
+
+        UsergridResponse resp = Usergrid.logoutUser(SDKTestConfiguration.APP_UserName,null);
+
+        response = Usergrid.GET(collectionName, "testEntity1");
+        assertNotNull("The response should throw an error",response.getResponseError());
+    }
+
+    @Test
+    public void testLogoutCurrentUser() {
+        String collectionName = "ect" + System.currentTimeMillis();
+
+        Map<String, String> fields = new HashMap<>(3);
+        fields.put("color", "red");
+        fields.put("shape", "square");
+
+        SDKTestUtils.createEntity(collectionName, "testEntity12", fields);
+        UsergridResponse response = Usergrid.GET(collectionName, "testEntity12");
+        assertNull("The response should not throw an error",response.getResponseError());
+
+        Usergrid.logoutCurrentUser();
+        response = Usergrid.GET(collectionName, "testEntity1");
+        assertNotNull("The response should throw an error",response.getResponseError());
+    }
+
+}
diff --git a/src/test/java/org/apache/usergrid/client/UsergridTestCase.java b/src/test/java/org/apache/usergrid/client/UsergridTestCase.java
new file mode 100644
index 0000000..5e1ab3a
--- /dev/null
+++ b/src/test/java/org/apache/usergrid/client/UsergridTestCase.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.client;
+
+import org.apache.usergrid.java.client.Usergrid;
+import org.apache.usergrid.java.client.auth.UsergridAppAuth;
+import org.junit.Before;
+import org.junit.Test;
+
+public class UsergridTestCase {
+
+    @Test
+    public void initialize() {
+        Usergrid.initSharedInstance(SDKTestConfiguration.ORG_NAME, SDKTestConfiguration.APP_NAME, SDKTestConfiguration.USERGRID_URL);
+    }
+}
diff --git a/usergrid-java-client-2.1.0.jar b/usergrid-java-client-2.1.0.jar
new file mode 100644
index 0000000..fa90a59
--- /dev/null
+++ b/usergrid-java-client-2.1.0.jar
Binary files differ