package kidozen.client;
import org.apache.http.HttpStatus;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import kidozen.client.authentication.KidoZenUser;
import kidozen.client.internal.Constants;
import kidozen.client.internal.SyncHelper;
/**
* Storage service interface
*
* @author kidozen
* @version 1.00, April 2013
*/
public class Storage extends KZService {
private static final String LOGCAT_KEY = "Storage";
/**
* You should not create a new instances of this constructor. Instead use the Storage() method of the KZApplication object.
*
* @param storage
* @param name
* @param provider
* @param username
* @param pass
* @param clientId
* @param userIdentity
* @param applicationIdentity
*/
public Storage(String storage, String name, String provider , String username, String pass, String clientId, KidoZenUser userIdentity, KidoZenUser applicationIdentity) {
super(storage, name, provider, username, pass, clientId, userIdentity, applicationIdentity);
}
/**
* Creates a new object in the storage
*
* @param message The object to be created
* @param isPrivate marks the object as private (true) / public (false)
* @param callback The callback with the result of the service call
*/
public void Create(final JSONObject message, final boolean isPrivate, final ServiceEventListener callback)
{
validateParameters(message);
String url = mEndpoint + "/" + mName;
HashMap<String, String> params = new HashMap<String, String>();
params.put("isPrivate", (isPrivate ? "true" : "false"));
HashMap<String, String> headers = new HashMap<String, String>();
headers.put(Constants.CONTENT_TYPE, Constants.APPLICATION_JSON);
headers.put(Constants.ACCEPT, Constants.APPLICATION_JSON);
KZServiceAsyncTask task = new KZServiceAsyncTask(KZHttpMethod.POST,params,headers,message, callback, getStrictSSL());
task.execute(url);
}
/**
* Creates a new object in the storage synchronously
*
* @param message The object to be created
* @param isPrivate marks the object as private (true) / public (false)
* @return a json object with storage metadata.
* @throws TimeoutException
* @throws SynchronousException
*/
public JSONObject Create(final JSONObject message, final boolean isPrivate) throws TimeoutException, SynchronousException {
return new SyncHelper<JSONObject>(this,"Create", JSONObject.class , Boolean.TYPE, ServiceEventListener.class)
.Invoke(new Object[] { message, isPrivate });
}
/**
* Creates a new private object in the storage
*
* @param message The object to be created
* @param callback The callback with the result of the service call
*/
public void Create(final JSONObject message, final ServiceEventListener callback)
{
this.Create(message, true, callback);
}
/**
* Creates a new private object in the storage synchronously
*
* @param message The object to be created
* @return a json object with storage metadata.
* @throws TimeoutException
* @throws SynchronousException
*/
public JSONObject Create(final JSONObject message) throws TimeoutException, SynchronousException {
return this.Create(message, true);
}
/**
* Updates an object
*
* @param message The updated object
* @param id The unique identifier of the object
* @param callback The callback with the result of the service call
*/
public void Update(final String id, final JSONObject message, final ServiceEventListener callback) {
JSONObject serializedMsg = null;
try {
serializedMsg = checkDateSerialization(message);
}
catch (JSONException e) {
//System.out.println(e.getMessage());
createServiceEventWithException(e, callback);
}
String url = mEndpoint + "/" + mName + "/" + id;
HashMap<String, String> params = null;
HashMap<String, String> headers = new HashMap<String, String>();
headers.put(Constants.CONTENT_TYPE, Constants.APPLICATION_JSON);
headers.put(Constants.ACCEPT, Constants.APPLICATION_JSON);
new KZServiceAsyncTask(KZHttpMethod.PUT,params,headers,serializedMsg,callback, getStrictSSL()).execute(url);
}
/**
* Updates an object synchronously
*
* @param message The updated object
* @param id The unique identifier of the object
* @return a json object with storage metadata.
* @throws TimeoutException
* @throws SynchronousException
*/
public JSONObject Update(final String id, final JSONObject message) throws TimeoutException, SynchronousException {
return new SyncHelper<JSONObject>(this,"Update", String.class, JSONObject.class , ServiceEventListener.class)
.Invoke(new Object[] { id, message});
}
/**
* Gets an object
*
* @param id The unique identifier of the object
* @param callback The callback with the result of the service call
*/
public void Get(final String id, final ServiceEventListener callback)
{
if (id=="" || id==null) {
throw new IllegalArgumentException();
}
String url = mEndpoint + "/" + mName + "/" + id;
new KZServiceAsyncTask(KZHttpMethod.GET ,null,null, callback, getStrictSSL()).execute(url);
}
/**
* Gets an object
*
* @param id The unique identifier of the object
* @return the requested jsonobject
* @throws TimeoutException
* @throws SynchronousException
*/
public JSONObject Get(final String id) throws TimeoutException, SynchronousException {
return new SyncHelper<JSONObject>(this,"Get", String.class, ServiceEventListener.class)
.Invoke(new Object[] { id });
}
/**
* Drops the entire storage
*
* @param callback The callback with the result of the service call
*/
public void Drop(final ServiceEventListener callback)
{
String url = mEndpoint + "/" + mName;
new KZServiceAsyncTask(KZHttpMethod.DELETE,null,null,callback, getStrictSSL()).execute(url);
}
/**
* Drops the entire storage synchronously
*
* @return true if the operation was success
* @throws TimeoutException
* @throws SynchronousException
*/
public boolean Drop() throws TimeoutException, SynchronousException {
SyncHelper<String> helper = new SyncHelper(this,"Drop", ServiceEventListener.class);
helper.Invoke(new Object[] {});
return (helper.getStatusCode() == HttpStatus.SC_OK);
}
/**
* Deletes a message from the storage
*
* @param idMessage The unique identifier of the object
* @param callback The callback with the result of the service call
*/
public void Delete(final String idMessage,final ServiceEventListener callback)
{
if (idMessage=="" || idMessage==null) {
throw new IllegalArgumentException();
}
String url = mEndpoint + "/" + mName + "/" + idMessage;
new KZServiceAsyncTask(KZHttpMethod.DELETE,null,null,callback, getStrictSSL()).execute(url);
}
/**
* Deletes a message from the storage synchronously
*
* @param idMessage
* @return true if the operation was success
* @throws TimeoutException
* @throws SynchronousException
*/
public boolean Delete(final String idMessage) throws TimeoutException, SynchronousException {
SyncHelper<String> helper = new SyncHelper(this,"Delete", String.class, ServiceEventListener.class);
helper.Invoke(new Object[] {idMessage});
return (helper.getStatusCode() == HttpStatus.SC_OK);
}
/**
* Returns all the objects from the storage
*
* @param callback The callback with the result of the service call
*/
public void All(final ServiceEventListener callback)
{
this.Query("{}", "{}","{}", callback);
}
public JSONArray All() throws TimeoutException, SynchronousException {
return this.Query("{}", "{}", "{}");
}
/**
* Executes a query against the Storage
*
* @param query An string with the same syntax used for a MongoDb query
* @param callback The callback with the result of the service call
*/
public void Query(final String query,final ServiceEventListener callback)
{
if (query == null || query == "") {
throw new IllegalArgumentException("query cannot be null or empty");
}
this.Query(query, "{}","{}", callback);
}
public JSONArray Query ( final String query) throws TimeoutException, SynchronousException {
return new SyncHelper<JSONArray>(this, "Query", String.class , ServiceEventListener.class)
.Invoke(new Object[] { query });
}
/**
* Executes a query against the Storage
*
* @param query An string with the same syntax used for a MongoDb query
* @param options An string with the same syntax used for a MongoDb query options
* @param callback The callback with the result of the service call
*/
public void Query(final String query, final String options,final ServiceEventListener callback)
{
if (query == null || query == "" || options == null || options == "" ){
throw new IllegalArgumentException("query and options cannot be null or empty");
}
this.Query(query, "{}",options, callback);
}
public JSONArray Query ( final String query, final String options) throws TimeoutException, SynchronousException {
return new SyncHelper<JSONArray>(this, "Query", String.class , String.class , ServiceEventListener.class)
.Invoke(new Object[] { query, options });
}
/**
* Executes a query against the Storage
*
* @param query An string with the same syntax used for a MongoDb query
* @param options An string with the same syntax used for a MongoDb query options
* @param fields The fields to retrieve
* @param callback The callback with the result of the service call
*/
public void Query(final String query, final String fields, final String options,final ServiceEventListener callback)
{
if (query == null || query == "" || options == null || options == "" || fields == null || fields == "")
{
throw new IllegalArgumentException("query, options or fields, cannot be null or empty");
}
String url = mEndpoint + "/" + mName;
HashMap<String, String> params = new HashMap<String, String>();
params.put("query", query);
params.put("options", options);
params.put("fields", fields);
new KZServiceAsyncTask(KZHttpMethod.GET,params,null,callback, getStrictSSL()).execute(url);
}
public JSONArray Query ( final String query, final String fields, final String options) throws TimeoutException, SynchronousException {
return new SyncHelper<JSONArray>(this, "Query", String.class , String.class , String.class , ServiceEventListener.class)
.Invoke(new Object[] { query, fields, options });
}
/**
* Upserts an object
*
* if message has the '_id' property the object is updated. If not is created
*
* @param message The object
* @param callback The callback with the result of the service call
*
* Remarks:
* Due to this method is a wrapper if you want to update an object you must add the '_metadata' property
*/
public void Save(JSONObject message, final ServiceEventListener callback) throws Exception {
this.Save(message, true, callback);
}
public JSONObject Save (JSONObject message) throws TimeoutException, SynchronousException {
return new SyncHelper<JSONObject>(this, "Save", JSONObject.class , ServiceEventListener.class)
.Invoke(new Object[] { message });
}
/**
* Upserts an object
*
* if message has the '_id' property the object is updated. If not is created
*
* @param message The object
* @param isPrivate marks the object as private (true) / public (false)
* @param callback The callback with the result of the service call
*
* Remarks:
* Due to this method is a wrapper if you want to update an object you must add the '_metadata' property
*/
public void Save(JSONObject message, Boolean isPrivate, final ServiceEventListener callback) throws Exception {
String id = null;
try {id = message.getString("_id");} catch (JSONException e) {}
if (id!=null)
{
Update(id,message,callback);
}
else
{
Create(message, isPrivate, callback);
}
}
public JSONObject Save (JSONObject message, Boolean isPrivate ) throws TimeoutException, SynchronousException {
return new SyncHelper<JSONObject>(this, "Save", JSONObject.class , Boolean.class , ServiceEventListener.class)
.Invoke(new Object[] { message, isPrivate });
}
private void createServiceEventWithException(Exception e, ServiceEventListener callback) {
ServiceEvent se = new ServiceEvent(this);
se.Response = e;
se.Body = e.getMessage();
se.StatusCode = HttpStatus.SC_BAD_REQUEST;
se.Exception = e;
callback.onFinish(se);
}
private void validateParameters(JSONObject message) {
if (message == null)
throw new IllegalArgumentException("message is Null");
Object id = null;
try {id = message.get("_id");} catch (JSONException e) {}
if (id!=null)
throw new IllegalArgumentException("_id property is not valid for object creation.");
}
private JSONObject checkDateSerialization(JSONObject original) throws JSONException {
JSONObject updatedMessage = original;
JSONObject updatedMetadata = null;
try {
JSONObject _metadata = original.getJSONObject("_metadata");
if (_metadata.get("createdOn").getClass().getName().toLowerCase().contains("date")) {
Date createdON = (Date) _metadata.get("createdOn");
SimpleDateFormat dateFormat = new SimpleDateFormat(Constants.GMT_DATE_FORMAT);
_metadata.remove("createdOn");
_metadata.put("createdOn", dateFormat.format(createdON));
updatedMetadata = _metadata;
}
if (_metadata.get("updatedOn").getClass().getName().toLowerCase().contains("date")) {
Date createdON = (Date) _metadata.get("updatedOn");
SimpleDateFormat dateFormat = new SimpleDateFormat(Constants.GMT_DATE_FORMAT);
_metadata.remove("updatedOn");
_metadata.put("updatedOn", dateFormat.format(createdON));
updatedMetadata = _metadata;
}
if (updatedMetadata!=null) {
updatedMessage.remove("_metadata");
updatedMessage.put("_metadata", updatedMetadata);
}
} catch (JSONException e) {
throw new JSONException(e.getMessage());
}
return updatedMessage;
}
}