package kidozen.client; import android.os.AsyncTask; import org.apache.http.HttpStatus; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import kidozen.client.authentication.IdentityManager; import kidozen.client.authentication.KidoZenUser; import kidozen.client.authentication.KidoZenUserIdentityType; import kidozen.client.internal.Constants; import kidozen.client.internal.SNIConnectionManager; import kidozen.client.internal.Utilities; /** * Base class for the following services: * - Storage * - Queue * - PubSub * - Log * - Configuration * - Files * - Mail * - DataSource * - Service */ public class KZService { private Boolean mStrictSSL = true; private boolean mProcessAsStream = false; protected String mName; protected String mEndpoint; protected KidoZenUser mUserIdentity = new KidoZenUser(); protected KidoZenUser mApplicationIdentity = new KidoZenUser(); String mPassiveClientId; String mActiveProvider; String mActiveUsername; String mActivePassword; Hashtable<String, String> mRequestHeaders = new Hashtable<String, String>(); private int mDefaultServiceTimeoutInSeconds = 10; public KZService() { } /* * Before sending the AuthHeader value to the requested service, it checks if the auth timeout * has been reached and executes authentication to get a new token again. * */ public void CreateAuthHeaderValue(final KZServiceEvent<String> cb) { // User Identity is the higher priority if (mUserIdentity != null) { if (mUserIdentity.IdentityType==KidoZenUserIdentityType.USER_IDENTITY) { IdentityManager.getInstance().GetRawToken(mActiveProvider, mActiveUsername, mActivePassword, new ServiceEventListener() { @Override public void onFinish(ServiceEvent e) { mUserIdentity = ((KidoZenUser) e.Response); cb.Fire(String.format("WRAP access_token=\"%s\"", mUserIdentity.Token)); } }); } else { IdentityManager.getInstance().GetToken(mUserIdentity, new ServiceEventListener() { @Override public void onFinish(ServiceEvent e) { cb.Fire(String.format("WRAP access_token=\"%s\"", e.Body)); } }); } } else { IdentityManager.getInstance().GetRawToken(mApplicationIdentity.HashKey, new ServiceEventListener() { @Override public void onFinish(ServiceEvent e) { mApplicationIdentity = ((KidoZenUser) e.Response); cb.Fire(String.format("WRAP access_token=\"%s\"", mApplicationIdentity.Token)); } }); } } /** * Constructor * * You should not create a new instances of this constructor. Instead use the Storage[""] method of the KZApplication object. * @param endpoint The service endpoint * @param name The name of the service to be created */ public KZService(String endpoint, String name,String provider , String username, String pass, String clientSecret, KidoZenUser userIdentity, KidoZenUser applicationIdentity) { mPassiveClientId = clientSecret; mActiveProvider = provider; mActiveUsername = username; mActivePassword = pass; mEndpoint = endpoint; mName = name; this.mApplicationIdentity = applicationIdentity; this.mUserIdentity = userIdentity; } public void ExecuteTask(String url, KZHttpMethod method, HashMap<String, String> params, HashMap<String, String> headers, ServiceEventListener callback, JSONObject message,Boolean bypassSSLValidation) { new KZServiceAsyncTask(method,params,headers,message,callback, bypassSSLValidation).execute(url); } public Boolean getStrictSSL() { return mStrictSSL; } public void setStrictSSL(Boolean strictSSL) { mStrictSSL = strictSSL; } public boolean shouldProcessAsStream() { //System.out.println("KZService, shouldProcessAsStream: " + String.valueOf(mProcessAsStream)); return mProcessAsStream; } public void setmProcessAsStream(boolean mProcessAsStream) { this.mProcessAsStream = mProcessAsStream; } public int getDefaultServiceTimeoutInSeconds() { return mDefaultServiceTimeoutInSeconds; } public void setDefaultServiceTimeoutInSeconds(int mDefaultServiceTimeoutInSeconds) { this.mDefaultServiceTimeoutInSeconds = mDefaultServiceTimeoutInSeconds; } public class KZServiceAsyncTask extends AsyncTask<String, Void, ServiceEvent> { HashMap<String, String> mQueryStringParameters = null; HashMap<String, String> mHeaders = null; KZHttpMethod mHttpMethod = null; ServiceEventListener mServiceEventCallback = null; ServiceEvent mFinalServiceEvent = null; String mStringMessage; InputStream mStreamMessage; Boolean mBypassSSLValidation; private SNIConnectionManager mSniManager; private String mContentType; public KZServiceAsyncTask(KZHttpMethod method, HashMap<String, String> params, HashMap<String, String> headers, ServiceEventListener callback, Boolean bypassSSLValidation) { mHttpMethod = method; mServiceEventCallback = callback; mBypassSSLValidation = bypassSSLValidation; if (params!=null) { mQueryStringParameters = params; } if (headers==null) { mRequestHeaders = new Hashtable<String, String>(); } else { Iterator<Map.Entry<String, String>> it = headers.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> pairs = it.next(); mRequestHeaders.put(pairs.getKey(), pairs.getValue()); it.remove(); } } //System.out.println("KZService, ctor."); } public KZServiceAsyncTask(KZHttpMethod method, HashMap<String, String> params, HashMap<String, String> headers, String message, ServiceEventListener callback, Boolean bypassSSLValidation) { this(method, params, headers, callback, bypassSSLValidation); mStringMessage = message; } public KZServiceAsyncTask(KZHttpMethod method, HashMap<String, String> params, HashMap<String, String> headers, JSONObject message, ServiceEventListener callback, Boolean bypassSSLValidation) { this(method, params, headers, callback, bypassSSLValidation); mStringMessage = message.toString(); } public KZServiceAsyncTask(KZHttpMethod method, HashMap<String, String> params, HashMap<String, String> headers, InputStream message, ServiceEventListener callback, Boolean bypassSSLValidation) { this(method, params, headers, callback, bypassSSLValidation); mStreamMessage = message; } @Override protected void onPreExecute() { super.onPreExecute(); CreateAuthHeaderValue(new KZServiceEvent<String>() { @Override public void Fire(String token) { mRequestHeaders.put(Constants.AUTHORIZATION_HEADER, token); System.out.println("KZService, onPreExecute, got token, " + token); } }); //System.out.println("KZService, onPreExecute"); } @Override protected ServiceEvent doInBackground(String... params) { //System.out.println("KZService, doInBackground"); int statusCode = HttpStatus.SC_BAD_REQUEST; try { String url = params[0]; //System.out.println("KZService, doInBackground, method:" + mHttpMethod); //System.out.println("KZService, doInBackground, url:" + url); if (shouldProcessAsStream()) { mSniManager = new SNIConnectionManager(url, mStreamMessage, mRequestHeaders, mQueryStringParameters, mBypassSSLValidation); OutputStream response = mSniManager.ExecuteHttpAsStream(mHttpMethod); createCallbackResponseForStream(statusCode, response); } else { //System.out.println("KZService, doInBackground, mStringMessage:" + mStringMessage); //System.out.println("KZService, doInBackground, mRequestHeaders:" + mRequestHeaders.toString()); //System.out.println("KZService, doInBackground, mQueryStringParameters:" + mQueryStringParameters); //System.out.println("KZService, doInBackground, mBypassSSLValidation:" + mBypassSSLValidation); mSniManager = new SNIConnectionManager(url, mStringMessage, mRequestHeaders, mQueryStringParameters, mBypassSSLValidation); if (mServiceEventCallback instanceof ServiceResponseHandler) { Utilities.DispatchServiceStartListener((ServiceResponseHandler)mServiceEventCallback); } Hashtable<String, String> response = mSniManager.ExecuteHttp(mHttpMethod); String body = response.get("responseBody"); statusCode = Integer.parseInt(response.get("statusCode")); mContentType = response.get("contentType").toLowerCase(); createCallbackResponse(statusCode, body); body = (body==null || body.equals("") || body.equals("null") ? "" : body); //System.out.println("KZService, doInBackground, body:" + body); //System.out.println("KZService, doInBackground, status:" + response.get("statusCode")); //System.out.println("KZService, doInBackground, content:" + response.get("contentType")); if (body == "") { mFinalServiceEvent = new ServiceEvent(this, statusCode, body, body); } else if (mContentType.contains("application/json")) { Object json = new JSONTokener(body).nextValue(); if (json instanceof JSONObject) { //System.out.println("KZService, doInBackground, Setting a new JSONObject" ); JSONObject theObject = new JSONObject(body); mFinalServiceEvent = new ServiceEvent(this, statusCode, body, theObject); } else if (json instanceof JSONArray) { //System.out.println("KZService, doInBackground, Setting a new JSONArray" ); JSONArray theObject = new JSONArray(body); mFinalServiceEvent = new ServiceEvent(this, statusCode, body, theObject); } } else { //System.out.println("KZService, doInBackground, Setting a new String" ); mFinalServiceEvent = new ServiceEvent(this, statusCode, body, response.get("responseMessage")); } } } catch(Exception e) { //System.out.println("KZService, doInBackground, Exception: " + e.getMessage().toLowerCase() ); String exMessage = (e.getMessage()==null ? "Unexpected error" : e.getMessage().toString()); mFinalServiceEvent = new ServiceEvent(this, statusCode, exMessage, null,e); } return mFinalServiceEvent; } private void createCallbackResponse(int statusCode, String body) { if (statusCode>= HttpStatus.SC_MULTIPLE_CHOICES) { String exceptionMessage = (body!=null ? body : "Unexpected HTTP Status Code: " + statusCode); mFinalServiceEvent = new ServiceEvent(this, statusCode, exceptionMessage, null, new Exception(exceptionMessage)); } } private void createCallbackResponseForStream(int statusCode, OutputStream response) { if (mSniManager.LastResponseCode>= HttpStatus.SC_MULTIPLE_CHOICES) { String exceptionMessage = (mSniManager.LastResponseBody!=null ? mSniManager.LastResponseBody : "Unexpected HTTP Status Code: " + mSniManager.LastResponseCode); mFinalServiceEvent = new ServiceEvent(this, statusCode, exceptionMessage, null, new Exception(exceptionMessage)); } mFinalServiceEvent = new ServiceEvent(this, mSniManager.LastResponseCode, null, response); } @Override protected void onPostExecute(ServiceEvent result) { System.out.println("KZService, onPostExecute" + result.toString()); if (mServiceEventCallback instanceof ServiceResponseHandler) { //System.out.println("KZService, doInBackground, onPostExecute. Is ServiceResponseHandler"); dispatchServiceResponseListener(result, (ServiceResponseHandler) mServiceEventCallback); } else { //System.out.println("KZService, doInBackground, onPostExecute. NOT ServiceResponseHandler"); mServiceEventCallback.onFinish(result); } } private void dispatchServiceResponseListener(final ServiceEvent e,final ServiceResponseHandler callback) { if (e.StatusCode >= HttpStatus.SC_MULTIPLE_CHOICES) { callback.onError(e.StatusCode, e.Body); } else { try { if (mContentType.contains("application/json")) { Object json = new JSONTokener(e.Body).nextValue(); if (json instanceof JSONObject) { JSONObject theObject = new JSONObject(e.Body); callback.onSuccess(e.StatusCode, theObject); } else if (json instanceof JSONArray) { JSONArray o = (JSONArray) e.Response; callback.onSuccess(e.StatusCode, o); } } else { callback.onSuccess(e.StatusCode, e.Body); } } catch (JSONException e1) { callback.onError(e.StatusCode, e1.getMessage()); } } } } }