com.betfair.testing.utils.cougar.helpers.CougarHelpers.java Source code

Java tutorial

Introduction

Here is the source code for com.betfair.testing.utils.cougar.helpers.CougarHelpers.java

Source

/*
 * Copyright 2013, The Sporting Exchange Limited
 * Copyright 2014, Simon Mati Langford
 *
 * 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 com.betfair.testing.utils.cougar.helpers;

import com.betfair.testing.utils.cougar.beans.BatchedRequestBean;
import com.betfair.testing.utils.cougar.beans.HttpCallBean;
import com.betfair.testing.utils.cougar.beans.HttpResponseBean;
import com.betfair.testing.utils.cougar.daos.CougarDefaultDAO;
import com.betfair.testing.utils.cougar.daos.ICougarDAO;
import com.betfair.testing.utils.cougar.enums.CougarMessageContentTypeEnum;
import com.betfair.testing.utils.cougar.enums.CougarMessageProtocolRequestTypeEnum;
import com.betfair.testing.utils.cougar.misc.IReflect;
import com.betfair.testing.utils.cougar.misc.Reflect;
import com.betfair.testing.utils.cougar.misc.XMLHelpers;
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.xerces.dom.DocumentImpl;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.management.Attribute;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.TabularData;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CougarHelpers {

    private static final Logger logger = LoggerFactory.getLogger(CougarHelpers.class);
    private ICougarDAO cougarDAO = new CougarDefaultDAO();

    private IReflect reflect = new Reflect();

    private static final String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress";

    private static final String SOAP_CALL_TEXT = "Make Cougar SOAP Call : ";
    private static final String JMX_SETTING_ERROR = "Problem setting JMX attribute: ";
    private static final String JMX_RETRIEVAL_ERROR = "Problem retrieving JMX attribute value: ";
    private static final String JMX_INVOKE_ERROR = "Problem invoking JMX operation: ";
    private static final String JSON_CONTENT = "application/json";
    private static final String XML_CONTENT = "application/xml";

    private static final String UTF8 = "utf-8";

    // Map of operation names to paths (where different)
    // TODO Would be better to generate this automatically
    private static final Map<String, String> OPERATION_PATHS = new HashMap<String, String>() {
        {
            put("testSimpleMapGet", "simpleMapGet");
            put("testSimpleListGet", "simpleListGet");
            put("testSimpleSetGet", "simpleSetGet");
            put("testSimpleGet", "simple");
            put("testSimpleCacheGet", "cache");
            put("testLargeGet", "largeGet");
            put("testLargeMapGet", "map");
            put("testMapsNameClash", "map1");
            put("testGetTimeout", "simple/timeout");
            put("testParameterStyles", "styles");
            put("testDateRetrieval", "dates");
            put("testDoubleHandling", "doubles");
            put("testListRetrieval", "primitiveLists");
            put("testComplexMutator", "complex");
            put("testLargePost", "largePost");
            put("testException", "exception");
            put("testSecureService", "secure");
            put("testSimpleTypeReplacement", "simpletypes");
            put("testStringableLists", "simpleLists");
            put("testBodyParams", "multibody");
            put("testNoParams", "noparams");
            put("testDirectMapReturn", "direct/map");
            put("testDirectListReturn", "direct/list");
            put("boolSimpleTypeEcho", "boolEcho");
            put("byteSimpleTypeEcho", "byteEcho");
            put("i32SimpleTypeEcho", "i32Echo");
            put("i64SimpleTypeEcho", "i64Echo");
            put("floatSimpleTypeEcho", "floatEcho");
            put("doubleSimpleTypeEcho", "doubleEcho");
            put("stringSimpleTypeEcho", "stringEcho");
            put("dateTimeSimpleTypeEcho", "dateTimeEcho");
            put("i32ListSimpleTypeEcho", "i32ListEcho");
            put("i32SetSimpleTypeEcho", "i32SetEcho");
            put("i32MapSimpleTypeEcho", "i32MapEcho");
            put("testIdentityChain", "identityChain");
            put("getDetailedHealthStatus", "detailed");
            put("isHealthy", "summary");
        }
    };

    private JMXConnector jmxc = null;

    /*
     * Send a request to a locally running Cougar container via SOAP as per the
     * passed parameters.
     *
     * @param message
     * @param serviceName
     * @param version
     * @param httpBean
     * @return
     */
    public HttpResponseBean makeCougarSOAPCall(SOAPMessage message, String serviceName, String version,
            HttpCallBean httpBean) {
        try {

            //Debugging code
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            message.writeTo(outStream);
            SOAPConnectionFactory connectionFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection connection = connectionFactory.createConnection();

            // this can either be a SOAPException or SOAPMessage
            HttpResponseBean responseBean = new HttpResponseBean();
            Object response;

            String host = httpBean.getHost();
            String port = httpBean.getPort();

            String endPoint = "http://" + host + ":" + port + "/" + serviceName + "Service/" + version;

            try {

                response = connection.call(message, endPoint);

            } catch (SOAPException e) {
                response = e;
            } finally {
                connection.close();
            }

            responseBean.setResponseObject(handleResponse(response, responseBean));

            return responseBean;

        } catch (SOAPException | IOException | ParserConfigurationException | TransformerException e) {
            throw new RuntimeException(SOAP_CALL_TEXT + e, e);
        }

    }

    /*
     * Handle the response of the SOAP call
     *
     * @param response
     * @return
     * @throws SOAPException
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws TransformerException
     */
    private Object handleResponse(Object response, HttpResponseBean responseBean)
            throws SOAPException, IOException, ParserConfigurationException, TransformerException {

        Class<?> clazz = response.getClass();

        if (clazz.getName().equalsIgnoreCase("com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl")
                || clazz.getName().equalsIgnoreCase("com.sun.xml.messaging.saaj.soap.ver1_1.Message1_1Impl")) {

            return handleSoapResponse((SOAPMessage) response, responseBean);
        } else { // else assume that an exception has been thrown
            return response;
        }

    }

    /*
     * ???
     *
     * @param response
     * @param responseBean
     * @throws DOMException
     * @throws SOAPException
     */
    private void extractHeaderDataSOAP(SOAPMessage response, HttpResponseBean responseBean) throws SOAPException {
        //extract MimeHeaders
        MimeHeaders mime = response.getMimeHeaders();
        Iterator<MimeHeader> iter = mime.getAllHeaders();

        while (iter.hasNext()) {
            MimeHeader mimeH = iter.next();
            responseBean.addEntryToResponseHeaders(mimeH.getName(), mimeH.getValue());

        }

        //extract SOAPHeaders from the envelope and a them to the mimeHeaders
        if (response.getSOAPHeader() != null) {
            javax.xml.soap.SOAPHeader header = response.getSOAPHeader();

            NodeList nodes = header.getChildNodes();

            for (int x = 0; x < nodes.getLength(); x++) {
                //if the header entry contains child nodes - write them with the node names
                if (nodes.item(x).hasChildNodes()) {
                    NodeList childnodes = nodes.item(x).getChildNodes();
                    for (int y = 0; y < childnodes.getLength(); y++) {
                        responseBean.addEntryToResponseHeaders(nodes.item(x).getLocalName(),
                                childnodes.item(y).getLocalName() + ":" + childnodes.item(y).getTextContent());
                    }
                } else {
                    responseBean.addEntryToResponseHeaders(nodes.item(x).getLocalName(),
                            nodes.item(x).getTextContent());
                }
            }
        }
    }

    /*
     * ???
     *
     * @param response
     * @param responseBean
     * @return
     * @throws TransformerException
     * @throws SOAPException
     * @throws ParserConfigurationException
     */
    private Document handleSoapResponse(SOAPMessage response, HttpResponseBean responseBean)
            throws TransformerException, SOAPException, ParserConfigurationException {

        Node responseNode = null;

        if (response != null) {
            responseNode = extractResponseNode(response);
            extractHeaderDataSOAP(response, responseBean);
        }

        // build new xml document for assertion
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document newDocument = builder.newDocument();

        Node adoptedBlob = newDocument.importNode(responseNode, true);
        newDocument.appendChild(adoptedBlob);

        // Output as String if required
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        transformer.transform(new DOMSource(newDocument), new StreamResult(out));

        if (logger.isDebugEnabled()) {
            logger.debug("\n Return Doc \n");
            logger.debug(new String(out.toByteArray()));
        }

        return newDocument;
    }

    public Node extractResponseNode(SOAPMessage response) throws SOAPException {

        Node responseNode;

        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        try {
            response.writeTo(outStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //      logger.LogBetfairDebugEntry("SOAP Response: " + outStream.toString());

        if (response.getSOAPBody().hasFault()) {
            responseNode = response.getSOAPBody().getFault();
        } else if (response.getSOAPBody().getFirstChild() == null) { // Response type is void
            responseNode = response.getSOAPBody();
        } else {
            // extract the body
            SOAPBody respBody = response.getSOAPBody();
            // First child should be the service name object
            Node serviceResponseNode = respBody.getFirstChild();

            // second child
            responseNode = serviceResponseNode.getFirstChild();
        }

        return responseNode;
    }

    /*
     * Create and return a HttpMethodBase for a Rest request based on the passed
     * HttpCallBean and CougarMessageProtocolRequestTypeEnum.
     *
     * @param httpCallBean
     * @param protocolRequestType
     * @return
     */
    public HttpUriRequest getRestMethod(HttpCallBean httpCallBean,
            CougarMessageProtocolRequestTypeEnum protocolRequestType) {

        Object postQueryObject = httpCallBean.getPostQueryObjectsByEnum(protocolRequestType);
        String postQuery;

        if (postQueryObject == null) {
            postQuery = null;
        } else {
            postQuery = (String) postQueryObject;
        }

        String serviceExtension = httpCallBean.getServiceExtension();
        String version = httpCallBean.getVersion();
        Map<String, String> queryParams = httpCallBean.getQueryParams();

        String host = httpCallBean.getHost();
        String port = httpCallBean.getPort();
        String path = httpCallBean.getPath();
        String altURL = httpCallBean.getAlternativeURL(); // Will be "" for standard URL, or "/www" for alternative URL
        boolean batchedQuery = httpCallBean.getJSONRPC();
        String fullPath = httpCallBean.getFullPath();

        String methodURL = "";

        if (batchedQuery) { // If request is a batched JSON request set the URL to the appropriate baseline URL
            postQuery = createBatchedPostString(httpCallBean.getBatchedRequests()); // Build the post string out of the list of requests to batch
            methodURL = "http://" + host + ":" + port + "/json-rpc";
        } else { // else build the request URL

            String queryParamString = "";
            if (queryParams != null) {
                int counter = 0;
                StringBuilder queryBuff = new StringBuilder();
                for (Map.Entry<String, String> entry : queryParams.entrySet()) {
                    String value = entry.getValue();
                    String key = entry.getKey();
                    if (counter == 0) {
                        String firstQuery = "?" + key + "=" + value;
                        queryBuff.append(firstQuery);
                    } else {
                        String nextQuery = "&" + key + "=" + value;
                        queryBuff.append(nextQuery);
                    }
                    counter++;
                }
                queryParamString = queryBuff.toString();
            }

            if (fullPath != null) {
                methodURL = "http://" + host + ":" + port + fullPath + queryParamString;
            } else {
                methodURL = "http://" + host + ":" + port + altURL + "/" + serviceExtension + "/" + version + "/"
                        + path + queryParamString;
            }
        }

        //        if (logger.isDebugEnabled()) {
        //        }

        if ((postQuery != null) && (!postQuery.equalsIgnoreCase(""))) {
            HttpPost method = new HttpPost(methodURL);
            try {
                method.setEntity(new StringEntity(postQuery, null, UTF8));
                return method;
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        } else {
            return new HttpGet(methodURL);
        }
    }

    private String createBatchedPostString(List<BatchedRequestBean> requests) {

        StringBuilder postQuery = new StringBuilder();
        postQuery.append("[");

        for (BatchedRequestBean entry : requests) { // build each request String and add to post string
            //if version not set - default to "2.0", if service not set - default to "Baseline"
            String version = entry.getVersion();
            String service = entry.getService();
            String method = entry.getMethod();
            String params = entry.getParams();
            String id = entry.getId();
            postQuery.append("{ \"jsonrpc\": \"").append(version).append("\", \"method\": \"").append(service)
                    .append("/v").append(version).append("/").append(method).append("\", \"params\": ")
                    .append(params).append(", \"id\": ").append(id).append("}");
            postQuery.append(",");
        }

        postQuery.deleteCharAt(postQuery.length() - 1); // Remove last comma
        postQuery.append("]");

        return postQuery.toString();
    }

    /**
     * Send a request to a locally running Cougar container via REST as per the
     * passed parameters.
     */
    public HttpResponseBean makeRestCougarHTTPCall(HttpCallBean httpCallBean, HttpUriRequest method,
            CougarMessageProtocolRequestTypeEnum protocolRequestType,
            CougarMessageContentTypeEnum responseContentTypeEnum,
            CougarMessageContentTypeEnum requestContentTypeEnum) {

        Map<String, String> headerParams = httpCallBean.getHeaderParams();
        String authority = httpCallBean.getAuthority();
        Map<String, String> authCredentials = httpCallBean.getAuthCredentials();
        Map<String, String> acceptProtocols = httpCallBean.getAcceptProtocols();
        String ipAddress = httpCallBean.getIpAddress();
        String altUrl = httpCallBean.getAlternativeURL();

        Object postQueryObject = httpCallBean.getPostQueryObjectsByEnum(protocolRequestType);
        String postQuery;
        if (postQueryObject == null) {
            postQuery = null;
        } else {
            postQuery = (String) postQueryObject;
        }

        InputStream inputStream = null;
        try {
            completeRestMethodBuild(method, responseContentTypeEnum, requestContentTypeEnum, postQuery,
                    headerParams, authority, authCredentials, altUrl, acceptProtocols, ipAddress);

            if (logger.isDebugEnabled()) {
                logger.debug("Request");
                logger.debug("=======");
                logger.debug("URI: '" + method.getURI() + "'");
                Header[] headers = method.getAllHeaders();
                for (Header h : headers) {
                    logger.debug("Header: '" + h.getName() + " = " + h.getValue() + "'");
                }
                logger.debug("Body:    '" + postQuery + "'");
            }

            Date requestTime = new Date();
            final HttpResponse httpResponse = cougarDAO.executeHttpMethodBaseCall(method);
            inputStream = httpResponse.getEntity().getContent();

            String response = buildResponseString(inputStream);

            if (logger.isDebugEnabled()) {
                logger.debug("Response");
                logger.debug("========");
                logger.debug(String.valueOf(httpResponse.getStatusLine()));
                Header[] headers = httpResponse.getAllHeaders();
                for (Header h : headers) {
                    logger.debug("Header: '" + h.getName() + " = " + h.getValue() + "'");
                }
                logger.debug("Body:    '" + response + "'");
            }

            Date responseTime = new Date();

            return buildHttpResponseBean(httpResponse, response, requestTime, responseTime);

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    /*ignore*/}
            }
        }
    }

    private String buildResponseString(InputStream is) throws IOException {

        List<Integer> bytes = new ArrayList<Integer>();
        int read;
        while ((read = is.read()) != -1) {
            bytes.add(read);
        }

        byte[] buffer = new byte[bytes.size()];
        for (int i = 0; i < bytes.size(); i++) {
            buffer[i] = bytes.get(i).byteValue();
        }

        return new String(buffer, "UTF-8");
    }

    public void setCougarDAO(ICougarDAO cougarDAO) {
        this.cougarDAO = cougarDAO;
    }

    public static void main(String[] args) {
        CougarHelpers ch = new CougarHelpers();
        ch.setJMXConnectionFactory();
    }

    /*
     * Find the VM instance running Cougar based on COUGARVMNAME1 and COUGARVMNAME2
     * fields, and attach, setting the JmxConnector to be used by other methods.
     *
     */
    private void setJMXConnectionFactory() {

        String id = null;
        List<VirtualMachineDescriptor> vms = VirtualMachine.list();
        Boolean foundVM = false;

        for (VirtualMachineDescriptor vmd : vms) {

            String vmName = cleanCommandLineArgs(vmd.displayName());

            id = vmd.id();
            JMXConnector jmxConnector = null;
            try {
                jmxConnector = createJMXConnector(id);
            } catch (Exception e) {//Do Nothing move onto next vm
                continue;
            }
            try {
                if (!makeServerConnection(jmxConnector)) {
                    continue;
                }
            } catch (Exception e) {//Do Nothing move onto next vm
                continue;
            }

            //No exceptions thrown so we have our cougar vm
            jmxc = jmxConnector;
            foundVM = true;
            break;
        }
        if (!foundVM) {
            throw new RuntimeException("Unable to find cougar VM");
        }
    }

    /*
     * Clean any command line args from a vm display name before comparing it with expected values
     */
    private String cleanCommandLineArgs(String vmName) {

        vmName = vmName.replaceAll("\"", ""); // Strip any quotes from the name (needed for running on Jenkins server)

        StringBuffer buff = new StringBuffer(vmName);
        int argIndex = -1;

        while ((argIndex = buff.indexOf("-D")) != -1) { // While there's a command line argument in the string

            int argEnd = -1;

            if ((argEnd = buff.indexOf(" ", argIndex)) == -1) { // If this argument is at the end of the display name then clean to the end rather than to next white space
                argEnd = buff.length();
            }

            buff.replace(argIndex - 1, argEnd, ""); // remove contents of buffer between space before arg starts and the next white space/end of buffer
        }

        return buff.toString();
    }

    public JMXConnector createJMXConnector(String id)
            throws IOException, AgentLoadException, AgentInitializationException, AttachNotSupportedException {

        // attach to the target application
        VirtualMachine vm = VirtualMachine.attach(id);

        // get the connector address
        String connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);

        // no connector address, so we start the JMX agent
        if (connectorAddress == null) {
            String agent = vm.getSystemProperties().getProperty("java.home") + File.separator + "lib"
                    + File.separator + "management-agent.jar";
            vm.loadAgent(agent);

            // agent is started, get the connector address
            connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
        }

        // establish connection to connector server
        JMXServiceURL url = new JMXServiceURL(connectorAddress);
        return JMXConnectorFactory.connect(url);
    }

    public boolean makeServerConnection(JMXConnector jmxConnector)
            throws IOException, MBeanException, AttributeNotFoundException, InstanceNotFoundException,
            ReflectionException, MalformedObjectNameException {

        MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
        Set<ObjectName> mbeans = mBeanServerConnection.queryNames(new ObjectName("CoUGAR:name=healthChecker,*"),
                null);
        if (!mbeans.isEmpty()) {
            mBeanServerConnection.getAttribute(mbeans.iterator().next(), "SystemInService");
            return true;
        }
        return false;
    }

    /*
     * Produce an alphabetically ordered array of the method names of a given class
     */
    private String[] getOrderedMethodNamesFromClass(String classPath) throws ClassNotFoundException {

        Class baseline = Class.forName(classPath);
        Method[] methods = baseline.getDeclaredMethods();

        String[] methodNames = new String[methods.length];
        for (int i = 0; i < methods.length; i++) {
            methodNames[i] = methods[i].getName();
        }
        Arrays.sort(methodNames);

        return methodNames;
    }

    /*
     * Get the path of a given operation (either from the map of paths or itself)
     */
    private String getPath(String name) {

        if (OPERATION_PATHS.containsKey(name)) { // If operation path is different to name then get it
            return OPERATION_PATHS.get(name);
        }
        return name; // Else return original name
    }

    private MBeanServerConnection getJMXConnection() {

        try {
            if (jmxc == null) {
                setJMXConnectionFactory();
            }
            return jmxc.getMBeanServerConnection();
        } catch (IOException e) {
            throw new RuntimeException("Problem connecting to cougar JMX", e);
        }
    }

    private void setJMXMBeanAttribute(String mBeanName, String attributeName, Object newMbeanValue) {

        try {
            MBeanServerConnection mBeanServerConnection = getJMXConnection();
            ObjectName mbeanName = new ObjectName(mBeanName);
            Object currentAttributeValue = mBeanServerConnection.getAttribute(mbeanName, attributeName);
            Object reflectedValue = reflect.getRealProperty(currentAttributeValue.getClass(), newMbeanValue);
            Attribute attribute = new Attribute(attributeName, reflectedValue);
            mBeanServerConnection.setAttribute(mbeanName, attribute);
        } catch (Exception e) {
            throw new RuntimeException(JMX_SETTING_ERROR + mBeanName + ": " + attributeName, e);
        }
    }

    public void setJMXFaultControllerAttribute(String attributeName, String value) {
        String mBeanName = "CoUGAR:name=faultController";
        setJMXMBeanAttribute(mBeanName, attributeName, value);
    }

    private HttpResponseBean buildHttpResponseBean(HttpResponse httpResponse, String response, Date requestTime,
            Date responseTime) {

        HttpResponseBean httpResponseBean = new HttpResponseBean();

        Header[] headersArray = httpResponse.getAllHeaders();
        Map<String, String[]> headersMap = new HashMap<>();
        for (Header header : headersArray) {
            String[] headerAttributes = header.toString().split(": ");
            headersMap.put(headerAttributes[0], new String[] { headerAttributes[1].replace("\r\n", "") });
        }
        httpResponseBean.setResponseHeaders(headersMap);

        httpResponseBean.setHttpStatusCode(httpResponse.getStatusLine().getStatusCode());
        httpResponseBean.setHttpStatusText(httpResponse.getStatusLine().getReasonPhrase());

        httpResponseBean.setRequestTime(new Timestamp(requestTime.getTime()));
        httpResponseBean.setResponseTime(new Timestamp(responseTime.getTime()));

        if ((response != null) && (!response.equalsIgnoreCase(""))) {
            httpResponseBean.setResponseObject(response);
        } else {
            httpResponseBean.setResponseObject(null);
        }

        return httpResponseBean;
    }

    private void completeRestMethodBuild(HttpUriRequest method,
            CougarMessageContentTypeEnum responseContentTypeEnum,
            CougarMessageContentTypeEnum requestContentTypeEnum, String postQuery, Map<String, String> headerParams,
            String authority, Map<String, String> authCredentials, String altUrl,
            Map<String, String> acceptProtocols, String ipAddress) {

        String contentType = selectContent(requestContentTypeEnum);
        if (!"".equals(contentType)) {
            method.setHeader("Content-Type", contentType);
        }

        method.setHeader("User-Agent", "java/socket");

        String accept = selectAccept(responseContentTypeEnum, acceptProtocols);
        method.setHeader("Accept", accept);

        // No need to set this header any more as it is set by the new http client version
        /*if ((postQuery != null) && (!postQuery.equalsIgnoreCase(""))) {
           Integer contentLength = postQuery.length();
           method.setHeader("Content-Length", contentLength.toString());
        }*/

        if (headerParams != null) {
            for (Map.Entry<String, String> entry : headerParams.entrySet()) {
                String headerParamValue = entry.getValue();
                String key = entry.getKey();
                method.setHeader(key, headerParamValue);
                //      logger.LogBetfairDebugEntry("Rest request header param added: '"
                //                  + key + ":" + headerParamValue + "'");
            }
        }

        if (authority != null) {
            method.setHeader("X-Authentication", authority);
        }
        if (authCredentials != null) {
            if ("".equals(altUrl)) {
                method.setHeader("X-Token-Username", authCredentials.get("Username"));
                method.setHeader("X-Token-Password", authCredentials.get("Password"));
            } else {
                method.setHeader("X-AltToken-Username", authCredentials.get("Username"));
                method.setHeader("X-AltToken-Password", authCredentials.get("Password"));
            }

        }

        if (ipAddress == null) {
            method.setHeader("X-Forwarded-For", null);
        } else if (!ipAddress.trim().equalsIgnoreCase("DO NOT INCLUDE")) {
            method.setHeader("X-Forwarded-For", ipAddress);
        }

        //logger.LogBetfairDebugEntry("Rest request postString: '"
        //      + postQuery + "'");
    }

    private String selectContent(CougarMessageContentTypeEnum requestContentTypeEnum) {
        switch (requestContentTypeEnum) {
        case JSON:
            //      logger.LogBetfairDebugEntry("Rest request Content-Type: "+ JSON_CONTENT);
            return JSON_CONTENT;
        case XML:
            //      logger.LogBetfairDebugEntry("Rest request Content-Type: "+ XML_CONTENT);
            return XML_CONTENT;
        case OTHER:
            //DO NOTHING
            return "";
        default:
            throw new RuntimeException(
                    "Unsupported request message content type supplied: " + requestContentTypeEnum.toString());
        }
    }

    private String selectAccept(CougarMessageContentTypeEnum responseContentTypeEnum,
            Map<String, String> acceptProtocols) {
        if (responseContentTypeEnum == null) {
            int loopCounter = 0;
            StringBuffer acceptBuff = new StringBuffer();
            for (Map.Entry<String, String> entry : acceptProtocols.entrySet()) {
                String ranking = entry.getValue();
                String protocol = entry.getKey();
                if (loopCounter == 0) {
                    if ((ranking != null) && (!ranking.equalsIgnoreCase(""))) {
                        String firstProtocolWithRanking = protocol + ";" + ranking;
                        acceptBuff.append(firstProtocolWithRanking);
                    } else {
                        acceptBuff.append(protocol);
                    }

                } else {
                    String nextProtocolWithRanking = "," + protocol + ";" + ranking;
                    acceptBuff.append(nextProtocolWithRanking);
                    //         logger.LogBetfairDebugEntry("Rest request Accept protocol: "+acceptBuff.toString());
                }
                loopCounter++;
            }
            return acceptBuff.toString();
        } else {
            switch (responseContentTypeEnum) {
            case JSON:
                //         logger.LogBetfairDebugEntry("Rest request Accept protocol: "
                //                     + JSON_CONTENT);
                return JSON_CONTENT;
            case XML:
                //         logger.LogBetfairDebugEntry("Rest request Accept protocol: "
                //                     + XML_CONTENT);
                return XML_CONTENT;
            default:
                throw new RuntimeException("Unsupported response message content type supplied: "
                        + responseContentTypeEnum.toString());
            }
        }
    }

    public void setJMXMBeanAttributeValue(String mBeanName, String attributeName, Object value) {

        try {
            MBeanServerConnection mBeanServerConnection = getJMXConnection();
            ObjectName mbeanName = new ObjectName(mBeanName);
            Attribute attr = new Attribute(attributeName, value);
            mBeanServerConnection.setAttribute(mbeanName, attr);

        } catch (Exception e) {
            throw new RuntimeException(JMX_RETRIEVAL_ERROR + mBeanName + ": " + attributeName, e);
        }
    }

    public void setSOAPSchemaValidationEnabled(boolean validationEnabled) {
        setJMXMBeanAttributeValue("com.betfair.cougar.transport:type=soapCommandProcessor",
                "SchemaValidationEnabled", validationEnabled);
    }

    private Object getJMXMBeanAttributeValue(String mBeanName, String attributeName) {

        try {
            MBeanServerConnection mBeanServerConnection = getJMXConnection();
            ObjectName mbeanName = new ObjectName(mBeanName);
            return mBeanServerConnection.getAttribute(mbeanName, attributeName);

        } catch (Exception e) {
            throw new RuntimeException(JMX_RETRIEVAL_ERROR + mBeanName + ": " + attributeName, e);
        }
    }

    private Object invokeJMXMBeanOperation(String mBeanName, String operationName, Object[] params,
            String[] signature) {

        try {
            MBeanServerConnection mBeanServerConnection = getJMXConnection();
            return mBeanServerConnection.invoke(new ObjectName(mBeanName), operationName, params, signature);

        } catch (Exception e) {
            throw new RuntimeException(JMX_INVOKE_ERROR + mBeanName + ": " + operationName + " with arguments : "
                    + Arrays.toString(params), e);
        }
    }

    public String getJMXLoggingManagerAttributeValue(String attributeName) {
        String mBeanName = "CoUGAR:name=Logging";
        return getJMXMBeanAttributeValue(mBeanName, attributeName).toString();
    }

    public String getJMXApplicationPropertyValue(String key) {
        String mBeanName = "CoUGAR:name=ApplicationProperties";
        return (String) invokeJMXMBeanOperation(mBeanName, "getProperty", new Object[] { key },
                new String[] { "java.lang.String" });
    }

    public String getJMXSystemPropertyValue(String propertyName) {
        TabularData sysProps = (TabularData) getJMXMBeanAttributeValue("java.lang:type=Runtime",
                "SystemProperties");
        return (String) sysProps.get(new String[] { "user.dir" }).get("value");

    }

    public String getRuntimeAttributeValue(String attributeName) {
        String mBeanName = "java.lang:type=Runtime";
        return getJMXMBeanAttributeValue(mBeanName, attributeName).toString();
    }

    public String getJMXAttributeValue(String mBeanName, String attributeName) {
        return getJMXMBeanAttributeValue(mBeanName, attributeName).toString();
    }

    /**
     * Returns the system Java version string in the format usable for User-Agent field
     * in cougar log
     * @return String
     */
    public String getJavaVersion() {
        String s = "";
        Pattern myPattern = Pattern.compile("(.*?)\\-");
        Matcher m = myPattern.matcher(System.getProperty("java.runtime.version"));
        while (m.find()) {
            s = m.group(1);
        }
        return "\"Java/" + s + "\"";

    }

    public Map<String, String> convertFaultObjectToMap(HttpResponseBean soapResp) {

        DocumentImpl doc = (DocumentImpl) soapResp.getResponseObject();

        String actualFaultCode = doc.getElementsByTagName("faultcode").item(0).getFirstChild().getNodeValue();
        String actualFaultString = doc.getElementsByTagName("faultstring").item(0).getFirstChild().getNodeValue();
        String actualMessage = doc.getElementsByTagName("message").item(0).getFirstChild().getNodeValue();
        Node actualTraceNode = doc.getElementsByTagName("trace").item(0).getFirstChild();
        String actualTrace = "";
        if (actualTraceNode != null) {
            actualTrace = actualTraceNode.getNodeValue();

            actualTrace = actualTrace.replace("\r", ""); // Clean string of escaped characters (to avoid errors on Linux CI build)
            actualTrace = actualTrace.trim();
        }

        Map<String, String> responseMap = new HashMap<String, String>();
        responseMap.put("faultCode", actualFaultCode);
        responseMap.put("faultString", actualFaultString);
        responseMap.put("faultMessage", actualMessage);
        responseMap.put("faultTrace", actualTrace);

        return responseMap;
    }

    // Method to convert batched JSON response to a map for comparison (as the order of the array of responses cannot be relied upon)
    public Map<String, Object> convertBatchedResponseToMap(HttpResponseBean batchedResponse) throws JSONException {

        JSONObject json = (JSONObject) batchedResponse.getResponseObject();
        JSONArray results = null;
        try {
            results = (JSONArray) json.get("response");
        } catch (JSONException je) {
            logger.debug(String.valueOf(json), je);
            throw je;
        }

        Map<String, Object> responseMap = new HashMap<String, Object>();

        for (int i = 0; i < results.length(); i++) {
            JSONObject jsonObject = results.getJSONObject(i);
            responseMap.put("response" + jsonObject.get("id"), jsonObject.toString());
        }

        responseMap.put("httpStatusCode", batchedResponse.getHttpStatusCode() + "");
        responseMap.put("httpStatusText", batchedResponse.getHttpStatusText());
        responseMap.put("requestTime", batchedResponse.getRequestTime());
        responseMap.put("responseTime", batchedResponse.getResponseTime());

        return responseMap;
    }

    public Date convertToSystemTimeZone(String datetoconvert) {
        TimeZone tz = TimeZone.getDefault();
        Date date = new Date();
        try {
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
            String s = datetoconvert;
            String[] tmp = s.split(".0Z");
            String s1 = tmp[0];
            logger.debug("given string is" + s1);
            date = dateFormat.parse(s1);
            logger.debug("OffsetValue is " + tz.getRawOffset());
            if (tz.getRawOffset() != 0)

                date = new Date(date.getTime() + tz.getRawOffset());
            logger.debug("After adding offset" + date);
            if (tz.inDaylightTime(date)) {
                Date dstDate = new Date(date.getTime() + tz.getDSTSavings());
                logger.debug("Day Light Saving is  " + tz.getDSTSavings());
                logger.debug("Dst is   " + dstDate);

                if (tz.inDaylightTime(dstDate)) {
                    date = dstDate;
                    //            logger.debug("dst date  "+ dstDate);
                }
            }
            logger.debug("After the day light saving" + date);

        } catch (Exception e) {
            logger.debug("System exception caught" + e);
        }
        return date;
    }

    public String dateInUTC(Date date) {
        if (date == null) {
            return "null";
        }
        return date.toGMTString().replace("GMT", "UTC");
    }
}