/**
 * Copyright 2010 Red Hat, Inc. and/or its affiliates.
 * 
 * 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.
 */


package org.jbpm.process.workitem.rest;

import org.jbpm.process.workitem.AbstractLogOrThrowWorkItemHandler;
import java.util.ArrayList;
import org.apache.http.client.AuthCache;
import org.apache.http.auth.AuthScope;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.Consts;
import org.apache.http.entity.ContentType;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import java.util.HashMap;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpUriRequest;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import org.apache.http.NameValuePair;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.StatusLine;
import org.apache.http.entity.StringEntity;
import java.io.StringReader;
import org.drools.core.util.StringUtils;
import java.io.StringWriter;
import java.net.URI;
import java.nio.charset.UnsupportedCharsetException;
import java.io.UnsupportedEncodingException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemManager;

/**
 * WorkItemHandler that is capable of interacting with REST service. Supports both types of services
 * secured (that requires authentication) and open (no authentication). Authentication methods currently supported:
 * <ul>
 *  <li>BASIC</li>
 *  <li>FORM BASED</li>
 * </ul>
 * Authentication information can be given on handler initialization and can be overridden via work item parameters.
 * All other configuration options must be given via work item parameters map:
 * <ul>
 *  <li>Url - resource location to be invoked - mandatory</li>
 *  <li>Method - HTTP method that will be executed - defaults to GET</li>
 *  <li>ContentType - data type in case of sending data - mandatory for POST,PUT</li>
 *  <li>Content - actual data to be sent - mandatory for POST,PUT</li>
 *  <li>ConnectTimeout - connection time out - default to 60 seconds</li>
 *  <li>ReadTimeout - read time out - default to 60 seconds</li>
 *  <li>Username - user name for authentication - overrides one given on handler initialization)</li>
 *  <li>Password - password for authentication - overrides one given on handler initialization)</li>
 *  <li>AuthUrl - url that is handling authentication (usually j_security_check url)</li>
 *  <li>HandleResponseErrors - optional parameter that instructs handler to throw errors in case
 *  of non successful response codes (other than 2XX)</li>
 *  <li>ResultClass - fully qualified class name of the class that response should be transformed to,
 *  if not given string format will be returned</li>
 * </ul>
 */
public class RESTWorkItemHandler extends AbstractLogOrThrowWorkItemHandler {
    private static final Logger logger = LoggerFactory.getLogger(RESTWorkItemHandler.class);

    private String username;

    private String password;

    private RESTWorkItemHandler.AuthenticationType type;

    private String authUrl;

    private ClassLoader classLoader;

    // protected for test purpose
    protected static boolean HTTP_CLIENT_API_43 = true;

    static {
        try {
            Class.forName("org.apache.http.client.methods.RequestBuilder");
            HTTP_CLIENT_API_43 = true;
        } catch (ClassNotFoundException e) {
            HTTP_CLIENT_API_43 = false;
        }
    }

    /**
     * Used when no authentication is required
     */
    public RESTWorkItemHandler() {
        RESTWorkItemHandler.logger.debug(("REST work item handler will use http client 4.3 api " + (RESTWorkItemHandler.HTTP_CLIENT_API_43)));
        RESTWorkItemHandler.this.type = RESTWorkItemHandler.AuthenticationType.NONE;
        RESTWorkItemHandler.this.classLoader = RESTWorkItemHandler.this.getClass().getClassLoader();
    }

    /**
     * Dedicated constructor when BASIC authentication method shall be used
     * @param username - user name to be used for authentication
     * @param password - password to be used for authentication
     */
    public RESTWorkItemHandler(String username, String password) {
        this();
        RESTWorkItemHandler.this.username = username;
        RESTWorkItemHandler.this.password = password;
        RESTWorkItemHandler.this.type = RESTWorkItemHandler.AuthenticationType.BASIC;
        RESTWorkItemHandler.this.classLoader = RESTWorkItemHandler.this.getClass().getClassLoader();
    }

