// Copyright 2015 The Project Buendia Authors // // 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 distrib- // uted 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 // specific language governing permissions and limitations under the License. package org.projectbuendia.client.net; import com.android.volley.DefaultRetryPolicy; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.google.gson.JsonObject; import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.projectbuendia.client.utils.Logger; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; /** * A connection to the module deployed in OpenMRS to provide xforms (which is part of the Buendia * API module). This is not part of OpenMrsServer as it has entirely its own interface, but should * be merged in the future. */ public class OpenMrsXformsConnection { private static final Logger LOG = Logger.create(); private final OpenMrsConnectionDetails mConnectionDetails; public OpenMrsXformsConnection(OpenMrsConnectionDetails connection) { this.mConnectionDetails = connection; } /** * Get a single (full) Xform from the OpenMRS server. * @param uuid the uuid of the form to fetch * @param resultListener the listener to be informed of the form asynchronously * @param errorListener a listener to be informed of any errors */ public void getXform(String uuid, final Response.Listener<String> resultListener, Response.ErrorListener errorListener) { Request request = new OpenMrsJsonRequest(mConnectionDetails, "/xforms/" + uuid + "?v=full", null, // null implies GET new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { String xml = response.getString("xml"); resultListener.onResponse(xml); } catch (JSONException e) { // The result was not in the expected format. Just log, and return // results so far. LOG.e(e, "response was in bad format: " + response); } } }, errorListener ); // Typical response times should be close to 10s, but as the number of users grows, this // number scales up quickly, so use a 30s timeout to be safe. request.setRetryPolicy(new DefaultRetryPolicy(Common.REQUEST_TIMEOUT_MS_MEDIUM, 1, 1f)); mConnectionDetails.getVolley().addToRequestQueue(request); } /** * List all xforms on the server, but not their contents. * @param listener a listener to be told about the index entries for all forms asynchronously. * @param errorListener a listener to be told about any errors. */ public void listXforms(final Response.Listener<List<OpenMrsXformIndexEntry>> listener, final Response.ErrorListener errorListener) { Request request = new OpenMrsJsonRequest(mConnectionDetails, "/xforms", // list all forms null, // null implies GET new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { LOG.i("got forms: " + response); ArrayList<OpenMrsXformIndexEntry> result = new ArrayList<>(); try { // This seems quite code heavy (parsing manually), but is reasonably // efficient as we only look at the fields we need, so we are robust to // changes in the rest of the object. JSONArray results = response.getJSONArray("results"); for (int i = 0; i < results.length(); i++) { JSONObject entry = results.getJSONObject(i); // Sometimes date_changed is not set; in this case, date_changed is // simply date_created. long dateChanged; if (entry.get("date_changed") == JSONObject.NULL) { dateChanged = entry.getLong("date_created"); } else { dateChanged = entry.getLong("date_changed"); } OpenMrsXformIndexEntry indexEntry = new OpenMrsXformIndexEntry( entry.getString("uuid"), entry.getString("name"), dateChanged); result.add(indexEntry); } } catch (JSONException e) { // The result was not in the expected format. Just log, and return // results so far. LOG.e(e, "response was in bad format: " + response); } LOG.i("returning response: " + response); listener.onResponse(result); } }, errorListener ); request.setRetryPolicy(new DefaultRetryPolicy(Common.REQUEST_TIMEOUT_MS_MEDIUM, 1, 1f)); mConnectionDetails.getVolley().addToRequestQueue(request); } /** * Send a single Xform to the OpenMRS server. * @param patientUuid null if this is to add a new patient, non-null for observation on existing * patient * @param resultListener the listener to be informed of the form asynchronously * @param errorListener a listener to be informed of any errors */ public void postXformInstance( @Nullable String patientUuid, String entererUuid, String xform, final Response.Listener<JSONObject> resultListener, Response.ErrorListener errorListener) { // The JsonObject members in the API as written at the moment. // int "patient_id" // int "enterer_id" // String "date_entered" in ISO8601 format (1977-01-10T // String "xml" the form. JsonObject post = new JsonObject(); post.addProperty("xml", xform); // Don't add patient property for create new patient if (patientUuid != null) { post.addProperty("patient_uuid", patientUuid); } post.addProperty("enterer_uuid", entererUuid); post.addProperty("date_entered", ISODateTimeFormat.dateTime().print(new DateTime())); JSONObject postBody = null; try { postBody = new JSONObject(post.toString()); } catch (JSONException e) { LOG.e(e, "This should never happen converting one JSON object to another. " + post); errorListener.onErrorResponse(new VolleyError("failed to convert to JSON", e)); } OpenMrsJsonRequest request = new OpenMrsJsonRequest( mConnectionDetails, "/xforminstances", postBody, // non-null implies POST new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { resultListener.onResponse(response); } }, errorListener ); // Set a permissive timeout. request.setRetryPolicy(new DefaultRetryPolicy(Common.REQUEST_TIMEOUT_MS_MEDIUM, 1, 1f)); mConnectionDetails.getVolley().addToRequestQueue(request); } }