com.sforce.cd.apexUnit.client.codeCoverage.WebServiceInvoker.java Source code

Java tutorial

Introduction

Here is the source code for com.sforce.cd.apexUnit.client.codeCoverage.WebServiceInvoker.java

Source

/* 
 * Copyright (c) 2016, salesforce.com, inc.
 * All rights reserved.
 * Licensed under the BSD 3-Clause license.
 * For full license text, see LICENSE.txt file in the repo root  or https://opensource.org/licenses/BSD-3-Clause
 */

/*
 * Class to invoke web services calls: get and post methods for the REST APIs using OAUTH
 * 
 * @author adarsh.ramakrishna@salesforce.com
 */

package com.sforce.cd.apexUnit.client.codeCoverage;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.sforce.cd.apexUnit.ApexUnitUtils;
import com.sforce.cd.apexUnit.arguments.CommandLineArguments;

import static java.net.URLEncoder.encode;

/*
 * WebServiceInvoker provides interfaces for get and post methods for the REST APIs using OAUTH
 */
public class WebServiceInvoker {
    private static Logger LOG = LoggerFactory.getLogger(WebServiceInvoker.class);

    /*
     * Utility to perform HTTP post operation on the orgUrl with the specific
     * sub-url as mentioned in the relativeServiceURL
     * 
     * @param relativeServiceURL - relative service url w.r.t org url for firing
     * post request
     * 
     * @return : hashmap with key-value pairs of response from the post query
     */
    public HashMap<String, String> doPost(String relativeServiceURL) {

        PostMethod post = null;
        HttpClient httpclient = new HttpClient();
        String requestString = "";
        HashMap<String, String> responseMap = new HashMap<String, String>();

        try {
            // the client id and secret is applicable across all dev orgs
            requestString = generateRequestString();
            String authorizationServerURL = CommandLineArguments.getOrgUrl() + relativeServiceURL;

            httpclient.getParams().setSoTimeout(0);
            post = new PostMethod(authorizationServerURL);
            post.addRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            post.addRequestHeader("X-PrettyPrint", "1");
            post.setRequestEntity(
                    new StringRequestEntity(requestString, "application/x-www-form-urlencoded", "UTF-8"));
            httpclient.executeMethod(post);

            Gson json = new Gson();
            // obtain the result map from the response body and get the access
            // token
            responseMap = json.fromJson(post.getResponseBodyAsString(), new TypeToken<HashMap<String, String>>() {
            }.getType());

        } catch (Exception ex) {
            ApexUnitUtils.shutDownWithDebugLog(ex, "Exception during post method: " + ex);
            if (LOG.isDebugEnabled()) {
                ex.printStackTrace();
            }
        } finally {
            post.releaseConnection();
        }

        return responseMap;

    }

