com.dongwookchung.nutritioncalculator.FatSecretAPI.java Source code

Java tutorial

Introduction

Here is the source code for com.dongwookchung.nutritioncalculator.FatSecretAPI.java

Source

package com.dongwookchung.nutritioncalculator;

/*
 * Copyright (C) 2014 Saurabh Rane
 *
 * 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.
 */

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.json.JSONObject;

/**
 * This class helps in calling requests to FatSecret REST API to search food items and recipes.
 *
 * @author Saurabh Rane
 * @version 2014-07-30
 */

public class FatSecretAPI {

    /**
     * A value FatSecret API issues to you which helps this API identify you
     */
    final private String APP_KEY;

    /**
     * A secret FatSecret API issues to you which helps this API establish that it really is you
     */
    final private String APP_SECRET;

    /**
     * Request URL
     * <p>
     * The URL to make API calls is http://platform.fatsecret.com/rest/server.api
     */
    final private String APP_URL = "http://platform.fatsecret.com/rest/server.api";

    /**
     * The signature method allowed by FatSecret API
     * <p>
     * They only support "HMAC-SHA1"
     */
    final private String APP_SIGNATURE_METHOD = "HmacSHA1";

    /**
     * The HTTP Method supported by FatSecret API
     * <p>
     * This API only supports GET method
     */
    final private String HTTP_METHOD = "GET";

    /**
     * Constructor to set values for APP_KEY and APP_SECRET
     *
     * @param APP_KEY
     *         A value FatSecret API issues to you which helps this API identify you
     * @param APP_SECRET
     *         A secret FatSecret API issues to you which helps this API establish that it really is you
     */
    public FatSecretAPI(String APP_KEY, String APP_SECRET) {
        this.APP_KEY = APP_KEY;
        this.APP_SECRET = APP_SECRET;
    }

    /**
     * Returns randomly generated nonce value for calling the request.
     *
     * @return the randomly generated value for nonce.
     */
    public String nonce() {
        Random r = new Random();
        StringBuffer n = new StringBuffer();
        for (int i = 0; i < r.nextInt(8) + 2; i++) {
            n.append(r.nextInt(26) + 'a');
        }
        return n.toString();
    }

    /**
     * Get all the oauth parameters and other parameters.
     *
     * @return an array of parameter values as "key=value" pair
     */
    public String[] generateOauthParams() {
        String[] a = { "oauth_consumer_key=" + APP_KEY, "oauth_signature_method=HMAC-SHA1",
                "oauth_timestamp=" + new Long(System.currentTimeMillis() / 1000).toString(),
                "oauth_nonce=" + nonce(), "oauth_version=1.0", "format=json" };
        return a;
    }

    /**
     * Returns string generated using params and separator
     *
     * @param params
     *          An array of parameter values as "key=value" pair
     * @param separator
     *          A separator for joining
     *
     * @return the string by appending separator after each parameter from params except the last.
     */
    public String join(String[] params, String separator) {
        StringBuffer b = new StringBuffer();
        for (int i = 0; i < params.length; i++) {
            if (i > 0) {
                b.append(separator);
            }
            b.append(params[i]);
        }
        return b.toString();
    }

    /**
     * Returns string generated using params and "&" for signature base and normalized parameters
     *
     * @param params
     *          An array of parameter values as "key=value" pair
     *
     * @return the string by appending separator after each parameter from params except the last.
     */
    public String paramify(String[] params) {
        String[] p = Arrays.copyOf(params, params.length);
        Arrays.sort(p);
        return join(p, "&");
    }

    /**
     * Returns the percent-encoded string for the given url
     *
     * @param url
     *          URL which is to be encoded using percent-encoding
     *
     * @return encoded url
     */
    public String encode(String url) {
        if (url == null)
            return "";

        try {
            return URLEncoder.encode(url, "utf-8").replace("+", "%20").replace("!", "%21").replace("*", "%2A")
                    .replace("\\", "%27").replace("(", "%28").replace(")", "%29");
        } catch (UnsupportedEncodingException wow) {
            throw new RuntimeException(wow.getMessage(), wow);
        }
    }

