See More

/* Copyright (c) 2013 Cloudbase.io Limited 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.cloudbase; import java.io.File; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import com.cloudbase.datacommands.CBDataAggregationCommand; import com.cloudbase.datacommands.CBSearchCondition; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; /*! \mainpage cloudbase.io Java Helper Class Reference * * \section intro_sec Introduction * * Copyright (c) 2013 Cloudbase.io Limited * * 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.

* * \section install_sec Getting Started * * The cloudbase.io Java helper class compiles to .jar library.

* Make sure the library is included in your project. There are two places where we need to call it from the * project properties
*/ /** * The main CBHelper class. All of the methods interacting with the cloudbase.io APIs are part of this class. *
* This class requires the appCode, appSecret and password * properties set. appCode and appSecret are handed to the class in the constructor and the password can be * set using the setPassword setter. *
* This library depends on the Gson library by google. This is used to serialise and de-serialise objects to be * sent to the APIs. This library was built on top of the Gson 2.2.1. Make sure the jar file is available in your * classpath * @author Stefano Buliani */ public class CBHelper implements CBHelperResponder { // application settings to connect to cloudbase.io private String appCode; private String appSecret; private String password; // whether to use the https apis. This should be set to "true" by default. private boolean https; // whether the APIs require user authentication. and the current application // username and password private boolean userAuthentication; private String authUsername; private String authPassword; // The current location variable to be attached to requests to the CloudBase apis private boolean useLocation; private CBLocation currentLocation; private String sessionId; private CBDeviceInfo deviceInfo; // this is used when downloading attachments from the CloudBase - temporary files // are saved in the application files folder and handed back to the application private String temporaryFilesPath; private CBHelperResponder defaultQueueResponder; private boolean debugMode; private String apiURL = "api.cloudbase.io"; private static final String defaultLogCategory = "DEFAULT"; public static final String logTag = "CBHELPER"; private boolean deviceRegistered; private static Gson jsonParser = new GsonBuilder().disableHtmlEscaping().create();//new Gson(); /** * Creates a new instance of CBHelper and initializes the main properties to their default values. * @param code The application code generated by cloudbase.io when the application is registered (test-application) * @param uniq The unique code generated by cloudbase.io when the application is registered (8a159fe6e4493d4b9a56d4aa580953a2) * @param activity The main activity from the application. This is used to get Context variables, specifically the Cache directory * @throws Exception */ public CBHelper(String code, String uniq, CBDeviceInfo info) { this.appCode = code; this.appSecret = uniq; this.userAuthentication = false; this.https = true; this.debugMode = false; this.deviceInfo = info; this.deviceRegistered = false; this.temporaryFilesPath = info.getTemporaryFilesPath(); //Log.d(logTag, "CBHelper initialized"); } /** * Logs an event to the cloudbase.io application log * @param logLine The content of the line to be logged */ public void logEvent(String logLine) { this.log(logLine, CBLogLevel.EVENT, null, null, false); } /** * Logs an event to the cloudbase.io application log * @param logLine The content of the line to be Logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events */ public void logEvent(String logLine, String category) { this.log(logLine, CBLogLevel.EVENT, category, null, false); } /** * Logs an event to the cloudbase.io application log * @param logLine The content of the line to be Logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events * @param responder A responder to handle the return value from the cloudbase.io APIs. This is an optional parameter * and can be sent as null */ public void logEvent(String logLine, String category, CBHelperResponder responder) { this.log(logLine, CBLogLevel.EVENT, category, responder, false); } /** * Logs a fatal exception to the cloudbase.io application log * @param logLine The content of the line to be logged */ public void logFatal(String logLine) { this.log(logLine, CBLogLevel.FATAL, null, null, false); } /** * Logs a fatal exception to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events */ public void logFatal(String logLine, String category) { this.log(logLine, CBLogLevel.FATAL, category, null, false); } /** * Logs a fatal exception to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events * @param responder A responder to handle the return value from the cloudbase.io APIs. This is an optional parameter * and can be sent as null */ public void logFatal(String logLine, String category, CBHelperResponder responder) { this.log(logLine, CBLogLevel.FATAL, category, responder, false); } /** * Logs an error to the cloudbase.io application log * @param logLine The content of the line to be logged */ public void logError(String logLine) { this.log(logLine, CBLogLevel.ERROR, null, null, false); } /** * Logs an error to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events */ public void logError(String logLine, String category) { this.log(logLine, CBLogLevel.ERROR, category, null, false); } /** * Logs an error to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events * @param responder A responder to handle the return value from the cloudbase.io APIs. This is an optional parameter * and can be sent as null */ public void logError(String logLine, String category, CBHelperResponder responder) { this.log(logLine, CBLogLevel.ERROR, category, responder, false); } /** * Logs a warning to the cloudbase.io application log * @param logLine The content of the line to be logged */ public void logWarning(String logLine) { this.log(logLine, CBLogLevel.WARNING, null, null, false); } /** * Logs a warning to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events */ public void logWarning(String logLine, String category) { this.log(logLine, CBLogLevel.WARNING, category, null, false); } /** * Logs a warning to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events * @param responder A responder to handle the return value from the cloudbase.io APIs. This is an optional parameter * and can be sent as null */ public void logWarning(String logLine, String category, CBHelperResponder responder) { this.log(logLine, CBLogLevel.WARNING, category, responder, false); } /** * Logs an information message to the cloudbase.io application log * @param logLine The content of the line to be logged */ public void logInfo(String logLine) { this.log(logLine, CBLogLevel.INFO, null, null, false); } /** * Logs an information message to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events */ public void logInfo(String logLine, String category) { this.log(logLine, CBLogLevel.INFO, category, null, false); } /** * Logs an information message to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events * @param responder A responder to handle the return value from the cloudbase.io APIs. This is an optional parameter * and can be sent as null */ public void logInfo(String logLine, String category, CBHelperResponder responder) { this.log(logLine, CBLogLevel.INFO, category, responder, false); } /** * Logs a debug message to the cloudbase.io application log * @param logLine The content of the line to be logged */ public void logDebug(String logLine) { this.log(logLine, CBLogLevel.DEBUG, null, null, false); } /** * Logs a debug message to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events */ public void logDebug(String logLine, String category) { this.log(logLine, CBLogLevel.DEBUG, category, null, false); } /** * Logs a debug message to the cloudbase.io application log * @param logLine The content of the line to be logged * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events * @param responder A responder to handle the return value from the cloudbase.io APIs. This is an optional parameter * and can be sent as null */ public void logDebug(String logLine, String category, CBHelperResponder responder) { this.log(logLine, CBLogLevel.DEBUG, category, responder, false); } /** * Send a line to the log on the cloudbase.io application log. * * @param logLine The content of the log line * @param level The severity of the log line, a CBLogLevel value * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events */ public void log(String logLine, CBLogLevel level, String category) { this.log(logLine, level, category, null, false); } /** * Send a line to the log on the cloudbase.io application log. * * @param logLine The content of the log line * @param level The severity of the log line, a CBLogLevel value * @param category The category of the log line. This is a free text string and can be used to separate different * sections of the application and events * @param responder A responder to handle the return value from the cloudbase.io APIs. This is an optional parameter * and can be sent as null * @param shouldQueue whether the request should be queued if connectivity is not available */ public void log(String logLine, CBLogLevel level, String category, CBHelperResponder responder, boolean shouldQueue) { String url = this.getUrl() + this.appCode + "/log"; // Create the log object Hashtable logData = new Hashtable(); logData.put("category", (category == null?CBHelper.defaultLogCategory:category)); logData.put("level", level.toString()); logData.put("device_name", this.deviceInfo.getDeviceName()); logData.put("device_model", this.deviceInfo.getDeviceModel()); logData.put("log_line", logLine); Hashtable preparedPost = this.preparePostParams(logData, null); this.startRequest(url, "log", null, preparedPost, null, responder, shouldQueue); } /** * Sends cloudbase.io the name of the newly opened screen. This data is used to then generate the usage * flow analytics and show how people interact with your application * This API request will always be queued * @param screenName The unique name assigned to the opened view */ public void logNavigation(String screenName) { String url = this.getUrl() + this.appCode + "/lognavigation"; Hashtable logData = new Hashtable(); logData.put("session_id", this.sessionId); logData.put("screen_name", screenName); Hashtable preparedPost = this.preparePostParams(logData, null); this.startRequest(url, "log", null, preparedPost, null, null, true); } /** * Inserts the given object in a cloudbase.io collection. If the collection does not exist it is automatically created. * Similarly if the data structure of the given object is different from documents already present in the collection * the structure is automatically altered to accommodate the new object. * The system will automatically try to serialize any object sent to this function. However, we recommend you use * the simplest possible objects to hold data if not a Map or Array directly. * Once the call to the APIs is completed the responder is called. * This API request will not be queued * @param document The object to be inserted * @param collection The name of the collection the document should be inserted into */ public void insertDocument(Object document, String collection) { insertDocument(document, collection, null, null); } /** * Inserts the given object in a cloudbase.io collection. If the collection does not exist it is automatically created. * Similarly if the data structure of the given object is different from documents already present in the collection * the structure is automatically altered to accommodate the new object. * The system will automatically try to serialize any object sent to this function. However, we recommend you use * the simplest possible objects to hold data if not a Map or Array directly. * Once the call to the APIs is completed the responder is called. * @param document The object to be inserted * @param collection The name of the collection the document should be inserted into * @param shouldQueue whether the request should be queued if connectivity is not available */ public void insertDocument(Object document, String collection, boolean shouldQueue) { insertDocument(document, collection, null, null, shouldQueue); } /** * Inserts the given object in a cloudbase.io collection. If the collection does not exist it is automatically created. * Similarly if the data structure of the given object is different from documents already present in the collection * the structure is automatically altered to accommodate the new object. * The system will automatically try to serialize any object sent to this function. However, we recommend you use * the simplest possible objects to hold data if not a Map or Array directly. * Once the call to the APIs is completed the responder is called. * This API request will not be queued * @param document The object to be inserted * @param collection The name of the collection the document should be inserted into * @param responder The CBHelperResponder object to handle the response from the cloudbase.io APIs */ public void insertDocument(Object document, String collection, CBHelperResponder responder) { insertDocument(document, collection, null, responder); } /** * Inserts the given object in a cloudbase.io collection. If the collection does not exist it is automatically created. * Similarly if the data structure of the given object is different from documents already present in the collection * the structure is automatically altered to accommodate the new object. * The system will automatically try to serialize any object sent to this function. However, we recommend you use * the simplest possible objects to hold data if not a Map or Array directly. * Once the call to the APIs is completed the responder is called. * @param document The object to be inserted * @param collection The name of the collection the document should be inserted into * @param responder The CBHelperResponder object to handle the response from the cloudbase.io APIs * @param shouldQueue whether the request should be queued if connectivity is not available */ public void insertDocument(Object document, String collection, CBHelperResponder responder, boolean shouldQueue) { insertDocument(document, collection, null, responder, shouldQueue); } /** * Inserts the given object in a cloudbase.io collection. If the collection does not exist it is automatically created. * Similarly if the data structure of the given object is different from documents already present in the collection * the structure is automatically altered to accommodate the new object. * The system will automatically try to serialize any object sent to this function. However, we recommend you use * the simplest possible objects to hold data if not a Map or Array directly. * Once the call to the APIs is completed the responder is called. * This API request will not be queued * @param document The object to be inserted * @param collection The name of the collection the document should be inserted into * @param attachments An ArrayList of of File objects to be attached to the record. File IDs will be stored in the additional column * cb_files * @param responder The CBHelperResponder object to handle the response from the cloudbase.io APIs */ public void insertDocument(Object document, String collection, ArrayList attachments, CBHelperResponder responder) { this.insertDocument(document, collection, attachments, responder, false); } @SuppressWarnings("unchecked") /** * Inserts the given object in a cloudbase.io collection. If the collection does not exist it is automatically created. * Similarly if the data structure of the given object is different from documents already present in the collection * the structure is automatically altered to accommodate the new object. * The system will automatically try to serialize any object sent to this function. However, we recommend you use * the simplest possible objects to hold data if not a Map or Array directly. * Once the call to the APIs is completed the responder is called. * @param document The object to be inserted * @param collection The name of the collection the document should be inserted into * @param attachments An ArrayList of of File objects to be attached to the record. File IDs will be stored in the additional column * cb_files * @param responder The CBHelperResponder object to handle the response from the cloudbase.io APIs * @param shouldQueue whether the request should be queued if connectivity is not available */ public void insertDocument(Object document, String collection, ArrayList attachments, CBHelperResponder responder, boolean shouldQueue) { // We need to insert a List as the cloudbase.io APIs expect an array of objects to the // insert APIs - this way we can insert multiple objects at the same time. If it is not a List // then create a new List and insert the given object in it. List finalDocument; if (document instanceof List) finalDocument = (List)document; else { finalDocument = new ArrayList(); finalDocument.add(document); } String url = this.getUrl() + this.appCode + "/" + collection + "/insert"; Hashtable preparedPost = this.preparePostParams(finalDocument, null); this.startRequest(url, "data", null, preparedPost, attachments, responder, shouldQueue); } /** * Updates a document in a collection in the Cloud Database. The documents to update are identified using the CBSearchCondition * parameter to the method. * @param document The new object to update * @param cond The search condition to match the documents to be updated in the Cloud Database * @param collection The name of the collection containing the documents to update * @param isUpsert Whether this is an upsert request (if the document doesn't exist then insert) * @param attachments An ArrayList of File objects to be attached to the new document * @param shouldQueue Whether the request should be queued * @throws Exception */ public void updateDocument(Object document, CBSearchCondition cond, String collection, boolean isUpsert, ArrayList attachments) throws Exception { this.updateDocument(document, cond, collection, isUpsert, attachments, null, false); } /** * Updates a document in a collection in the Cloud Database. The documents to update are identified using the CBSearchCondition * parameter to the method. * @param document The new object to update * @param cond The search condition to match the documents to be updated in the Cloud Database * @param collection The name of the collection containing the documents to update * @param isUpsert Whether this is an upsert request (if the document doesn't exist then insert) * @param attachments An ArrayList of File objects to be attached to the new document * @param responder A reponder to receive the cloudbase.io response * @param shouldQueue Whether the request should be queued * @throws Exception */ public void updateDocument(Object document, CBSearchCondition cond, String collection, boolean isUpsert, ArrayList attachments, CBHelperResponder responder, boolean shouldQueue) throws Exception { JsonElement tmpElement = CBHelper.jsonParser.toJsonTree(document); if ( !tmpElement.isJsonObject() ) { throw new Exception("Update is allowed only on objects"); } JsonObject tmpObject = (JsonObject)tmpElement; tmpObject.add("cb_search_key", CBHelper.jsonParser.toJsonTree(cond.serializeConditions(cond))); if ( isUpsert ) { tmpObject.addProperty("cb_upsert", 1); } String url = this.getUrl() + this.appCode + "/" + collection + "/update"; Hashtable preparedPost = this.preparePostParams(tmpObject, null); this.startRequest(url, "data", null, preparedPost, attachments, responder, shouldQueue); } /** * Returns all of the documents in the given collection * This API request will not be queued * @param collection The name of the collection to run the search over * @param responder The CBHelperResponder object to manage the data returned from the cloudbase.io APIs */ public void searchDocument(String collection, CBHelperResponder responder) { this.searchDocument(collection, null, responder); } /** * Returns all of the documents in the given collection * @param collection The name of the collection to run the search over * @param responder The CBHelperResponder object to manage the data returned from the cloudbase.io APIs * @param shouldQueue whether the request should be queued if connectivity is not available */ public void searchDocument(String collection, CBHelperResponder responder, boolean shouldQueue) { this.searchDocument(collection, null, responder, shouldQueue); } /** * Runs a search over a collection with the given criteria. The documents matching the search criteria are then * returned to the given responder object * This API request will not be queued * @param collection The name of the collection to run the search over * @param cond A CBSearchCondition object containing the criteria for this search. This object can be null, in which case * all of the documents in the collection will be returned * @param responder The CBHelperResponder object to manage the data returned from the cloudbase.io APIs */ public void searchDocument(String collection, CBSearchCondition cond, CBHelperResponder responder) { this.searchDocument(collection, cond, responder, false); } /** * Runs a search over a collection with the given criteria. The documents matching the search criteria are then * returned to the given responder object * @param collection The name of the collection to run the search over * @param cond A CBSearchCondition object containing the criteria for this search. This object can be null, in which case * all of the documents in the collection will be returned * @param responder The CBHelperResponder object to manage the data returned from the cloudbase.io APIs * @param shouldQueue whether the request should be queued if connectivity is not available */ @SuppressWarnings("rawtypes") public void searchDocument(String collection, CBSearchCondition cond, CBHelperResponder responder, boolean shouldQueue) { // if we have no conditions for the request then send an empty Map - the cloudbase.io APIs // will then return all of the objects in the collection Map serializedConditions = null; if (cond != null) serializedConditions = cond.serializeConditions(); else { serializedConditions = new HashMap(); } String url = this.getUrl() + this.appCode + "/" + collection + "/search"; Hashtable preparedPost = this.preparePostParams(serializedConditions, null); this.startRequest(url, "data", null, preparedPost, null, responder, shouldQueue); } /** * Runs a search over a collection and applies the given list of aggregation commands to the output. * This API request will not be queued * @param collection The name of the collection to run the search over * @param aggregateConditions A List of CBDataAggregationCommand objects * @param handler a block of code to be executed once the request is completed */ public void searchDocumentAggregate(String collection, List aggregateConditions, CBHelperResponder responder) { this.searchDocumentAggregate(collection, aggregateConditions, responder, false); } /** * Runs a search over a collection and applies the given list of aggregation commands to the output. * @param collection The name of the collection to run the search over * @param aggregateConditions A List of CBDataAggregationCommand objects * @param handler a block of code to be executed once the request is completed * @param shouldQueue whether the request should be queued if connectivity is not available */ public void searchDocumentAggregate(String collection, List aggregateConditions, CBHelperResponder responder, boolean shouldQueue) { List> serializedAggregateConditions = new ArrayList>(); for (CBDataAggregationCommand curComm : aggregateConditions) { Map curSerializedCondition = new HashMap(); curSerializedCondition.put(curComm.getCommandType().toString(), curComm.serializeAggregateConditions()); serializedAggregateConditions.add(curSerializedCondition); } String url = this.getUrl() + this.appCode + "/" + collection + "/aggregate"; HashMap paramsToPrepare = new HashMap(); paramsToPrepare.put("cb_aggregate_key", serializedAggregateConditions); Hashtable preparedPost = this.preparePostParams(paramsToPrepare, null); this.startRequest(url, "data", null, preparedPost, null, responder, shouldQueue); } /** * Downloads a file matching the given file id. The file id comes from the cloudbase.io cb_files field on collections * created when documents are inserted with file attachments. * The data is downloaded and a java.io.File object is made available in the CBHelperResponse class called downloadedFile * This API request will not be queued * @param fileId the cloudbase.io generated file id * @param responder The object to handle the response object */ public void downloadFile(String fileId, CBHelperResponder responder) { this.downloadFile(fileId, responder, false); } /** * Downloads a file matching the given file id. The file id comes from the cloudbase.io cb_files field on collections * created when documents are inserted with file attachments. * The data is downloaded and a java.io.File object is made available in the CBHelperResponse class called downloadedFile * @param fileId the cloudbase.io generated file id * @param responder The object to handle the response object * @param shouldQueue whether the request should be queued if connectivity is not available */ public void downloadFile(String fileId, CBHelperResponder responder, boolean shouldQueue) { String url = this.getUrl() + this.appCode + "/file/" + fileId; Hashtable preparedPost = this.preparePostParams(null, null); this.startRequest(url, "download", fileId, preparedPost, null, responder, shouldQueue); } /** * Subscribes the current device, with the Key received from Google's C2DM or GCM to a notification channel. By default all * devices are automatically subscribed to the "All" channel. * This API request will not be queued * @param deviceKey The registration id received from the Google's C2DM/GCM * @param channel The name of the channel to subscribe to. If the given channel does not exist then it is automatically * created * @param isC2DM Whether to use the C2DM or the GCM network to send the push notification */ public void notificationSubscribeDevice(String deviceKey, String channel, boolean isC2DM) { notificationSubscribeDevice(deviceKey, channel, isC2DM, null); } /** * Subscribes the current device, with the Key received from Google's C2DM or GCM to a notification channel. By default all * devices are automatically subscribed to the "All" channel. * This API request will not be queued * @param deviceKey deviceKey The registration id received from the Google's C2DM/GCM * @param channel The name of the channel to subscribe to. If the given channel does not exist then it is automatically * @param isC2DM Whether to use the C2DM or the GCM network to send the push notification * @param responder A CBHelperResponder object to handle the response from the cloudbase.io APIs */ public void notificationSubscribeDevice(String deviceKey, String channel, boolean isC2DM, CBHelperResponder responder) { this.notificationSubscribeDevice(deviceKey, channel, responder, isC2DM, false); } /** * Subscribes the current device, with the Key received from Google's C2DM or GCM to a notification channel. By default all * devices are automatically subscribed to the "All" channel. * @param deviceKey deviceKey The registration id received from the Google's C2DM/GCM * @param channel The name of the channel to subscribe to. If the given channel does not exist then it is automatically * @param responder A CBHelperResponder object to handle the response from the cloudbase.io APIs * @param isC2DM Whether to use the C2DM or the GCM network to send the push notification * @param shouldQueue whether the request should be queued if connectivity is not available */ public void notificationSubscribeDevice(String deviceKey, String channel, CBHelperResponder responder, boolean isC2DM, boolean shouldQueue) { Map subForm = new HashMap(); subForm.put("action", "subscribe"); subForm.put("device_key", deviceKey); subForm.put("device_network", "and"); subForm.put("android_network", (isC2DM?"c2dm":"gcm")); subForm.put("channel", channel); String url = this.getUrl() + this.appCode + "/notifications-register"; Hashtable preparedPost = this.preparePostParams(subForm, null); this.startRequest(url, "notifications-register", null, preparedPost, null, responder, shouldQueue); } /** * Unsubscribes the current device from the given notification channel * This API request will not be queued * @param deviceKey deviceKey The registration id received from the Google's C2DM * @param channel The name of the channel to subscribe to. If the given channel does not exist then it is automatically */ public void notificationUnsubscribeDevice(String deviceKey, String channel) { notificationUnsubscribeDevice(deviceKey, channel, null); } /** * Unsubscribes the current device from the given notification channel * This API request will not be queued * @param deviceKey deviceKey The registration id received from the Google's C2DM * @param channel The name of the channel to subscribe to. If the given channel does not exist then it is automatically * @param responder A CBHelperResponder object to handle the response from the cloudbase.io server */ public void notificationUnsubscribeDevice(String deviceKey, String channel, CBHelperResponder responder) { this.notificationUnsubscribeDevice(deviceKey, channel, responder, false); } /** * Unsubscribes the current device from the given notification channel * @param deviceKey deviceKey The registration id received from the Google's C2DM * @param channel The name of the channel to subscribe to. If the given channel does not exist then it is automatically * @param responder A CBHelperResponder object to handle the response from the cloudbase.io server * @param shouldQueue whether the request should be queued if connectivity is not available */ public void notificationUnsubscribeDevice(String deviceKey, String channel, CBHelperResponder responder, boolean shouldQueue) { Map subForm = new HashMap(); subForm.put("action", "unsubscribe"); subForm.put("device_key", deviceKey); subForm.put("device_network", "and"); subForm.put("channel", channel); String url = this.getUrl() + this.appCode + "/notifications-register"; Hashtable preparedPost = this.preparePostParams(subForm, null); this.startRequest(url, "notifications-register", null, preparedPost, null, responder, shouldQueue); } /** * Pushes a notification to the given channels

* Device notifications must be enabled in the application configuration on cloudbase.io for this to work. * @param notificationText The content of the notification text * @param channels An ArrayList of channel names (String) to be notified * @param shouldQueue whether the request should be queued if connectivity is not available */ public void sendNotification(String notificationText, ArrayList channels, boolean shouldQueue) { for (String channel : channels) { sendNotification(notificationText, channel, shouldQueue); } } /** * Pushes a notification to the given channel. If channel is null then the default "All" channel will be used

* Device notifications must be enabled in the application configuration on cloudbase.io for this to work. * @param notificationText The full text for the notification * @param channel The channel this notification should be sent to * @param shouldQueue whether the request should be queued if connectivity is not available */ public void sendNotification(String notificationText, String channel, boolean shouldQueue) { Map subForm = new HashMap(); subForm.put("channel", channel); subForm.put("cert_type", "production"); subForm.put("alert", notificationText); subForm.put("badge", ""); subForm.put("sound", ""); String url = this.getUrl() + this.appCode + "/notifications"; Hashtable preparedPost = this.preparePostParams(subForm, null); this.startRequest(url, "notifications", null, preparedPost, null, null, shouldQueue); } /** * Pushes a notification to a list of channels using the Google Cloud Messaging system * @param notificationText The text for the notification * @param tickerText The ticker text for the GCM message * @param contentTitle The content title for the GCM message * @param contentText The text for the GCM message * @param channel The channel this notification should be sent to * @param shouldQueue whether the request should be queued if connectivity is not available */ public void sendGCMNotification(String notificationText, String tickerText, String contentTitle, String contentText, ArrayList channels, boolean shouldQueue) { for (String channel : channels) { sendGCMNotification(notificationText, tickerText, contentTitle, contentText, channel, shouldQueue); } } /** * Pushes a notification using the Google Cloud Messaging system * @param notificationText The text for the notification * @param tickerText The ticker text for the GCM message * @param contentTitle The content title for the GCM message * @param contentText The text for the GCM message * @param channel The channel this notification should be sent to * @param shouldQueue whether the request should be queued if connectivity is not available */ public void sendGCMNotification(String notificationText, String tickerText, String contentTitle, String contentText, String channel, boolean shouldQueue) { Map subForm = new HashMap(); subForm.put("channel", channel); subForm.put("cert_type", "production"); subForm.put("alert", notificationText); subForm.put("gcm_ticker_text", tickerText); subForm.put("gcm_content_title", contentTitle); subForm.put("gcm_content_text", contentText); String url = this.getUrl() + this.appCode + "/notifications"; Hashtable preparedPost = this.preparePostParams(subForm, null); this.startRequest(url, "notifications", null, preparedPost, null, null, shouldQueue); } /** * Sends an email to the specified recipient using the given template. * This API request will not be queued * @param templateCode The code of the template created in the control panel on cloudbase.io * @param recipient The email address of the recipient of the email * @param subject The subject of the email * @param vars A Map of variables to fill the template. */ public void sendEmail(String templateCode, String recipient, String subject, Map vars) { this.sendEmail(templateCode, recipient, subject, vars, false); } /** * Sends an email to the specified recipient using the given template. * @param templateCode The code of the template created in the control panel on cloudbase.io * @param recipient The email address of the recipient of the email * @param subject The subject of the email * @param vars A Map of variables to fill the template. * @param shouldQueue whether the request should be queued if connectivity is not available */ public void sendEmail(String templateCode, String recipient, String subject, Map vars, boolean shouldQueue) { Map subForm = new HashMap(); subForm.put("template_code", templateCode); subForm.put("recipient", recipient); subForm.put("subject", subject); subForm.put("variables", CBHelper.jsonParser.toJson(vars)); String url = this.getUrl() + this.appCode + "/email"; Hashtable preparedPost = this.preparePostParams(subForm, null); this.startRequest(url, "email", null, preparedPost, null, null, shouldQueue); } /** * Executes a CloudFunction on the cloudbase.io servers on demand. Results will be ignored. * This API request will not be queued * @param functionCode The name of the function to be executed */ public void runCloudFunction(String functionCode) { runCloudFunction(functionCode, null, null); } /** * Executes a CloudFunction on the coudbase.io servers on demand. The additional parameters will be accessible * to the function like standard HTTP POST parameters. Results will be ignored. * This API request will not be queued * @param functionCode The name of the function to be executed * @param params The list of parameters to be passed to the function */ public void runCloudFunction(String functionCode, Map params) { runCloudFunction(functionCode, params, null); } /** * Executes a CloudFunction on the coudbase.io servers on demand. The additional parameters will be accessible * to the function like standard HTTP POST parameters. Results and output are parsed and handed to the responder. * This API request will not be queued * @param functionCode The name of the function to be executed * @param params The list of parameters to be passed to the function * @param responder The CBHelperResponder to handle the response value */ public void runCloudFunction(String functionCode, Map params, CBHelperResponder responder) { this.runCloudFunction(functionCode, params, responder, false); } /** * Executes a CloudFunction on the coudbase.io servers on demand. The additional parameters will be accessible * to the function like standard HTTP POST parameters. Results and output are parsed and handed to the responder. * @param functionCode The name of the function to be executed * @param params The list of parameters to be passed to the function * @param responder The CBHelperResponder to handle the response value * @param shouldQueue whether the request should be queued if connectivity is not available */ public void runCloudFunction(String functionCode, Map params, CBHelperResponder responder, boolean shouldQueue) { String url = this.getUrl() + this.appCode + "/cloudfunction/" + functionCode; Hashtable preparedPost = this.preparePostParams(Collections.EMPTY_MAP, params); this.startRequest(url, "cloudfunction", null, preparedPost, null, responder, shouldQueue); } /** * Executes a Shared API on the coudbase.io servers on demand. The additional parameters will be accessible * to the function like standard HTTP POST parameters. Results and output are parsed and handed to the responder. * @param apiCode The unique identifier for the Shared API * @param password The password to access the Shared API if necessary * @param params The list of parameters to be passed to the function * @param responder The CBHelperResponder to handle the response value */ public void runSharedApi(String apiCode, String password, Map params, CBHelperResponder responder) { this.runSharedApi(apiCode, password, params, responder, false); } /** * Executes a Shared API on the coudbase.io servers on demand. The additional parameters will be accessible * to the function like standard HTTP POST parameters. Results and output are parsed and handed to the responder. * @param apiCode The unique identifier for the Shared API * @param password The password to access the Shared API if necessary * @param params The list of parameters to be passed to the function * @param responder The CBHelperResponder to handle the response value * @param shouldQueue whether the request should be queued if connectivity is not available */ public void runSharedApi(String apiCode, String password, Map params, CBHelperResponder responder, boolean shouldQueue) { String url = this.getUrl() + this.appCode + "/shared/" + apiCode; if ( password != null && !password.equals("") ) { params.put("cb_shared_password", password); } Hashtable preparedPost = this.preparePostParams(Collections.EMPTY_MAP, params); this.startRequest(url, "shared-api", null, preparedPost, null, responder, shouldQueue); } /** * Executes of the cloudbase.io applets on demand. * Results and output are parsed and handed to the responder. * This API request will not be queued * @param appletCode The name of the applet to be executed * @param params The list of parameters to be passed to the applet * @param responder The CBHelperResponder to handle the response value */ public void runApplet(String appletCode, Map params, CBHelperResponder responder) { this.runApplet(appletCode, params, responder, false); } /** * Executes of the cloudbase.io applets on demand. * Results and output are parsed and handed to the responder. * @param appletCode The name of the applet to be executed * @param params The list of parameters to be passed to the applet * @param responder The CBHelperResponder to handle the response value * @param shouldQueue whether the request should be queued if connectivity is not available */ public void runApplet(String appletCode, Map params, CBHelperResponder responder, boolean shouldQueue) { String url = this.getUrl() + this.appCode + "/applet/" + appletCode; Hashtable preparedPost = this.preparePostParams(Collections.EMPTY_MAP, params); this.startRequest(url, "applet", null, preparedPost, null, responder, shouldQueue); } /** * Initiates a transaction with PayPal by sending the payment details and retrieving a token * and an express checkout url. The url returned should be then opened in a browser window. * This API request will not be queued * @param purchaseDetails a populated CBPayPalBill object * @param isLiveEnvironment whether we are using the production or sandbox paypal environments * @param responder a responder to handle the returned PayPal token and submission url */ public void preparePayPalPurchase(CBPayPalBill purchaseDetails, boolean isLiveEnvironment, CBHelperResponder responder) { this.preparePayPalPurchase(purchaseDetails, isLiveEnvironment, responder, false); } /** * Initiates a transaction with PayPal by sending the payment details and retrieving a token * and an express checkout url. The url returned should be then opened in a browser window. * @param purchaseDetails a populated CBPayPalBill object * @param isLiveEnvironment whether we are using the production or sandbox paypal environments * @param responder a responder to handle the returned PayPal token and submission url * @param shouldQueue whether the request should be queued if connectivity is not available */ public void preparePayPalPurchase(CBPayPalBill purchaseDetails, boolean isLiveEnvironment, CBHelperResponder responder, boolean shouldQueue) { String url = this.getUrl() + this.appCode + "/paypal/prepare"; Hashtable postData = new Hashtable(); postData.put("environment", isLiveEnvironment?"live":"sandbox"); postData.put("currency", purchaseDetails.getCurrency()); postData.put("type", "purchase"); postData.put("completed_cloudfunction", purchaseDetails.getPaymentCompletedFunction()); postData.put("cancelled_cloudfunction", purchaseDetails.getPaymentCancelledFunction()); postData.put("purchase_details", purchaseDetails.serializePurchase()); if (purchaseDetails.getPaymentCompletedUrl() != null) postData.put("payment_completed_url", purchaseDetails.getPaymentCompletedUrl()); if (purchaseDetails.getPaymentCancelledUrl() != null) postData.put("payment_cancelled_url", purchaseDetails.getPaymentCancelledUrl()); Hashtable preparedPost = this.preparePostParams(postData, null); this.startRequest(url, "paypal", null, preparedPost, null, responder, shouldQueue); } /** * Once the PayPal purchase is completed this method updates the record in the cloudbase.io database. * The responder can then proceed to close the payment window using the output of the call. * This API request will not be queued * @param url The url returned by PayPal once the payment is completed * @param responder The responder to complete the payment in the application * @param shouldQueue whether the request should be queued if connectivity is not available */ public void completePayPalPurchase(String url, CBHelperResponder responder) { this.completePayPalPurchase(url, responder, false); } /** * Once the PayPal purchase is completed this method updates the record in the cloudbase.io database. * The responder can then proceed to close the payment window using the output of the call * @param url The url returned by PayPal once the payment is completed * @param responder The responder to complete the payment in the application * @param shouldQueue whether the request should be queued if connectivity is not available */ public void completePayPalPurchase(String url, CBHelperResponder responder, boolean shouldQueue) { Hashtable preparedPost = this.preparePostParams(new Hashtable(), null); this.startRequest(url, "paypal", null, preparedPost, null, responder, shouldQueue); } /** * Returns all of the details of a payment which has been prepared. * This API request will not be queued * @param paymentId The payment_id returned by the cloudbase.io APIs when the payment is prepared * @param responder A responder to handle the details */ public void getPayPalPaymentDetails(String paymentId, CBHelperResponder responder) { this.getPayPalPaymentDetails(paymentId, responder, false); } /** * Returns all of the details of a payment which has been prepared. * @param paymentId The payment_id returned by the cloudbase.io APIs when the payment is prepared * @param responder A responder to handle the details * @param shouldQueue whether the request should be queued if connectivity is not available */ public void getPayPalPaymentDetails(String paymentId, CBHelperResponder responder, boolean shouldQueue) { String url = this.getUrl() + this.appCode + "/paypal/payment-details"; Hashtable postData = new Hashtable(); postData.put("payment_id", paymentId); Hashtable preparedPost = this.preparePostParams(postData, null); this.startRequest(url, "paypal", null, preparedPost, null, responder, shouldQueue); } // this function is used only by the helper class and it registers the device // with the cloudbase.io APIs. This is used to get a session_id used by the logNavigation // method. To receive the session_id the CBHelper object itself is a responder private void registerDevice() { if (this.deviceRegistered) return; Map device = new HashMap(); device.put("device_type", "Android"); device.put("device_name", this.deviceInfo.getDeviceName()); device.put("device_model", this.deviceInfo.getDeviceModel()); device.put("language", this.deviceInfo.getLanguage()); device.put("country", this.deviceInfo.getCountry()); String url = this.getUrl() + this.appCode + "/register"; Hashtable preparedPost = this.preparePostParams(device, null); this.startRequest(url, "register-device", null, preparedPost, null, this, true); /* CBHelperRequest req = new CBHelperRequest(url, "register-device"); req.setPostData(preparedPost); req.setResponder(this); Handler handler = new Handler(); req.setmHandler(handler); Thread t = new Thread(req); t.start(); */ } /** * Starts a request to the cloudbase.io APIs and passes on all of the parameters. Also handles the queueing * of requests * @param url The API url to be called * @param function The cloudbase.io function code * @param postParams The prepared Hashtable of post parameters * @param responder A responder ogject if available */ private void startRequest(String url, String function, String fileId, Hashtable postParams, ArrayList attachments, CBHelperResponder responder, boolean shouldQueue) { // if connectivity is available and we have a queue of requests then start it now if (this.isNetworkAvailable() && this.getQueueSize() > 0 && !this.isQueueLocked()) { this.createQueueLock(); CBQueuedRequestSender sender = new CBQueuedRequestSender(this.getQueue(), this); Thread senderThread = new Thread(sender); senderThread.start(); } CBQueuedRequest queueRequest = new CBQueuedRequest(); queueRequest.setUrl(url); queueRequest.setCloudbaseFunction(function); queueRequest.setParameters(postParams); if (attachments != null) queueRequest.setFiles(attachments); if (fileId != null) queueRequest.setFileId(fileId); String queueFileName = ""; CBHelperRequest req = new CBHelperRequest(queueRequest, this); if (responder != null) { req.setResponder(responder); } if (shouldQueue) { queueFileName = this.queueRequest(queueRequest); req.setQueueFileName(queueFileName); } req.setTemporaryFilePath(this.getTemporaryFilesPath()); if (this.isNetworkAvailable()) { Thread t = new Thread(req); t.start(); } } private String queueRequest(CBQueuedRequest request) { try { String queuePath = this.getQueueFolder(); //if (this.debugMode) //Log.i(logTag, "using queue folder: " + queuePath); String queueFileName = queuePath + File.separator + "cb_queue_" + this.getQueueSize(); FileOutputStream fos = new FileOutputStream(queueFileName, true);//this.applicationActivity.openFileOutput(queueFileName, Context.MODE_PRIVATE); ObjectOutputStream os = new ObjectOutputStream(fos); os.writeObject(request); os.close(); //if (this.debugMode) //Log.i(logTag, "Saved queue object to " + queueFileName); return queueFileName; } catch (Exception e) { //Log.e(logTag, "Error while saving queued request", e); return null; } } private void createQueueLock() { try { FileOutputStream fos = new FileOutputStream(this.getQueueLockFile(), true); fos.write("lock".getBytes()); fos.close(); } catch (Exception e) { //Log.e(logTag, "Error while creating queue lock file", e); } } public void removeQueueLock() { File lockFile = new File(this.getQueueLockFile()); if (lockFile.exists()) lockFile.delete(); } public boolean isQueueLocked() { File lockFile = new File(this.getQueueLockFile()); return lockFile.exists(); } public void removeQueuedRequest(String fileName) { try { File queueFile = new File(fileName); if (queueFile.exists() && queueFile.isFile()) { queueFile.delete(); //if (this.debugMode) //Log.i(logTag, "removed queue file " + fileName); } else { //if (this.debugMode) //Log.e(logTag, "Could not find queue file " + fileName); } } catch (Exception e) { //Log.e(logTag, "Error while removing queue file " + fileName, e); } } private int getQueueSize() { if (this.isQueueLocked()) return 0; File queueFolder = new File(this.getQueueFolder() + File.separator); String queueLockFile = this.getQueueLockFile(); int size = 0; //return queueFolder.listFiles().length; for (File curFile : queueFolder.listFiles()) { if (curFile.getAbsolutePath().equals(queueLockFile)) continue; size++; } return size; } private ArrayList getQueue() { ArrayList queue = new ArrayList(); File queueFolder = new File(this.getQueueFolder() + File.separator); String queueLockFile = this.getQueueLockFile(); for (File curQueueFile : queueFolder.listFiles()) { if (curQueueFile.getAbsolutePath().equals(queueLockFile)) continue; queue.add(curQueueFile.getAbsolutePath()); } return queue; } public void flushQueue() { File queueFolder = new File(this.getQueueFolder() + File.separator); for (File curQueueFile : queueFolder.listFiles()) { if (!curQueueFile.getAbsolutePath().equals(this.getQueueLockFile())) this.removeQueuedRequest(curQueueFile.getAbsolutePath()); } } private String getQueueFolder() { String queueFolder = this.temporaryFilesPath + File.separator + "cb_queue"; File queueFolderFile = new File(queueFolder); if (!queueFolderFile.exists()) { queueFolderFile.mkdirs(); } queueFolderFile = null; return queueFolder; } private String getQueueLockFile() { String queueFolder = this.temporaryFilesPath + File.separator + "cb_queue"; queueFolder += File.separator + "cb_queue_lock"; return queueFolder; } // This function prepares a request for the cloudbase.io APIs adding all the default // parameters needed for a call private Hashtable preparePostParams(Object postData, Map additionalParams) { Hashtable post = new Hashtable(); post.put("app_uniq", this.appSecret); post.put("app_pwd", this.password); post.put("device_uniq", this.deviceInfo.getDeviceUniqueIdentifier()); // additional parameters are used for the CloudFunction and Applet APIs if (additionalParams != null) { Set keys = additionalParams.keySet(); for (String curKey : keys) { post.put(curKey, additionalParams.get(curKey)); } } if (this.userAuthentication) { post.put("cb_auth_user", this.authUsername); post.put("cb_auth_password", this.authPassword); } if (this.useLocation && this.currentLocation != null) { Hashtable locData = new Hashtable(); locData.put("lat", Double.toString(this.currentLocation.getLat())); locData.put("lng", Double.toString(this.currentLocation.getLng())); locData.put("alt", Double.toString(this.currentLocation.getAlt())); post.put("location_data", CBHelper.jsonParser.toJson(locData)); } if ( postData instanceof JsonObject ) { post.put("post_data", ((JsonObject)postData).toString()); } else { post.put("post_data", CBHelper.jsonParser.toJson(postData)); } return post; } private String getUrl() { return (this.https?"https":"http") + "://" + this.apiURL + "/"; } /** * Returns the device unique identifier used by this object * @return A String representing the unique identifier */ public String getDeviceUniqueIdentifier() { return this.deviceInfo.getDeviceUniqueIdentifier(); } /** * Sets the unique identifier. By default this is initialized to the ANDROID_ID in the Secure * class. * @param deviceUniqueIdentifier The new unique identifier */ public void setDeviceUniqueIdentifier(String deviceUniqueIdentifier) { this.deviceInfo.setDeviceUniqueIdentifier(deviceUniqueIdentifier); } /** * Sets the password for the application to access the APIs. This should be an md5 encoded string. * @param password The md5 hash of the password */ public void setPassword(String password) { this.password = password; // after the password is set we should have all of the information needed // to connect to cloudbase.io and register the device. this.registerDevice(); this.deviceRegistered = true; } private boolean isNetworkAvailable() { return true; } public boolean isHttps() { return https; } public void setHttps(boolean https) { this.https = https; } public boolean isUserAuthentication() { return userAuthentication; } public void setUserAuthentication(boolean userAuthentication) { this.userAuthentication = userAuthentication; } public String getAuthUsername() { return authUsername; } public void setAuthUsername(String authUsername) { this.authUsername = authUsername; } public String getAuthPassword() { return authPassword; } public void setAuthPassword(String authPassword) { this.authPassword = authPassword; } public boolean isUseLocation() { return useLocation; } public void setUseLocation(boolean useLocation) { this.useLocation = useLocation; } public CBLocation getCurrentLocation() { return currentLocation; } public void setCurrentLocation(CBLocation currentLocation) { this.currentLocation = currentLocation; } public String getTemporaryFilesPath() { return temporaryFilesPath; } public void setTemporaryFilesPath(String temporaryFilesPath) { this.temporaryFilesPath = temporaryFilesPath; } public boolean isDebugMode() { return debugMode; } /** * If the object is set in debug mode then additional logging messages * will be printed in the Android category log using the CBHELPER tag * @param debugMode true if the object should run in debug mode */ public void setDebugMode(boolean debugMode) { this.debugMode = debugMode; } public CBHelperResponder getDefaultQueueResponder() { return defaultQueueResponder; } /** * Sets the default CBHelperResponder object to receive messages from API * requests queued because internet connectivity wasn't available. * @param defaultQueueResponder A CBHelperResponder object */ public void setDefaultQueueResponder(CBHelperResponder defaultQueueResponder) { this.defaultQueueResponder = defaultQueueResponder; } public String getApiURL() { return apiURL; } public void setApiURL(String apiURL) { this.apiURL = apiURL; } // This is the response handler for the registerDevice method. Read the session_id // from cloudbase and save it in the CBHelper global variable @SuppressWarnings("unchecked") public void handleResponse(CBQueuedRequest req, CBHelperResponse res) { if (res == null) { return; } if (res.getFunction().equals("register-device") && res.isSuccess()) { Map map = (Map)res.getData(); if (map.containsKey("sessionid")) this.sessionId = (String)map.get("sessionid"); } } }