    /**
     * Dedicated constructor when FORM BASED authentication method shall be used
     * @param username - user name to be used for authentication
     * @param password - password to be used for authentication
     * @param authUrl
     */
    public RESTWorkItemHandler(String username, String password, String authUrl) {
        this();
        RESTWorkItemHandler.this.username = username;
        RESTWorkItemHandler.this.password = password;
        RESTWorkItemHandler.this.type = RESTWorkItemHandler.AuthenticationType.FORM_BASED;
        RESTWorkItemHandler.this.authUrl = authUrl;
        RESTWorkItemHandler.this.classLoader = RESTWorkItemHandler.this.getClass().getClassLoader();
    }

    /**
     * Used when no authentication is required
     */
    public RESTWorkItemHandler(ClassLoader classLoader) {
        RESTWorkItemHandler.logger.debug(("REST work item handler will use http client 4.3 api " + (RESTWorkItemHandler.HTTP_CLIENT_API_43)));
        RESTWorkItemHandler.this.type = RESTWorkItemHandler.AuthenticationType.NONE;
        RESTWorkItemHandler.this.classLoader = classLoader;
    }

    /**
     * Dedicated constructor when BASIC authentication method shall be used
     * @param username - user name to be used for authentication
     * @param password - password to be used for authentication
     */
    public RESTWorkItemHandler(String username, String password, ClassLoader classLoader) {
        this();
        RESTWorkItemHandler.this.username = username;
        RESTWorkItemHandler.this.password = password;
        RESTWorkItemHandler.this.type = RESTWorkItemHandler.AuthenticationType.BASIC;
        RESTWorkItemHandler.this.classLoader = classLoader;
    }

    /**
     * Dedicated constructor when FORM BASED authentication method shall be used
     * @param username - user name to be used for authentication
     * @param password - password to be used for authentication
     * @param authUrl
     */
    public RESTWorkItemHandler(String username, String password, String authUrl, ClassLoader classLoader) {
        this();
        RESTWorkItemHandler.this.username = username;
        RESTWorkItemHandler.this.password = password;
        RESTWorkItemHandler.this.type = RESTWorkItemHandler.AuthenticationType.FORM_BASED;
        RESTWorkItemHandler.this.authUrl = authUrl;
        RESTWorkItemHandler.this.classLoader = classLoader;
    }

    public String getAuthUrl() {
        return authUrl;
    }

    public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
        boolean handleException = false;
        // extract required parameters
        String urlStr = ((String) (workItem.getParameter("Url")));
        String method = ((String) (workItem.getParameter("Method")));
        String handleExceptionStr = ((String) (workItem.getParameter("HandleResponseErrors")));
        String resultClass = ((String) (workItem.getParameter("ResultClass")));
        if (urlStr == null) {
            throw new IllegalArgumentException("Url is a required parameter");
        } 
        if ((method == null) || ((method.trim().length()) == 0)) {
            method = "GET";
        } 
        if (handleExceptionStr != null) {
            handleException = Boolean.parseBoolean(handleExceptionStr);
        } 
        Map<String, Object> params = workItem.getParameters();
        // authentication type from parameters
        RESTWorkItemHandler.AuthenticationType authType = type;
        if ((params.get("AuthType")) != null) {
            authType = RESTWorkItemHandler.AuthenticationType.valueOf(((String) (params.get("AuthType"))));
        } 
        // optional timeout config parameters, defaulted to 60 seconds
        Integer connectTimeout = getParamAsInt(params.get("ConnectTimeout"));
        if (connectTimeout == null)
            connectTimeout = 60000;
        
        Integer readTimeout = getParamAsInt(params.get("ReadTimeout"));
        if (readTimeout == null)
            readTimeout = 60000;
        
