All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.stackmob.sdk.api.StackMobDatastore Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2012 StackMob
 *
 * 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.
 */
package com.stackmob.sdk.api;

import com.google.gson.*;
import com.stackmob.sdk.callback.StackMobRawCallback;
import com.stackmob.sdk.callback.StackMobRedirectedCallback;
import com.stackmob.sdk.exception.StackMobException;
import com.stackmob.sdk.net.HttpVerb;
import com.stackmob.sdk.net.HttpVerbWithPayload;
import com.stackmob.sdk.net.HttpVerbWithoutPayload;
import com.stackmob.sdk.request.StackMobRequest;
import com.stackmob.sdk.request.StackMobRequestWithPayload;
import com.stackmob.sdk.request.StackMobRequestWithoutPayload;
import com.stackmob.sdk.util.Http;
import com.stackmob.sdk.util.Pair;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;

/**
 * Make calls to StackMob's API directly. This class lets you call CRUD methods, as well as talk to any custom APIs you have.
 */
public class StackMobDatastore {


    private ExecutorService executor;
    private StackMobSession session;
    private String host;
    private StackMobRedirectedCallback redirectedCallback;

    public StackMobDatastore(ExecutorService executor, StackMobSession session, String host, StackMobRedirectedCallback redirectedCallback) {
        this.executor = executor;
        this.session = session;
        this.host = host;
        this.redirectedCallback = redirectedCallback;
    }

    /**
     * set a specific session
     * @param session the session to set
     */
    public void setSession(StackMobSession session) {
        this.session = session;
    }

