package org.openintents.wifiserver.requesthandler.shoppinglist; import static android.provider.BaseColumns._ID; import java.io.UnsupportedEncodingException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.entity.AbstractHttpEntity; import org.apache.http.entity.StringEntity; import org.apache.http.protocol.HttpContext; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.openintents.shopping.library.provider.ShoppingContract.ContainsFull; import org.openintents.shopping.library.provider.ShoppingContract.Items; import org.openintents.wifiserver.util.URLUtil; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.util.Log; /** * Handler which is used to retrieve all or a specific item. It handles requests of the form "/shoppinglist/list/get". * * @author Stanley Förster * */ public class GetItem extends ShoppinglistHandler { private static final String[] PROJECTION_ITEMS = new String[] { Items._ID, Items.NAME, Items.PRICE, Items.UNITS, Items.TAGS }; private static final String[] PROJECTION_CONTAINS = new String[] { ContainsFull.ITEM_ID, ContainsFull.ITEM_NAME, ContainsFull.ITEM_PRICE, ContainsFull.ITEM_UNITS, ContainsFull.ITEM_TAGS, ContainsFull.LIST_ID, ContainsFull.PRIORITY, ContainsFull.QUANTITY, ContainsFull.STATUS }; /** * Creates a new request handler. * * @param context The application's context to access the necessary content providers. */ public GetItem(Context context) { super(context); } /** * <p> * {@inheritDoc} * </p> * * This method deletes an item. The required HTTP method is GET. * * To specify a special item, the <code>id</code> and <code>list</code> parameters can be used: * <ul> * <li><code>id</code> specifies the item, that should be returned.</li> * <li><code>list</code> specifies the list, that contains the item.</li> * </ul> * If no parameter is given, all items will be returned. If only the <code>list</code> parameter is present, all items of this list will be returned. * * <p> * Status Codes: * <ul> * <li>405: if HTTP method is not GET</li> * <li>501: if OI Shoppinglist app is not installed on the device.</li> * <li>500: if something went wrong during response creation.</li> * </ul> * </p> */ @Override public void getResponse(HttpRequest request, HttpResponse response, HttpContext context) { if (!"GET".equals(request.getRequestLine().getMethod())) { response.setStatusCode(405); return; } String id = URLUtil.getParameter(request.getRequestLine().getUri(), "id"); String list = URLUtil.getParameter(request.getRequestLine().getUri(), "list"); Cursor cursor = null; Object jsonResult = null; try { if (id == null && list == null) { cursor = query(Items.CONTENT_URI, PROJECTION_ITEMS, null, null, null); jsonResult = itemsToJSONArray(cursor); } if (id == null && list != null) { cursor = query(ContainsFull.CONTENT_URI, PROJECTION_CONTAINS, ContainsFull.LIST_ID + " = ?", new String[] { list }, null); jsonResult = containsToJSONArray(cursor); } if (id != null && list != null) { cursor = query(ContainsFull.CONTENT_URI, PROJECTION_CONTAINS, ContainsFull.LIST_ID + " = ? AND " + ContainsFull.ITEM_ID + " = ?", new String[] { list, id }, null); if (cursor.getCount() == 0) { response.setStatusCode(404); return; } jsonResult = containsToJSONObject(cursor); } if (id != null && list == null) { cursor = query(Items.CONTENT_URI, PROJECTION_ITEMS, _ID+" = ?", new String[] { id }, null); if (cursor.getCount() == 0) { response.setStatusCode(404); return; } jsonResult = itemToJSONObject(cursor); } AbstractHttpEntity entity = new StringEntity(jsonResult.toString()); entity.setContentType("application/json"); response.setEntity(entity); } catch (UnsupportedEncodingException e) { Log.e(TAG, "Failed to create entity!", e); response.setStatusCode(500); } catch (JSONException e) { Log.e(TAG, "Failed to create JSON Object", e); response.setStatusCode(500); } catch (UnsupportedOperationException e) { Log.e(TAG, e.getMessage(), e); response.setStatusCode(501); } finally { if (cursor != null) cursor.close(); } } /** * <p> * Wrapper for the {@link ContentResolver#query(Uri, String[], * String, String[], String)} method which throws an exception if the * necessary URI is not available. * This behavior simplifies the handling of all the different cases much * easier. * </p> * <p> * For parameter and return value definition see * {@link ContentResolver#query(Uri, String[], String, * String[], String)}. * </p> * * @return The cursor that is returned by {@link ContentResolver#query(Uri, String[], String, String[], String)} * * @see Cursor * @see ContentResolver#query(Uri, String[], String, String[], String) */ private Cursor query(Uri contentUri, String[] projectionItems, String selection, String[] selectionArgs, String sortOrder) { Cursor result = mContext.getContentResolver().query(contentUri, projectionItems, selection, selectionArgs, sortOrder); if (result == null) throw new UnsupportedOperationException("No content provider available for URI "+contentUri.toString()); return result; } /** * Creates a JSON object which contains all the given parameters. * * @param id {@link Items#_ID} * @param name {@link Items#NAME} * @param price {@link Items#PRICE} * @param units {@link Items#UNITS} * @param tags {@link Items#TAGS} * * @return A JSONObject, containing all the parameters. * * @throws JSONException */ protected JSONObject itemToJSONObject(long id, String name, long price, String units, String tags) throws JSONException { JSONObject json = new JSONObject(); json.put(Items._ID, id); json.put(Items.NAME, name); json.put(Items.PRICE, price); json.put(Items.UNITS, units); json.put(Items.TAGS, tags); return json; } /** * Creates a JSON Object which contains the following attributes: * <ul> * <li>{@link Items#_ID}</li> * <li>{@link Items#NAME}</li> * <li>{@link Items#PRICE}</li> * <li>{@link Items#UNITS}</li> * <li>{@link Items#TAGS}</li> * </ul> * * @return * @throws JSONException */ protected JSONObject itemToJSONObject(Cursor itemCursor) throws JSONException { return itemToJSONObject(itemCursor.getLong( itemCursor.getColumnIndex(Items._ID)), itemCursor.getString(itemCursor.getColumnIndex(Items.NAME)), itemCursor.getLong( itemCursor.getColumnIndex(Items.PRICE)), itemCursor.getString(itemCursor.getColumnIndex(Items.UNITS)), itemCursor.getString(itemCursor.getColumnIndex(Items.TAGS)) ); } protected JSONArray itemsToJSONArray(Cursor itemsCursor) throws JSONException { JSONArray array = new JSONArray(); if (itemsCursor.moveToFirst()) do { array.put(itemToJSONObject(itemsCursor)); } while (itemsCursor.moveToNext()); return array; } protected JSONObject containsToJSONObject(long item_id, String item_name, long item_price, String item_units, String item_tags, long priority, long status, String quantity) throws JSONException { JSONObject json = new JSONObject(); json.put(ContainsFull.ITEM_ID, item_id); json.put(ContainsFull.ITEM_NAME, item_name); json.put(ContainsFull.ITEM_PRICE, item_price); json.put(ContainsFull.ITEM_TAGS, item_tags); json.put(ContainsFull.ITEM_UNITS, item_units); json.put(ContainsFull.PRIORITY, priority); json.put(ContainsFull.STATUS, status); json.put(ContainsFull.QUANTITY, quantity); return json; } protected JSONObject containsToJSONObject(Cursor containsCursor) throws JSONException { return containsToJSONObject(containsCursor.getLong( containsCursor.getColumnIndex(ContainsFull.ITEM_ID)), containsCursor.getString(containsCursor.getColumnIndex(ContainsFull.ITEM_NAME)), containsCursor.getLong( containsCursor.getColumnIndex(ContainsFull.ITEM_PRICE)), containsCursor.getString(containsCursor.getColumnIndex(ContainsFull.ITEM_UNITS)), containsCursor.getString(containsCursor.getColumnIndex(ContainsFull.ITEM_TAGS)), containsCursor.getLong( containsCursor.getColumnIndex(ContainsFull.PRIORITY)), containsCursor.getLong( containsCursor.getColumnIndex(ContainsFull.STATUS)), containsCursor.getString(containsCursor.getColumnIndex(ContainsFull.QUANTITY)) ); } protected JSONArray containsToJSONArray(Cursor containsCursor) throws JSONException { JSONArray array = new JSONArray(); if (containsCursor.moveToFirst()) do { array.put(containsToJSONObject(containsCursor)); } while (containsCursor.moveToNext()); return array; } }