        HttpClient httpClient = getHttpClient(readTimeout, connectTimeout);
        Object methodObject = configureRequest(method, urlStr, params);
        try {
            HttpResponse response = doRequestWithAuthorization(httpClient, methodObject, params, authType);
            StatusLine statusLine = response.getStatusLine();
            int responseCode = statusLine.getStatusCode();
            Map<String, Object> results = new HashMap<String, Object>();
            HttpEntity respEntity = response.getEntity();
            String responseBody = null;
            String contentType = null;
            if (respEntity != null) {
                responseBody = EntityUtils.toString(respEntity);
                if ((respEntity.getContentType()) != null) {
                    contentType = respEntity.getContentType().getValue();
                } 
            } 
            if ((responseCode >= 200) && (responseCode < 300)) {
                postProcessResult(responseBody, resultClass, contentType, results);
                results.put("StatusMsg", ((("request to endpoint " + urlStr) + " successfully completed ") + (statusLine.getReasonPhrase())));
            } else {
                if (handleException) {
                    handleException(new RESTServiceException(responseCode, responseBody, urlStr));
                } else {
                    RESTWorkItemHandler.logger.warn("Unsuccessful response from REST server (status: {}, endpoint: {}, response: {}", responseCode, urlStr, responseBody);
                    results.put("StatusMsg", ((("endpoint " + urlStr) + " could not be reached: ") + responseBody));
                }
            }
            results.put("Status", responseCode);
            // notify manager that work item has been completed
            manager.completeWorkItem(workItem.getId(), results);
        } catch (Exception e) {
            handleException(e);
        } finally {
            try {
                close(httpClient, methodObject);
            } catch (Exception e) {
                // no idea if this throws something, but we still don't care!
            }
        }
    }

    protected Integer getParamAsInt(Object param) {
        if (param == null) {
            return null;
        } 
        if ((param instanceof String) && (!(((String) (param)).isEmpty()))) {
            return Integer.parseInt(((String) (param)));
        } 
        if (param instanceof Number) {
            return ((Number) (param)).intValue();
        } 
        return null;
    }

    protected void setBody(RequestBuilder builder, Map<String, Object> params) {
        if (params.containsKey("Content")) {
            try {
                String contentType = ((String) (params.get("ContentType")));
                Object content = params.get("Content");
                if (!(content instanceof String)) {
                    content = transformRequest(content, contentType);
                } 
                StringEntity entity = new StringEntity(((String) (content)), ContentType.parse(contentType));
                builder.setEntity(entity);
            } catch (UnsupportedCharsetException e) {
                throw new RuntimeException(((("Cannot set body for REST request [" + (builder.getMethod())) + "] ") + (builder.getUri())), e);
            }
        } 
    }

    protected void setBody(HttpRequestBase theMethod, Map<String, Object> params) {
        if (params.containsKey("Content")) {
            Object content = params.get("Content");
            if (!(content instanceof String)) {
                content = transformRequest(content, ((String) (params.get("ContentType"))));
            } 
            ((HttpEntityEnclosingRequestBase) (theMethod)).setEntity(new StringEntity(((String) (content)), ContentType.parse(((String) (params.get("ContentType"))))));
        } 
    }

    protected void postProcessResult(String result, String resultClass, String contentType, Map<String, Object> results) {
        if ((!(StringUtils.isEmpty(resultClass))) && (!(StringUtils.isEmpty(contentType)))) {
            try {
                Class<?> clazz = Class.forName(resultClass, true, classLoader);
                Object resultObject = transformResult(clazz, contentType, result);
                results.put("Result", resultObject);
            } catch (Throwable e) {
                throw new RuntimeException("Unable to transform respose to object", e);
            }
        } else {
            results.put("Result", result);
        }
    }

    protected String transformRequest(Object data, String contentType) {
        try {
            if (contentType.toLowerCase().contains("application/json")) {
                ObjectMapper mapper = new ObjectMapper();
                return mapper.writeValueAsString(data);
            } else if (contentType.toLowerCase().contains("application/xml")) {
                StringWriter stringRep = new StringWriter();
                JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{ data.getClass() });
                jaxbContext.createMarshaller().marshal(data, stringRep);
                return stringRep.toString();
            } 
        } catch (Exception e) {
            throw new RuntimeException("Unable to transform request to object", e);
        }
        throw new IllegalArgumentException(((("Unable to find transformer for content type '" + contentType) + "' to handle data ") + data));
    }

    protected Object transformResult(Class<?> clazz, String contentType, String content) throws Exception {
        if (contentType.toLowerCase().contains("application/json")) {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.readValue(content, clazz);
        } else if (contentType.toLowerCase().contains("application/xml")) {
            StringReader result = new StringReader(content);
            JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{ clazz });
            return jaxbContext.createUnmarshaller().unmarshal(result);
        } 
        RESTWorkItemHandler.logger.warn("Unable to find transformer for content type '{}' to handle for content '{}'", contentType, content);
        // unknown content type, returning string representation
        return content;
    }

    protected HttpResponse doRequestWithAuthorization(HttpClient httpclient, Object method, Map<String, Object> params, RESTWorkItemHandler.AuthenticationType authType) {
        if (RESTWorkItemHandler.HTTP_CLIENT_API_43) {
            return doRequestWithAuthorization(httpclient, ((RequestBuilder) (method)), params, authType);
        } else {
            return doRequestWithAuthorization(httpclient, ((HttpRequestBase) (method)), params, authType);
        }
    }

    /**
     * This method does the actual request, including the setup for authorization.
     * </p>
     * It is <b>not</b> responsible for cleaning up after the last request that it does.
     * </p>
     * It <i>is</i> responsible for cleaning up after all previous request, such as for form-based authentication, that happen.
     * 
     * @param httpclient The {@link HttpClient} instance
     * @param requestBuilder The {@link RequestBuilder} instance
     * @param params The parameters that may be needed for authentication
     * @return A {@link HttpResponse} instance from which we can extract the content
     */
    protected HttpResponse doRequestWithAuthorization(HttpClient httpclient, RequestBuilder requestBuilder, Map<String, Object> params, RESTWorkItemHandler.AuthenticationType type) {
        // no authorization
        if ((type == null) || (type == (RESTWorkItemHandler.AuthenticationType.NONE))) {
            HttpUriRequest request = requestBuilder.build();
            try {
                return httpclient.execute(request);
            } catch (Exception e) {
                throw new RuntimeException(((("Could not execute request [" + (request.getMethod())) + "] ") + (request.getURI())), e);
            }
        } 
        // user/password
        String u = ((String) (params.get("Username")));
        String p = ((String) (params.get("Password")));
        if ((u == null) || (p == null)) {
            u = RESTWorkItemHandler.this.username;
            p = RESTWorkItemHandler.this.password;
        } 
        if (u == null) {
            throw new IllegalArgumentException("Could not find username");
        } 
        if (p == null) {
            throw new IllegalArgumentException("Could not find password");
        } 
        if (type == (RESTWorkItemHandler.AuthenticationType.BASIC)) {
            // basic auth
            URI requestUri = requestBuilder.getUri();
            HttpHost targetHost = new HttpHost(requestUri.getHost(), requestUri.getPort(), requestUri.getScheme());
            // Create AuthCache instance and add it: so that HttpClient thinks that it has already queried (as per the HTTP spec)
            // - generate BASIC scheme object and add it to the local auth cache
            AuthCache authCache = new org.apache.http.impl.client.BasicAuthCache();
            BasicScheme basicAuth = new BasicScheme();
            authCache.put(targetHost, basicAuth);
            // - add AuthCache to the execution context:
            HttpClientContext clientContext = HttpClientContext.create();
            CredentialsProvider credsProvider = new org.apache.http.impl.client.BasicCredentialsProvider();
            // specify host and port, since that is safer/more secure
            credsProvider.setCredentials(new AuthScope(requestUri.getHost(), requestUri.getPort(), AuthScope.ANY_REALM), new org.apache.http.auth.UsernamePasswordCredentials(u, p));
            clientContext.setCredentialsProvider(credsProvider);
            clientContext.setAuthCache(authCache);
            // - execute request
            HttpUriRequest request = requestBuilder.build();
            try {
                return httpclient.execute(targetHost, request, clientContext);
            } catch (Exception e) {
                throw new RuntimeException(((("Could not execute request with preemptive authentication [" + (request.getMethod())) + "] ") + (request.getURI())), e);
            }
        } else if (type == (RESTWorkItemHandler.AuthenticationType.FORM_BASED)) {
            // form auth
            // 1. do initial request to trigger authentication
            HttpUriRequest request = requestBuilder.build();
            int statusCode = -1;
            try {
                HttpResponse initialResponse = httpclient.execute(request);
                statusCode = initialResponse.getStatusLine().getStatusCode();
            } catch (IOException e) {
                throw new RuntimeException("Could not execute request for form-based authentication", e);
            } finally {
                // weird, but this is the method that releases resources, including the connection
                request.abort();
            }
            // 1b. form authentication requests should have a status of 401
            // See: www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2
            if (statusCode != (HttpStatus.SC_UNAUTHORIZED)) {
                RESTWorkItemHandler.logger.error("Expected form authentication request with status {} but status on response is {}: proceeding anyways", HttpStatus.SC_UNAUTHORIZED, statusCode);
            } 
            // 2. do POST form request to authentiate
            String authUrlStr = ((String) (params.get("AuthUrl")));
            if (authUrlStr == null) {
                authUrlStr = authUrl;
            } 
            if (authUrlStr == null) {
                throw new IllegalArgumentException("Could not find authentication url");
            } 
            HttpPost authMethod = new HttpPost(authUrlStr);
            List<NameValuePair> formParams = new ArrayList<NameValuePair>(2);
            formParams.add(new org.apache.http.message.BasicNameValuePair("j_username", u));
            formParams.add(new org.apache.http.message.BasicNameValuePair("j_password", p));
            UrlEncodedFormEntity formEntity;
            try {
                formEntity = new UrlEncodedFormEntity(formParams);
            } catch (UnsupportedEncodingException uee) {
                throw new RuntimeException("Could not encode authentication parameters into request body", uee);
            }
            authMethod.setEntity(formEntity);
            try {
                httpclient.execute(authMethod);
            } catch (IOException e) {
                throw new RuntimeException("Could not initialize form-based authentication", e);
            } finally {
                authMethod.releaseConnection();
            }
            // 3. rebuild request and execute
            request = requestBuilder.build();
            try {
                return httpclient.execute(request);
            } catch (Exception e) {
                throw new RuntimeException(((("Could not execute request [" + (request.getMethod())) + "] ") + (request.getURI())), e);
            }
        } else {
            throw new RuntimeException(("Unknown AuthenticationType " + type));
        }
    }

    protected HttpResponse doRequestWithAuthorization(HttpClient httpclient, HttpRequestBase httpMethod, Map<String, Object> params, RESTWorkItemHandler.AuthenticationType type) {
        if ((type == null) || (type == (RESTWorkItemHandler.AuthenticationType.NONE))) {
            try {
                return httpclient.execute(httpMethod);
            } catch (Exception e) {
                throw new RuntimeException(((("Could not execute request [" + (httpMethod.getMethod())) + "] ") + (httpMethod.getURI())), e);
            }
        } 
        String u = ((String) (params.get("Username")));
        String p = ((String) (params.get("Password")));
        if ((u == null) || (p == null)) {
            u = RESTWorkItemHandler.this.username;
            p = RESTWorkItemHandler.this.password;
        } 
        if (u == null) {
            throw new IllegalArgumentException("Could not find username");
        } 
        if (p == null) {
            throw new IllegalArgumentException("Could not find password");
        } 
        if (type == (RESTWorkItemHandler.AuthenticationType.BASIC)) {
            HttpHost targetHost = new HttpHost(httpMethod.getURI().getHost(), httpMethod.getURI().getPort(), httpMethod.getURI().getScheme());
            ((DefaultHttpClient) (httpclient)).getCredentialsProvider().setCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()), new org.apache.http.auth.UsernamePasswordCredentials(u, p));
            // Create AuthCache instance
            AuthCache authCache = new org.apache.http.impl.client.BasicAuthCache();
            // Generate BASIC scheme object and add it to the local
            // auth cache
            BasicScheme basicAuth = new BasicScheme();
            authCache.put(targetHost, basicAuth);
            // Add AuthCache to the execution context
            BasicHttpContext localcontext = new BasicHttpContext();
            localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
            try {
                return httpclient.execute(targetHost, httpMethod, localcontext);
            } catch (Exception e) {
                throw new RuntimeException(((("Could not execute request [" + (httpMethod.getMethod())) + "] ") + (httpMethod.getURI())), e);
            }
        } else if (type == (RESTWorkItemHandler.AuthenticationType.FORM_BASED)) {
            String authUrlStr = ((String) (params.get("AuthUrl")));
            if (authUrlStr == null) {
                authUrlStr = authUrl;
            } 
            if (authUrlStr == null) {
                throw new IllegalArgumentException("Could not find authentication url");
            } 
            try {
                httpclient.execute(httpMethod);
            } catch (IOException e) {
                throw new RuntimeException("Could not execute request for form-based authentication", e);
            } finally {
                httpMethod.releaseConnection();
            }
            HttpPost authMethod = new HttpPost(authUrlStr);
            List<NameValuePair> nvps = new ArrayList<NameValuePair>();
            nvps.add(new org.apache.http.message.BasicNameValuePair("j_username", u));
            nvps.add(new org.apache.http.message.BasicNameValuePair("j_password", p));
            authMethod.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
            try {
                httpclient.execute(authMethod);
            } catch (IOException e) {
                throw new RuntimeException("Could not initialize form-based authentication", e);
            } finally {
                authMethod.releaseConnection();
            }
            try {
                return httpclient.execute(httpMethod);
            } catch (Exception e) {
                throw new RuntimeException(((("Could not execute request [" + (httpMethod.getMethod())) + "] ") + (httpMethod.getURI())), e);
            }
        } else {
            throw new RuntimeException(("Unknown AuthenticationType " + type));
        }
    }

    public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {
        // Do nothing, this work item cannot be aborted
    }

    public enum AuthenticationType {
NONE, BASIC, FORM_BASED;    }

    protected HttpClient getHttpClient(Integer readTimeout, Integer connectTimeout) {
        if (RESTWorkItemHandler.HTTP_CLIENT_API_43) {
            RequestConfig config = RequestConfig.custom().setSocketTimeout(readTimeout).setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectTimeout).build();
            HttpClientBuilder clientBuilder = HttpClientBuilder.create().setDefaultRequestConfig(config);
            HttpClient httpClient = clientBuilder.build();
            return httpClient;
        } else {
            DefaultHttpClient httpClient = new DefaultHttpClient();
            httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, readTimeout);
            httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectTimeout);
            return httpClient;
        }
    }

    protected void close(HttpClient httpClient, Object httpMethod) throws IOException {
        if (RESTWorkItemHandler.HTTP_CLIENT_API_43) {
            ((CloseableHttpClient) (httpClient)).close();
        } else {
            ((HttpRequestBase) (httpMethod)).releaseConnection();
        }
    }

    protected Object configureRequest(String method, String urlStr, Map<String, Object> params) {
        if (RESTWorkItemHandler.HTTP_CLIENT_API_43) {
            RequestBuilder builder = null;
            if ("GET".equals(method)) {
                builder = RequestBuilder.get().setUri(urlStr);
            } else if ("POST".equals(method)) {
                builder = RequestBuilder.post().setUri(urlStr);
                setBody(builder, params);
            } else if ("PUT".equals(method)) {
                builder = RequestBuilder.put().setUri(urlStr);
                setBody(builder, params);
            } else if ("DELETE".equals(method)) {
                builder = RequestBuilder.delete().setUri(urlStr);
            } else {
                throw new IllegalArgumentException((("Method " + method) + " is not supported"));
            }
            return builder;
        } else {
            HttpRequestBase theMethod = null;
            if ("GET".equals(method)) {
                theMethod = new org.apache.http.client.methods.HttpGet(urlStr);
            } else if ("POST".equals(method)) {
                theMethod = new HttpPost(urlStr);
                setBody(theMethod, params);
            } else if ("PUT".equals(method)) {
                theMethod = new org.apache.http.client.methods.HttpPut(urlStr);
                setBody(theMethod, params);
            } else if ("DELETE".equals(method)) {
                theMethod = new org.apache.http.client.methods.HttpDelete(urlStr);
            } else {
                throw new IllegalArgumentException((("Method " + method) + " is not supported"));
            }
            return theMethod;
        }
    }
}

