package me.evis.mobile.noodle.product; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathFactory; import me.evis.mobile.noodle.R; import me.evis.mobile.util.DeviceUtil; import me.evis.mobile.util.XmlUtil; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import android.content.Context; import android.net.http.AndroidHttpClient; import android.os.AsyncTask; import android.util.Log; import com.amazon.advertising.api.sample.SignedRequestsHelper; public class QueryProductByEanTask extends AsyncTask<String, Void, ObjectResult<Product>> { private static final String TAG = "QueryApaapiByEanTask"; private Context context; private OnSuccessListener onSuccessListener; private OnFailureListener onFailureListener; public QueryProductByEanTask(Context context, OnSuccessListener onSuccessListener, OnFailureListener onFailureListener) { this.context = context; this.onSuccessListener = onSuccessListener; this.onFailureListener = onFailureListener; } @Override protected ObjectResult<Product> doInBackground(String... params) { if (!DeviceUtil.isOnline(context)) { return new ObjectResult<Product>(false, context.getString(R.string.error_no_network)); } if (context == null) { throw new IllegalStateException("Context in null"); } if (params.length < 1) { throw new IllegalStateException("No params"); } String ean = params[0]; SignedRequestsHelper helper; String endpoint = context.getString(R.string.amazon_aws_endpoint); String accessKey = context.getString(R.string.amazon_aws_access_key_id); String secretKey = context.getString(R.string.amazon_aws_secret_key); String associateTag = context.getString(R.string.amazon_associate_tag); try { helper = SignedRequestsHelper.getInstance(endpoint, accessKey, secretKey); } catch (Exception e) { Log.e(TAG, "Error creating signer", e); return null; } String requestUrl = null; Map<String, String> serviceParams = new HashMap<String, String>(); serviceParams.put("Service", "AWSECommerceService"); serviceParams.put("Version", "2011-08-01"); serviceParams.put("AssociateTag", associateTag); serviceParams.put("Operation", "ItemLookup"); serviceParams.put("SearchIndex", "All"); serviceParams.put("IdType", "EAN"); serviceParams.put("ItemId", ean); // Temporarily removed product description to shrink the response size //serviceParams.put("ResponseGroup", "ItemAttributes,EditorialReview,Images"); serviceParams.put("ResponseGroup", "ItemAttributes"); requestUrl = helper.sign(serviceParams); Log.d(TAG, "Signed Request is \"" + requestUrl + "\""); AndroidHttpClient client = AndroidHttpClient.newInstance("Android", context); HttpGet request = new HttpGet(requestUrl); HttpResponse response = null; ObjectResult<Product> result = null; try { response = client.execute(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { String resultStr = "HTTP " + response.getStatusLine().getStatusCode() + ": " + response.getStatusLine().getReasonPhrase(); Log.d(TAG, resultStr); // Handle specific errors switch (response.getStatusLine().getStatusCode()) { case HttpStatus.SC_SERVICE_UNAVAILABLE: resultStr = context.getString(R.string.error_service_error); break; case HttpStatus.SC_FORBIDDEN: resultStr = context.getString(R.string.error_need_upgrade); break; default: break; } result = new ObjectResult<Product>(false, resultStr); } else { Document doc = null; InputStream is = response.getEntity().getContent(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); doc = db.parse(is); NodeList errors = doc.getElementsByTagName("Error"); XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); if (errors.getLength() > 0) { String resultStr = "Service Error: " + errors.item(0).getTextContent(); Log.d(TAG, resultStr); // Handle specific errors String code = XmlUtil.getXPathItemText(doc, xpath, "//Error/Code/text()"); if ("AWS.InvalidParameterValue".equals(code)) { resultStr = context.getString(R.string.error_barcode_not_found); } else if ("AWS.InternalError".equals(code)) { resultStr = context.getString(R.string.error_service_error); } else if ("AWS.InvalidAccount".equals(code)) { resultStr = context.getString(R.string.error_need_upgrade); } else if ("RequestThrottled".equals(code)) { resultStr = context.getString(R.string.error_service_error); } result = new ObjectResult<Product>(false, resultStr); } else { NodeList itemNodes = doc.getElementsByTagName("Item"); if (itemNodes.getLength() > 0) { Product product = new Product(); product.setProductId(XmlUtil.getXPathItemText(doc, xpath, "//Item/ASIN/text()")); product.setName(XmlUtil.getXPathItemText(doc, xpath, "//Item/ItemAttributes/Title/text()")); product.setManufacturer(XmlUtil.getXPathItemText(doc, xpath, "//Item/ItemAttributes/Manufacturer/text()")); product.setImageUrl(XmlUtil.getXPathItemText(doc, xpath, "//Item/MediumImage/URL/text()")); product.setBuyUrl(XmlUtil.getXPathItemText(doc, xpath, "//Item/DetailPageURL/text()")); String brandOrAuthor = XmlUtil.getXPathItemText(doc, xpath, "//Item/ItemAttributes/Author/text()"); if (brandOrAuthor == null) { brandOrAuthor = XmlUtil.getXPathItemText(doc, xpath, "//Item/ItemAttributes/Brand/text()"); } product.setBrand(brandOrAuthor); // Temporarily removed product description to shrink the response size //product.setDescription(XmlUtil.getXPathItemText(doc, xpath, "//Item/EditorialReviews/EditorialReview/Content/text()")); result = new ObjectResult<Product>(true, null, product); } else { Log.d(TAG, "Items are empty"); result = new ObjectResult<Product>(false, "Items are empty"); } } } } catch (ClientProtocolException e) { Log.e(TAG, "Http protocol error", e); result = new ObjectResult<Product>(false, "Error response"); } catch (IOException e) { Log.e(TAG, "Error when requesting URL: \"" + requestUrl + "\" or parsing HTTP response", e); result = new ObjectResult<Product>(false, "Error requesting or parsing HTTP response"); } catch (Exception e) { Log.e(TAG, "Error parsing HTTP response", e); result = new ObjectResult<Product>(false, "Error parsing HTTP response"); } finally { // Close the connection if (client != null && client.getConnectionManager() != null) { client.close(); client = null; } } return result; } @Override protected void onPostExecute(ObjectResult<Product> result) { super.onPostExecute(result); if (result.isSuccess() && onSuccessListener != null) { onSuccessListener.onSuccess(result.getResult()); } if (!result.isSuccess() && onFailureListener != null) { onFailureListener.onFailure(result.getMessage()); } } public interface OnSuccessListener { public void onSuccess(Product product); } public interface OnFailureListener { public void onFailure(String failure); } }