    /**
     * Returns signature generated using signature base as text and consumer secret as key
     *
     * @param method
     *          Http method
     * @param uri
     *          Request URL - http://platform.fatsecret.com/rest/server.api (Always remains the same)
     * @param params
     *          An array of parameter values as "key=value" pair
     *
     * @return oauth_signature which will be added to request for calling fatsecret api
     */
    public String sign(String method, String uri, String[] params) throws UnsupportedEncodingException {

        String encodedURI = encode(uri);
        String encodedParams = encode(paramify(params));

        String[] p = { method, encodedURI, encodedParams };

        String text = join(p, "&");
        String key = APP_SECRET + "&";
        SecretKey sk = new SecretKeySpec(key.getBytes(), APP_SIGNATURE_METHOD);
        String sign = "";
        try {
            Mac m = Mac.getInstance(APP_SIGNATURE_METHOD);
            m.init(sk);
            sign = encode(new String(Base64.encode(m.doFinal(text.getBytes()), Base64.DEFAULT)).trim());
        } catch (java.security.NoSuchAlgorithmException e) {

        } catch (java.security.InvalidKeyException e) {

        }
        return sign;
    }

    /**
     * Returns JSONObject associated with the food items depending on the search query
     *
     * @param query
     *          Search terms for querying fatsecret api
     *
     * @return food items at page number '0' based on the query
     */
    public JSONObject getFoodItemID(String query) throws UnsupportedEncodingException {
        JSONObject result = new JSONObject();

        List<String> params = new ArrayList<String>(Arrays.asList(generateOauthParams()));
        String[] template = new String[1];
        params.add("method=foods.search");
        params.add("max_results=2");
        params.add("search_expression=" + encode(query));
        params.add("oauth_signature=" + sign(HTTP_METHOD, APP_URL, params.toArray(template)));

        try {
            URL url = new URL(APP_URL + "?" + paramify(params.toArray(template)));
            URLConnection api = url.openConnection();
            String line;
            StringBuilder builder = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(api.getInputStream()));

            while ((line = reader.readLine()) != null)
                builder.append(line);

            JSONObject json = new JSONObject(builder.toString());

            result.put("result", json);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    public JSONObject getFoodItemIDs(String query) throws UnsupportedEncodingException {
        JSONObject result = new JSONObject();

        List<String> params = new ArrayList<String>(Arrays.asList(generateOauthParams()));
        String[] template = new String[1];
        params.add("method=foods.search");
        params.add("max_results=20");
        params.add("search_expression=" + encode(query));
        params.add("oauth_signature=" + sign(HTTP_METHOD, APP_URL, params.toArray(template)));

        try {
            URL url = new URL(APP_URL + "?" + paramify(params.toArray(template)));
            URLConnection api = url.openConnection();
            String line;
            StringBuilder builder = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(api.getInputStream()));

            while ((line = reader.readLine()) != null)
                builder.append(line);

            JSONObject json = new JSONObject(builder.toString());

            result.put("result", json);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * Returns JSONObject associated with the food items depending on the search query and page number
     *
     * @param query
     *          Search terms for querying fatsecret api
     * @param pageNumber
     *          Page Number to search the food items
     *
     * @return food items at a particular page number based on the query
     */
    public JSONObject getFoodItemsAtPageNumber(String query, int pageNumber) throws UnsupportedEncodingException {
        JSONObject result = new JSONObject();

        List<String> params = new ArrayList<String>(Arrays.asList(generateOauthParams()));
        String[] template = new String[1];
        params.add("method=foods.search");
        params.add("max_results=20");
        params.add("page_number=" + pageNumber);
        params.add("search_expression=" + encode(query));
        params.add("oauth_signature=" + sign(HTTP_METHOD, APP_URL, params.toArray(template)));

        try {
            URL url = new URL(APP_URL + "?" + paramify(params.toArray(template)));
            URLConnection api = url.openConnection();
            String line;
            StringBuilder builder = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(api.getInputStream()));

            while ((line = reader.readLine()) != null)
                builder.append(line);

            JSONObject json = new JSONObject(builder.toString());

            result.put("result", json);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * Returns JSONObject associated with the food id with nutritional information
     *
     * @param id
     *          The ID of the food to retrieve.
     *
     * @return food items based on the food id
     */
    public JSONObject getFoodItem(long id) throws UnsupportedEncodingException {
        JSONObject result = new JSONObject();

        List<String> params = new ArrayList<String>(Arrays.asList(generateOauthParams()));
        String[] template = new String[1];
        params.add("method=food.get");
        params.add("max_results=20");
        params.add("food_id=" + encode("" + id));
        params.add("oauth_signature=" + sign(HTTP_METHOD, APP_URL, params.toArray(template)));

        try {
            URL url = new URL(APP_URL + "?" + paramify(params.toArray(template)));
            URLConnection api = url.openConnection();
            String line;
            StringBuilder builder = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(api.getInputStream()));

            while ((line = reader.readLine()) != null)
                builder.append(line);

            JSONObject json = new JSONObject(builder.toString());

            result.put("result", json);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * Returns JSONObject associated with the recipes depending on the search query
     *
     * @param query
     *          Search terms for querying fatsecret api
     *
     * @return recipes at page number '0' based on the query
     */
    public JSONObject getRecipes(String query) throws UnsupportedEncodingException {
        JSONObject result = new JSONObject();
        List<String> params = new ArrayList<String>(Arrays.asList(generateOauthParams()));
        String[] template = new String[1];
        params.add("method=recipes.search");
        params.add("max_results=50");
        params.add("search_expression=" + encode(query));
        params.add("oauth_signature=" + sign(HTTP_METHOD, APP_URL, params.toArray(template)));

        try {
            URL url = new URL(APP_URL + "?" + paramify(params.toArray(template)));
            URLConnection api = url.openConnection();
            String line;
            StringBuilder builder = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(api.getInputStream()));

            while ((line = reader.readLine()) != null)
                builder.append(line);

            JSONObject json = new JSONObject(builder.toString());
            result.put("result", json);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * Returns JSONObject associated with the recipes depending on the search query
     *
     * @param query
     *          Search terms for querying fatsecret api
     * @param pageNumber
     *          Page Number to search the food items
     *
     * @return recipes at a particular page number based on the query
     */
    public JSONObject getRecipesAtPageNumber(String query, int pageNumber) throws UnsupportedEncodingException {
        JSONObject result = new JSONObject();
        List<String> params = new ArrayList<String>(Arrays.asList(generateOauthParams()));
        String[] template = new String[1];
        params.add("method=recipes.search");
        params.add("max_results=50");
        params.add("page_number=" + pageNumber);
        params.add("search_expression=" + encode(query));
        params.add("oauth_signature=" + sign(HTTP_METHOD, APP_URL, params.toArray(template)));

        try {
            URL url = new URL(APP_URL + "?" + paramify(params.toArray(template)));
            URLConnection api = url.openConnection();
            String line;
            StringBuilder builder = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(api.getInputStream()));

            while ((line = reader.readLine()) != null)
                builder.append(line);

            JSONObject json = new JSONObject(builder.toString());
            result.put("result", json);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * Returns JSONObject associated with general information about the recipe item with detailed nutritional information for the standard serving.
     *
     * @param id
     *          The ID of the recipe to retrieve.
     *
     * @return recipe based on the recipe id
     */
    public JSONObject getRecipe(long id) throws UnsupportedEncodingException {
        JSONObject result = new JSONObject();

        List<String> params = new ArrayList<String>(Arrays.asList(generateOauthParams()));
        String[] template = new String[1];
        params.add("method=recipe.get");
        params.add("recipe_id=" + encode("" + id));
        params.add("oauth_signature=" + sign(HTTP_METHOD, APP_URL, params.toArray(template)));

        try {
            URL url = new URL(APP_URL + "?" + paramify(params.toArray(template)));
            URLConnection api = url.openConnection();
            String line;
            StringBuilder builder = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(api.getInputStream()));

            while ((line = reader.readLine()) != null)
                builder.append(line);

            JSONObject json = new JSONObject(builder.toString());

            result.put("result", json);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}