    public String generateRequestString() {
        String requestString = "";
        try {
            requestString = "grant_type=password&client_id=" + CommandLineArguments.getClientId()
                    + "&client_secret=" + CommandLineArguments.getClientSecret() + "&username="
                    + CommandLineArguments.getUsername() + "&password="
                    + encode(CommandLineArguments.getPassword(), "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            ApexUnitUtils.shutDownWithDebugLog(ex, "Exception during request string generation: " + ex);
            if (LOG.isDebugEnabled()) {
                ex.printStackTrace();
            }
        }

        return requestString;
    }

    public static JSONObject doGet(String relativeServiceURL, String soql, String accessToken) {
        if (soql != null && !soql.equals("")) {
            try {
                relativeServiceURL += "/query/?q=" + encode(soql, "UTF-8");
            } catch (UnsupportedEncodingException e) {

                ApexUnitUtils.shutDownWithDebugLog(e,
                        "Error encountered while trying to encode the query string using UTF-8 format. The error says: "
                                + e.getMessage());
            }
        }
        return doGet(relativeServiceURL, accessToken);
    }

    /*
     * method to perform get operation using the access token for the org and
     * return the json response
     * 
     * @param relativeServiceURL - relative service url w.r.t org url for firing
     * post request
     * 
     * @param accessToken : access token for the org(generated in the post
     * method)
     * 
     * @return : json response from the get request
     */
    public static JSONObject doGet(String relativeServiceURL, String accessToken) {

        LOG.debug("relativeServiceURL in doGet method:" + relativeServiceURL);
        HttpClient httpclient = new HttpClient();
        GetMethod get = null;

        String authorizationServerURL = CommandLineArguments.getOrgUrl() + relativeServiceURL;
        get = new GetMethod(authorizationServerURL);
        get.addRequestHeader("Content-Type", "application/json");
        get.setRequestHeader("Authorization", "Bearer " + accessToken);
        LOG.debug("Start GET operation for the url..." + authorizationServerURL);
        InputStream instream = null;
        try {
            instream = executeHTTPMethod(httpclient, get, authorizationServerURL);
            LOG.debug("done with get operation");

            JSONObject json = (JSONObject) JSONValue.parse(new InputStreamReader(instream));
            LOG.debug("is json null? :" + json == null ? "true" : "false");
            if (json != null) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("ToolingApi.get response: " + json.toString());
                    Set<String> keys = castSet(String.class, json.keySet());
                    Iterator<String> jsonKeyIter = keys.iterator();
                    LOG.debug("Response for the GET method: ");
                    while (jsonKeyIter.hasNext()) {
                        String key = jsonKeyIter.next();
                        LOG.debug("key : " + key + ". Value :  " + json.get(key) + "\n");
                        // TODO if query results are too large, only 1st batch
                        // of results
                        // are returned. Need to use the identifier in an
                        // additional query
                        // to retrieve rest of the next batch of results

                        if (key.equals("nextRecordsUrl")) {
                            // fire query to the value for this key
                            // doGet((String) json.get(key), accessToken);
                            try {
                                authorizationServerURL = CommandLineArguments.getOrgUrl() + (String) json.get(key);
                                get.setURI(new URI(authorizationServerURL, false));
                                instream = executeHTTPMethod(httpclient, get, authorizationServerURL);
                                JSONObject newJson = (JSONObject) JSONValue.parse(new InputStreamReader(instream));
                                if (newJson != null) {
                                    Set<String> newKeys = castSet(String.class, json.keySet());
                                    Iterator<String> newJsonKeyIter = newKeys.iterator();
                                    while (newJsonKeyIter.hasNext()) {
                                        String newKey = newJsonKeyIter.next();
                                        json.put(newKey, newJson.get(newKey));
                                        LOG.debug("newkey : " + newKey + ". NewValue :  " + newJson.get(newKey)
                                                + "\n");
                                    }
                                }

                            } catch (URIException e) {
                                ApexUnitUtils.shutDownWithDebugLog(e,
                                        "URI exception while fetching subsequent batch of result");
                            }
                        }

                    }
                }
            }
            return json;
        } finally {
            get.releaseConnection();
            try {
                if (instream != null) {
                    instream.close();

                }
            } catch (IOException e) {
                ApexUnitUtils.shutDownWithDebugLog(e,
                        "Encountered IO exception when closing the stream after reading response from the get method. The error says: "
                                + e.getMessage());
            }
        }
    }

    /**
     * 
     * execute the HTTP Get method and return response as Input stream
     * 
     * @param httpclient
     *            HTTPClient
     * @param get
     *            GetMethod
     * @return
     * @throws IOException
     * @throws HttpException
     */

    private static InputStream executeHTTPMethod(HttpClient httpclient, GetMethod get,
            String authorizationServerURL) {
        try {
            httpclient.executeMethod(get);
        } catch (HttpException e) {
            ApexUnitUtils.shutDownWithDebugLog(e,
                    "Encountered HTTP exception when executing get method using OAuth authentication for the url "
                            + authorizationServerURL + ". The error says: " + e.getMessage());
        } catch (IOException e) {
            ApexUnitUtils.shutDownWithDebugLog(e,
                    "Encountered IO exception when executing get method using OAuth authentication for the url "
                            + authorizationServerURL + ". The error says: " + e.getMessage());
        }
        LOG.info("Status code : " + get.getStatusCode() + "   Status message from the get request:"
                + get.getStatusText() + " Reason phrase: " + get.getStatusLine().getReasonPhrase());

        InputStream instream = null;
        try {
            // don't delete the below line --i.e. getting response body as
            // string. Getting response as stream fails upon deleting the below
            // line! strange!
            String respStr;
            respStr = get.getResponseBodyAsString();
            instream = get.getResponseBodyAsStream();
        } catch (IOException e) {

            ApexUnitUtils.shutDownWithDebugLog(e,
                    "Encountered IO exception when obtaining response body for the get method. The error says: "
                            + e.getMessage());
        }
        return instream;
    }

    /*
     * Method to cast a collection of objects to a set of given type
     * 
     * @param clazz - class type of the collection
     * 
     * @param c - collection set
     * 
     * @return set - A set returned that is of the class 'clazz'
     */
    public static <T> Set<T> castSet(Class<? extends T> clazz, Collection<?> c) {
        Set<T> set = new HashSet<T>();
        for (Object o : c)
            set.add(clazz.cast(o));
        return set;
    }
}