    /**
     * do a get request on the StackMob platform
     * @param path the path to get
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void get(String path, StackMobRawCallback callback) {
        new StackMobRequestWithoutPayload(this.executor,
                                          this.session,
                                          HttpVerbWithoutPayload.GET,
                                          StackMobOptions.none(),
                                          StackMobRequest.EmptyParams,
                                          path,
                                          callback,
                                          this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a get request on the StackMob platform
     * @param path the path to get
     * @param options additional options, such as headers, to modify the request
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void get(String path, StackMobOptions options, StackMobRawCallback callback) {
        get(path, StackMobRequest.EmptyParams, options, callback);
    }

    /**
     * do a get request on the StackMob platform
     * @param path the path to get
     * @param arguments arguments to be encoded into the query string of the get request
     * @param headers any additional headers to send
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    private void get(String path, List> arguments, List> headers, StackMobRawCallback callback) {
        new StackMobRequestWithoutPayload(this.executor,
                                          this.session,
                                          HttpVerbWithoutPayload.GET,
                                          StackMobOptions.headers(headers),
                                          arguments,
                                          path,
                                          callback,
                                          this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a get request on the StackMob platform
     * @param path the path to get
     * @param arguments arguments to be encoded into the query string of the get request
     * @param options additional options, such as headers, to modify the request
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    private void get(String path, List> arguments, StackMobOptions options, StackMobRawCallback callback) {
        new StackMobRequestWithoutPayload(this.executor,
                this.session,
                HttpVerbWithoutPayload.GET,
                options,
                arguments,
                path,
                callback,
                this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a get request on the StackMob platform
     * @param query the query to run
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void get(StackMobQuery query, StackMobRawCallback callback) {
        StackMobOptions options = StackMobOptions.headers(query.getHeaders());
        this.get("/"+query.getObjectName(), query.getArguments(), options.getHeaders(), callback);
    }

    /**
     * do a get request on the StackMob platform
     * @param query the query to run
     * @param options additional options, such as headers, to modify the request
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void get(StackMobQuery query, StackMobOptions options, StackMobRawCallback callback) {
        this.get("/"+query.getObjectName(), query.getArguments(), options.withHeaders(query.getHeaders()).getHeaders(), callback);
    }

    /**
     * do a head request on the StackMob platform
     * @param path the path to head
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void head(String path, StackMobRawCallback callback) {
        new StackMobRequestWithoutPayload(this.executor,
                this.session,
                HttpVerbWithoutPayload.HEAD,
                StackMobOptions.none(),
                StackMobRequest.EmptyParams,
                path,
                callback,
                this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a head request on the StackMob platform
     * @param path the path to head
     * @param options additional options, such as headers, to modify the request
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void head(String path, StackMobOptions options, StackMobRawCallback callback) {
        head(path, StackMobRequest.EmptyParams, options, callback);
    }

    /**
     * do a head request on the StackMob platform
     * @param path the path to head
     * @param arguments arguments to be encoded into the query string of the head request
     * @param headers any additional headers to send
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    private void head(String path, List> arguments, List> headers, StackMobRawCallback callback) {
        new StackMobRequestWithoutPayload(this.executor,
                this.session,
                HttpVerbWithoutPayload.HEAD,
                StackMobOptions.headers(headers),
                arguments,
                path,
                callback,
                this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a head request on the StackMob platform
     * @param path the path to head
     * @param arguments arguments to be encoded into the query string of the head request
     * @param options additional options, such as headers, to modify the request
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    private void head(String path, List> arguments, StackMobOptions options, StackMobRawCallback callback) {
        new StackMobRequestWithoutPayload(this.executor,
                this.session,
                HttpVerbWithoutPayload.HEAD,
                options,
                arguments,
                path,
                callback,
                this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a head request on the StackMob platform
     * @param query the query to run
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void head(StackMobQuery query, StackMobRawCallback callback) {
        StackMobOptions options = StackMobOptions.headers(query.getHeaders());
        this.head("/"+query.getObjectName(), query.getArguments(), options.getHeaders(), callback);
    }

    /**
     * do a head request on the StackMob platform
     * @param query the query to run
     * @param options additional options, such as headers, to modify the request
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void head(StackMobQuery query, StackMobOptions options, StackMobRawCallback callback) {
        this.head("/"+query.getObjectName(), query.getArguments(), options.withHeaders(query.getHeaders()).getHeaders(), callback);
    }


    /**
     * do a post request on the StackMob platform for a single object
     * @param path the path to get
     * @param requestObject the object to serialize and send in the POST body. this object will be serialized with Gson
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void post(String path, Object requestObject, StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.POST,
                                       StackMobOptions.none(),
                                       StackMobRequest.EmptyParams,
                                       requestObject,
                                       path,
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a post request on the StackMob platform for a single object
     * @param path the path to get
     * @param requestObject the object to serialize and send in the POST body. this object will be serialized with Gson
     * @param options additional options, such as headers, to modify the request
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void post(String path, Object requestObject, StackMobOptions options, StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.POST,
                                       options,
                                       StackMobRequest.EmptyParams,
                                       requestObject,
                                       path,
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a post request on the StackMob platform for a single object
     * @param path the path to get
     * @param body the json body
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void post(String path, String body, StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.POST,
                                       StackMobOptions.none(),
                                       StackMobRequest.EmptyParams,
                                       body,
                                       path,
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a POST request on the StackMob platform for a single object
     * @param path the path to get
     * @param body the json body
     * @param options any additional headers to send
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void post(String path, String body, StackMobOptions options, StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.POST,
                                       options,
                                       StackMobRequest.EmptyParams,
                                       body,
                                       path,
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a post request on the StackMob platform with a list of objects
     * @param path the path to get
     * @param requestObjects List of objects to serialize and send in the POST body. the list will be serialized with Gson
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public  void postBulk(String path, List requestObjects, StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.POST,
                                       StackMobOptions.none(),
                                       StackMobRequest.EmptyParams,
                                       requestObjects,
                                       path,
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * post a new related object to an existing object. the relation of the root object is updated
     * @param path the path to get
     * @param primaryId id of the object with the relation
     * @param relatedField name of the relation
     * @param relatedObject related object to post
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void postRelated(String path, String primaryId, String relatedField, Object relatedObject, StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.POST,
                                       StackMobOptions.none(),
                                       StackMobRequest.EmptyParams,
                                       relatedObject,
                                       String.format("%s/%s/%s", path, primaryId, relatedField),
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * post a new related object to an existing object. the relation of the root object is updated
     * @param path the path to get
     * @param primaryId id of the object with the relation
     * @param relatedField name of the relation
     * @param relatedObject related object to post
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void postRelated(String path, String primaryId, String relatedField, String relatedObject, StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.POST,
                                       StackMobOptions.none(),
                                       StackMobRequest.EmptyParams,
                                       relatedObject,
                                       String.format("%s/%s/%s", path, primaryId, relatedField),
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * post a list of new related objects to an existing object. the relation of the root object is updated
     * @param path the path to get
     * @param primaryId id of the object with the relation
     * @param relatedField name of the relation
     * @param relatedObjects list of related objects to post. the list will be serialized with Gson
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public  void postRelatedBulk(String path, String primaryId, String relatedField, List relatedObjects, StackMobRawCallback callback) {
        postRelated(path, primaryId, relatedField, relatedObjects, callback);
    }


    /**
     * do a PUT request on the StackMob platform
     * @param path the path to PUT
     * @param id the id of the object to PUT
     * @param requestObject the object to serialize and send in the PUT body. this object will be serialized with Gson
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void put(String path, String id, Object requestObject, StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.PUT,
                                       StackMobOptions.none(),
                                       StackMobRequest.EmptyParams,
                                       requestObject,
                                       path + "/" + id,
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a put request on the StackMob platform
     * @param path the path to put
     * @param id the id of the object to put
     * @param body the json body
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void put(String path, String id, String body, StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.PUT,
                                       StackMobOptions.none(),
                                       StackMobRequest.EmptyParams,
                                       body,
                                       path + "/" + id,
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a PUT request on the StackMob platform, treating some of the fields as counters to be incremented rather
     * than as values to set
     * @param path the path to put
     * @param id the id of the object to put
     * @param requestObject the object to serialize and send in the PUT body. this object will be serialized with Gson
     * @param counterFields a list of the fields in the object to be treated as counters being incremented
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void putAndUpdateAtomicCounters(String path,
                                           String id,
                                           Object requestObject,
                                           List counterFields,
                                           StackMobRawCallback callback) {
        JsonObject obj = new Gson().toJsonTree(requestObject).getAsJsonObject();
        for(Map.Entry field : new HashSet>(obj.entrySet())) {
            if(counterFields.contains(field.getKey())) {
                obj.remove(field.getKey());
                obj.add(field.getKey() + "[inc]", field.getValue());
            }
        }
        put(path, id, obj.toString(), callback);
    }

    /**
     * do an atomic update on a an integer field in a particular object and schema
     * @param path the path to put
     * @param id the id of the object to put
     * @param field the field to increment
     * @param value the value to increment by
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void updateAtomicCounter(String path,
                                    String id,
                                    String field,
                                    int value,
                                    StackMobRawCallback callback) {
        JsonObject body = new JsonObject();
        body.add(field + "[inc]", new JsonPrimitive(value));
        put(path, id, body.toString(), callback);
    }

    /**
     * do a an atomic put request on the StackMob platform with the contents of the has-many relation
     * @param path the path to get
     * @param primaryId id of the object with the relation
     * @param relatedField name of the relation
     * @param relatedIds list of ids to atomically add to the relation. The type should be the same type as the primary
     *                   key field of the related object
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public  void putRelated(String path,
                               String primaryId,
                               String relatedField,
                               List relatedIds,
                               StackMobRawCallback callback) {
        new StackMobRequestWithPayload(this.executor,
                                       this.session,
                                       HttpVerbWithPayload.PUT,
                                       StackMobOptions.none(),
                                       StackMobRequest.EmptyParams,
                                       relatedIds,
                                       String.format("%s/%s/%s", path, primaryId, relatedField),
                                       callback,
                                       this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a DELETE request to the StackMob platform
     * @param path the path to delete
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void delete(String path, StackMobRawCallback callback) {
        new StackMobRequestWithoutPayload(this.executor,
                this.session,
                HttpVerbWithoutPayload.DELETE,
                StackMobOptions.none(),
                StackMobRequest.EmptyParams,
                path,
                callback,
                this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a DELETE request to the StackMob platform
     * @param path the path to delete
     * @param id the id of the object to put
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void delete(String path, String id, StackMobRawCallback callback) {
        delete(path + "/" + id, callback);
    }

    /**
     * atomically remove elements from an array or has many relationship
     * @param path the path to get
     * @param primaryId id of the object with the relation
     * @param field name of the relation or array field to delete from
     * @param idsToDelete list of ids to atomically remove from field.
     *                    ids should be same type as the primary id of the related type (most likely String or Integer)
     * @param cascadeDeletes true if related objects specified in idsToDelete should also be deleted
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public  void deleteIdsFrom(String path,
                                  String primaryId,
                                  String field,
                                  List idsToDelete,
                                  boolean cascadeDeletes,
                                  StackMobRawCallback callback) {
        StringBuilder ids = new StringBuilder();
        for (int i = 0; i < idsToDelete.size(); i++) {
            ids.append(idsToDelete.get(i).toString());
            if (i < idsToDelete.size() - 1) {
                ids.append(",");
            }
        }
        List> headers = new ArrayList>();
        if (cascadeDeletes) {
            headers.add(new Pair("X-StackMob-CascadeDelete", "true"));
        }
        new StackMobRequestWithoutPayload(this.executor,
                                          this.session,
                                          HttpVerbWithoutPayload.DELETE,
                                          StackMobOptions.headers(headers),
                                          StackMobRequest.EmptyParams,
                                          String.format("%s/%s/%s/%s", path, primaryId, field, ids.toString()),
                                          callback,
                                          this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * atomically remove elements from an array or has many relationship
     * @param path the path to get
     * @param primaryId id of the object with the relation
     * @param field name of the relation or array field to delete from
     * @param idToDelete id to atomically remove from field.
     *                   should be same type as the primary id of the related type (most likely String or Integer)
     * @param cascadeDelete true if related object specified in idToDelete should also be deleted
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public  void deleteIdFrom(String path,
                                 String primaryId,
                                 String field,
                                 T idToDelete,
                                 boolean cascadeDelete,
                                 StackMobRawCallback callback) {
        List> headers = new ArrayList>();
        if (cascadeDelete) {
            headers.add(new Pair("X-StackMob-CascadeDelete", "true"));
        }
        new StackMobRequestWithoutPayload(this.executor,
                                          this.session,
                                          HttpVerbWithoutPayload.DELETE,
                                          StackMobOptions.headers(headers),
                                          StackMobRequest.EmptyParams,
                                          String.format("%s/%s/%s/%s", path, primaryId, field, idToDelete),
                                          callback,
                                          this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * do a DELETE request to the StackMob platform, with query parameters.
     *
     * warning! this has the ability to delete a substantial amount of data in one request. use with care!
     *
     * @param query the query on which to match elements to be deleted
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void delete(StackMobQuery query,
                       StackMobRawCallback callback) {
        new StackMobRequestWithoutPayload(
                this.executor,
                this.session,
                HttpVerbWithoutPayload.DELETE,
                StackMobOptions.none(),
                query.getArguments(),
                query.getObjectName(),
                callback,
                this.redirectedCallback).setUrlFormat(this.host).sendRequest();
    }

    /**
     * retrieve the number of objects for a schema on the StackMob platform
     * @param path the path to get
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void count(String path, StackMobRawCallback callback) {
        count(new StackMobQuery(path), callback);
    }

    /**
     * retrieve the number of objects for a query on the StackMob platform
     * @param query the query to send
     * @param callback callback to be called when the server returns. may execute in a separate thread
     */
    public void count(StackMobQuery query, StackMobRawCallback callback) {
        final StackMobRawCallback userCallback = callback;
        get(query.isInRange(0, 0), new StackMobRawCallback() {
            @Override
            public void unsent(StackMobException e) {
                userCallback.unsent(e);
            }

            @Override
            public void temporaryPasswordResetRequired(StackMobException e) {
                userCallback.temporaryPasswordResetRequired(e);
            }

            @Override
            public void done(HttpVerb requestVerb, String requestURL, List> requestHeaders, String requestBody, Integer responseStatusCode, List> responseHeaders, byte[] responseBody) {
                if(Http.isSuccess(responseStatusCode)) {
                    long count = getTotalNumberOfItemsFromContentRange(responseHeaders);
                    if (count < 0) {
                        try { // No header means all available items were returned, so count them (0 or 1)
                            count = new JsonParser().parse(new String(responseBody)).getAsJsonArray().size();
                        } catch(Exception ignore) {}
                    }
                    responseBody = String.valueOf(count).getBytes();
                }
                userCallback.setDone(requestVerb, requestURL, requestHeaders, requestBody, responseStatusCode, responseHeaders, responseBody);
            }

            @Override
            public void circularRedirect(String originalUrl, Map redirectHeaders, String redirectBody, String newURL) {
                userCallback.circularRedirect(originalUrl, redirectHeaders, redirectBody, newURL);
            }
        });
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy