/*
*Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
*WSO2 Inc. licenses this file to you 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.wso2.am.integration.test.utils.generic;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.wso2.am.admin.clients.endpoint.EndPointAdminClient;
import org.wso2.am.admin.clients.localentry.LocalEntriesAdminClient;
import org.wso2.am.admin.clients.mediation.MessageProcessorClient;
import org.wso2.am.admin.clients.mediation.PriorityMediationAdminClient;
import org.wso2.am.admin.clients.rest.api.RestApiAdminClient;
import org.wso2.am.admin.clients.sequences.SequenceAdminServiceClient;
import org.wso2.am.admin.clients.tasks.TaskAdminClient;
import org.wso2.am.admin.clients.template.EndpointTemplateAdminServiceClient;
import org.wso2.am.admin.clients.template.SequenceTemplateAdminServiceClient;
import org.wso2.am.integration.clients.publisher.api.v1.dto.APIInfoDTO;
import org.wso2.am.integration.clients.publisher.api.v1.dto.APIListDTO;
import org.wso2.am.integration.test.utils.APIManagerIntegrationTestException;
import org.wso2.am.integration.test.utils.bean.APIBean;
import org.wso2.carbon.apimgt.api.model.APIIdentifier;
import org.wso2.carbon.automation.test.utils.http.client.HttpResponse;
import org.wso2.carbon.endpoint.stub.types.EndpointAdminEndpointAdminException;
import org.wso2.carbon.localentry.stub.types.LocalEntryAdminException;
import org.wso2.carbon.rest.api.stub.RestApiAdminAPIException;
import org.wso2.carbon.sequences.stub.types.SequenceEditorException;
import org.wso2.carbon.task.stub.TaskManagementException;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.xpath.XPathExpressionException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.rmi.RemoteException;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.Signature;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import static org.testng.Assert.assertTrue;

public class APIMTestCaseUtils {

    private static final Log log = LogFactory.getLog(APIMTestCaseUtils.class);
    private static int SERVICE_DEPLOYMENT_DELAY = TestConfigurationProvider.getServiceDeploymentDelay();
    private static final String PROXY = "proxy";
    private static final String LOCAL_ENTRY = "localEntry";
    private static final String ENDPOINT = "endpoint";
    private static final String SEQUENCE = "sequence";
    private static final String MESSAGE_STORE = "messageStore";
    private static final String MESSAGE_PROCESSOR = "messageProcessor";
    private static final String TEMPLATE = "template";
    private static final String API = "api";
    private static final String PRIORITY_EXECUTOR = "priorityExecutor";
    private static final String KEY = "key";
    private static final String NAME = "name";
    private static final String VERSION = "version";

    /**
     * Loads the specified resource from the classpath and returns its content as an OMElement.
     *
     * @param path A relative path to the resource file
     * @return An OMElement containing the resource content
     */
    public static OMElement loadResource(String path) throws FileNotFoundException, XMLStreamException {
        OMElement documentElement = null;
        FileInputStream inputStream = null;
        XMLStreamReader parser = null;
        StAXOMBuilder builder = null;
        path = TestConfigurationProvider.getResourceLocation() + path;
        File file = new File(path);
        if (file.exists()) {
            try {
                inputStream = new FileInputStream(file);
                parser = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
                //create the builder
                builder = new StAXOMBuilder(parser);
                //get the root element (in this case the envelope)
                documentElement = builder.getDocumentElement().cloneOMElement();
            } finally {
                if (builder != null) {
                    builder.close();
                }
                if (parser != null) {
                    try {
                        parser.close();
                    } catch (XMLStreamException e) {
                        //ignore
                    }
                }
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        //ignore
                    }
                }

            }
        } else {
            throw new FileNotFoundException("File Not Exist at " + path);
        }
        return documentElement;
    }

    /**
     * @param synapseConfig - Synapse configuration to be updated
     * @param backendURL    - backend URL of the gateway server
     * @param sessionCookie - session cookie of user login
     * @throws Exception - Throws if update fails
     */
    public static void updateSynapseConfiguration(OMElement synapseConfig, String backendURL,
                                           String sessionCookie)
            throws Exception {

        EndPointAdminClient endPointAdminClient =
                new EndPointAdminClient(backendURL, sessionCookie);
        SequenceAdminServiceClient sequenceAdminClient =
                new SequenceAdminServiceClient(backendURL, sessionCookie);
        LocalEntriesAdminClient localEntryAdminServiceClient =
                new LocalEntriesAdminClient(backendURL, sessionCookie);
        MessageProcessorClient messageProcessorClient =
                new MessageProcessorClient(backendURL, sessionCookie);
        EndpointTemplateAdminServiceClient endpointTemplateAdminServiceClient =
                new EndpointTemplateAdminServiceClient(backendURL, sessionCookie);
        SequenceTemplateAdminServiceClient sequenceTemplateAdminServiceClient =
                new SequenceTemplateAdminServiceClient(backendURL, sessionCookie);
        RestApiAdminClient apiAdminClient = new RestApiAdminClient(backendURL, sessionCookie);
        PriorityMediationAdminClient priorityMediationAdminClient =
                new PriorityMediationAdminClient(backendURL, sessionCookie);

        checkLocalEntries(synapseConfig, backendURL, sessionCookie, localEntryAdminServiceClient);

        checkEndPoints(synapseConfig, backendURL, sessionCookie, endPointAdminClient);

        checkSequences(synapseConfig, backendURL, sessionCookie, sequenceAdminClient);

        checkTemplates(synapseConfig, backendURL, sessionCookie, endpointTemplateAdminServiceClient, sequenceTemplateAdminServiceClient);

        checkAPIs(synapseConfig, backendURL, sessionCookie, apiAdminClient);

        checkPriorityExecutors(synapseConfig, backendURL, sessionCookie, priorityMediationAdminClient);

        Thread.sleep(1000);
        verifySynapseDeployment(synapseConfig, backendURL, sessionCookie);
        log.info("Synapse configuration  Deployed");

    }

    private static void checkPriorityExecutors(OMElement synapseConfig, String backendURL,
                                        String sessionCookie,
                                        PriorityMediationAdminClient priorityMediationAdminClient)
            throws RemoteException {
        Iterator priorityExecutorList =
                synapseConfig.getChildrenWithLocalName(PRIORITY_EXECUTOR);
        while (priorityExecutorList.hasNext()) {
            OMElement executor = (OMElement) priorityExecutorList.next();
            String executorName = executor.getAttributeValue(new QName(NAME));
            if (ArrayUtils.contains(priorityMediationAdminClient.getExecutorList(), executorName)) {
                priorityMediationAdminClient.remove(executorName);
                assertTrue(
                        isPriorityExecutorUnDeployed(backendURL, sessionCookie, executorName)
                        , executorName + " Priority Executor undeployment failed");
            }
            priorityMediationAdminClient.addPriorityMediator(executorName, executor);
            log.info(executorName + " Priority Executor Uploaded");
        }
    }

    private static void checkAPIs(OMElement synapseConfig, String backendURL, String sessionCookie,
                           RestApiAdminClient apiAdminClient)
            throws RestApiAdminAPIException, RemoteException {
        Iterator apiElements = synapseConfig.getChildrenWithLocalName(API);
        while (apiElements.hasNext()) {
            OMElement api = (OMElement) apiElements.next();
            String apiName = api.getAttributeValue(new QName(NAME));
            if (ArrayUtils.contains(apiAdminClient.getApiNames(), apiName)) {
                apiAdminClient.deleteApi(apiName);
                assertTrue(isApiUnDeployed(backendURL, sessionCookie, apiName), apiName + " Api undeployment failed");
            }
            apiAdminClient.add(api);
            log.info(apiName + " API Uploaded");
        }
    }

    private static void checkTemplates(OMElement synapseConfig, String backendURL, String sessionCookie,
                                EndpointTemplateAdminServiceClient endpointTemplateAdminServiceClient,
                                SequenceTemplateAdminServiceClient sequenceTemplateAdminServiceClient)
            throws RemoteException, EndpointAdminEndpointAdminException {
        Iterator templates = synapseConfig.getChildrenWithLocalName(TEMPLATE);
        while (templates.hasNext()) {
            OMElement template = (OMElement) templates.next();
            String templateName = template.getAttributeValue(new QName(NAME));
            if (template.getFirstChildWithName(
                    new QName(template.getNamespace().getNamespaceURI(), SEQUENCE)) != null) {
                if (ArrayUtils.contains(sequenceTemplateAdminServiceClient.getSequenceTemplates(),
                                        templateName)) {
                    sequenceTemplateAdminServiceClient.deleteTemplate(templateName);
                    assertTrue(
                            isSequenceTemplateUnDeployed(backendURL, sessionCookie, templateName)
                            , templateName + " Sequence Template undeployment failed");
                }
                sequenceTemplateAdminServiceClient.addSequenceTemplate(template);

            } else {

                if (ArrayUtils.contains(endpointTemplateAdminServiceClient.getEndpointTemplates(),
                                        templateName)) {
                    endpointTemplateAdminServiceClient.deleteEndpointTemplate(templateName);
                    assertTrue(
                            isEndpointTemplateUnDeployed(backendURL, sessionCookie, templateName)
                            , templateName + " Endpoint Template undeployment failed");
                }
                endpointTemplateAdminServiceClient.addEndpointTemplate(template);
            }
            log.info(templateName + " Template Uploaded");
        }
    }

    private static void checkMessageProcessors(OMElement synapseConfig, String backendURL,
                                        String sessionCookie,
                                        MessageProcessorClient messageProcessorClient)
            throws RemoteException, SequenceEditorException {
        Iterator messageProcessors =
                synapseConfig.getChildrenWithLocalName(MESSAGE_PROCESSOR);
        while (messageProcessors.hasNext()) {
            OMElement messageProcessor = (OMElement) messageProcessors.next();
            String mProcessor = messageProcessor.getAttributeValue(new QName(NAME));
            if (ArrayUtils
                    .contains(messageProcessorClient.getMessageProcessorNames(), mProcessor)) {
                messageProcessorClient.deleteMessageProcessor(mProcessor);
                assertTrue(isMessageProcessorUnDeployed(backendURL, sessionCookie, mProcessor),
                        mProcessor + " Message Processor undeployment failed");
            }
            messageProcessorClient.addMessageProcessor(messageProcessor);
            log.info(mProcessor + " Message Processor Uploaded");
        }
    }


    private static void checkSequences(OMElement synapseConfig, String backendURL, String sessionCookie,
                                SequenceAdminServiceClient sequenceAdminClient)
            throws SequenceEditorException, RemoteException {
        Iterator sequences = synapseConfig.getChildrenWithLocalName(SEQUENCE);
        while (sequences.hasNext()) {
            OMElement sequence = (OMElement) sequences.next();
            String sqn = sequence.getAttributeValue(new QName(NAME));
            boolean isSequenceExist = ArrayUtils.contains(sequenceAdminClient.getSequences(), sqn);
            if (("main".equalsIgnoreCase(sqn) || "fault".equalsIgnoreCase(sqn)) && isSequenceExist) {
                sequenceAdminClient.updateSequence(sequence);
            } else {
                if (isSequenceExist) {
                    sequenceAdminClient.deleteSequence(sqn);
                    assertTrue(isSequenceUnDeployed(backendURL, sessionCookie, sqn),
                               sqn + " Sequence undeployment failed");
                }
                sequenceAdminClient.addSequence(sequence);
            }
            log.info(sqn + " Sequence Uploaded");
        }
    }

    private static void checkEndPoints(OMElement synapseConfig, String backendURL, String sessionCookie,
                                EndPointAdminClient endPointAdminClient)
            throws EndpointAdminEndpointAdminException, IOException, XMLStreamException {
        Iterator endpoints = synapseConfig.getChildrenWithLocalName(ENDPOINT);
        while (endpoints.hasNext()) {
            OMElement endpoint = (OMElement) endpoints.next();
            String ep = endpoint.getAttributeValue(new QName(NAME));
            if (ArrayUtils.contains(endPointAdminClient.getEndpointNames(), ep)) {
                assertTrue(endPointAdminClient.deleteEndpoint(ep), ep + " Endpoint deletion failed");
                assertTrue(isEndpointUnDeployed(backendURL, sessionCookie, ep), ep + " Endpoint undeployment failed");
            }
            assertTrue(endPointAdminClient.addEndPoint(endpoint), ep + " Endpoint addition failed");
            log.info(ep + " Endpoint Uploaded");
        }
    }

    private static void checkLocalEntries(OMElement synapseConfig, String backendURL, String sessionCookie,
                                   LocalEntriesAdminClient localEntryAdminServiceClient)
            throws LocalEntryAdminException, RemoteException {
        Iterator localEntries = synapseConfig.getChildrenWithLocalName(LOCAL_ENTRY);
        while (localEntries.hasNext()) {
            OMElement localEntry = (OMElement) localEntries.next();
            String le = localEntry.getAttributeValue(new QName(KEY));
            if (ArrayUtils.contains(localEntryAdminServiceClient.getEntryNames(), le)) {
                assertTrue(localEntryAdminServiceClient.deleteLocalEntry(le), le + " Local Entry deletion failed");
                assertTrue(isLocalEntryUnDeployed(backendURL, sessionCookie, le),
                        le + " Local Entry undeployment failed");
            }
            assertTrue(localEntryAdminServiceClient.addLocalEntry(localEntry), le + " Local Entry addition failed");
            log.info(le + " LocalEntry Uploaded");
        }
    }

    public static void addEndpoint(String backEndUrl, String sessionCookie, OMElement endpointConfig)
            throws Exception {
        EndPointAdminClient endPointAdminClient =
                new EndPointAdminClient(backEndUrl, sessionCookie);
        endPointAdminClient.addEndPoint(endpointConfig);
        String ep = endpointConfig.getAttributeValue(new QName(NAME));
        assertTrue(isEndpointDeployed(backEndUrl, sessionCookie, ep),
                   ep + "Endpoint deployment not found or time out");
    }

    public static void addLocalEntry(String backEndUrl, String sessionCookie,
                              OMElement localEntryConfig) throws Exception {
        LocalEntriesAdminClient localEntryAdminServiceClient =
                new LocalEntriesAdminClient(backEndUrl,
                                            sessionCookie);
        boolean value = localEntryAdminServiceClient.addLocalEntry(localEntryConfig);
        assertTrue(value, "LocalEntry Addition failed");
        if (value) {
            String le = localEntryConfig.getAttributeValue(new QName(KEY));
            assertTrue(isLocalEntryDeployed(backEndUrl, sessionCookie, le),
                       le + "LocalEntry deployment not found or time out");
        }

    }

    public static void addSequence(String backEndUrl, String sessionCookie, OMElement sequenceConfig)
            throws Exception {
        SequenceAdminServiceClient sequenceAdminClient = new SequenceAdminServiceClient(backEndUrl,
                                                                                        sessionCookie);
        sequenceAdminClient.addSequence(sequenceConfig);
        String sqn = sequenceConfig.getAttributeValue(new QName(NAME));
        assertTrue(isSequenceDeployed(backEndUrl, sessionCookie, sqn),
                   sqn + "Sequence deployment not found or time out");

    }

    public static void addSequenceTemplate(String backEndUrl, String sessionCookie,
                                    OMElement sequenceTemplate) throws RemoteException {
        SequenceTemplateAdminServiceClient sequenceTemplateAdminServiceClient =
                new SequenceTemplateAdminServiceClient(backEndUrl, sessionCookie);
        sequenceTemplateAdminServiceClient.addSequenceTemplate(sequenceTemplate);
        String seqTmpName = sequenceTemplate.getAttributeValue(new QName(NAME));
        assertTrue(isSequenceTemplateDeployed(backEndUrl, sessionCookie, seqTmpName),
                   "Sequence Template deployment failed");

    }

    public static void addEndpointTemplate(String backEndUrl, String sessionCookie,
                                    OMElement endpointTemplate) throws RemoteException {
        EndpointTemplateAdminServiceClient endpointTemplateAdminServiceClient =
                new EndpointTemplateAdminServiceClient(backEndUrl, sessionCookie);
        endpointTemplateAdminServiceClient.addEndpointTemplate(endpointTemplate);
        String endpointTmpName = endpointTemplate.getAttributeValue(new QName(NAME));
        assertTrue(isEndpointTemplateDeployed(backEndUrl, sessionCookie, endpointTmpName),
                   "Endpoint Template deployment failed");

    }

    public static void addAPI(String backEndUrl, String sessionCookie,
                       OMElement api) throws RemoteException, RestApiAdminAPIException {
        RestApiAdminClient apiAdminClient = new RestApiAdminClient(backEndUrl, sessionCookie);
        apiAdminClient.add(api);
        String apiName = api.getAttributeValue(new QName(NAME));
        assertTrue(isApiDeployed(backEndUrl, sessionCookie, apiName),
                   "Rest Api deployment failed");
    }

    public static void addPriorityExecutor(String backEndUrl, String sessionCookie,
                                    OMElement priorityExecutor)
            throws RemoteException {
        PriorityMediationAdminClient priorityMediationAdminClient =
                new PriorityMediationAdminClient(backEndUrl, sessionCookie);
        String executorName = priorityExecutor.getAttributeValue(new QName(NAME));
        priorityMediationAdminClient.addPriorityMediator(executorName, priorityExecutor);
        assertTrue(isPriorityExecutorDeployed(backEndUrl, sessionCookie, executorName),
                   "Priority Executor deployment failed");
    }

    public static void addScheduleTask(String backEndUrl, String sessionCookie, OMElement taskDescription)
            throws TaskManagementException, RemoteException {
        TaskAdminClient taskAdminClient = new TaskAdminClient(backEndUrl, sessionCookie);
        taskAdminClient.addTask(taskDescription);
        assertTrue(isScheduleTaskDeployed(backEndUrl, sessionCookie,
                        taskDescription.getAttributeValue(new QName("name"))),
                   "ScheduleTask deployment failed"
        );
    }

    public static boolean isEndpointDeployed(String backEndUrl, String sessionCookie, String endpointName)
            throws EndpointAdminEndpointAdminException, RemoteException {
        EndPointAdminClient endPointAdminClient = new EndPointAdminClient(backEndUrl,
                                                                          sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Endpoint " + endpointName);
        boolean isEndpointExist = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] endpoints = endPointAdminClient.getEndpointNames();
            if (endpoints != null && endpoints.length > 0) {
                for (String endpoint : endpoints) {

                    if (endpointName.equals(endpoint)) {
                        isEndpointExist = true;
                        log.info(endpointName + " Endpoint Found in " + time + " millis");
                        break;
                    }
                }
            }
            if (isEndpointExist) {
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isEndpointExist;
    }

    public static boolean isSequenceDeployed(String backEndUrl, String sessionCookie, String sequenceName)
            throws SequenceEditorException, RemoteException {
        SequenceAdminServiceClient sequenceAdminServiceClient =
                new SequenceAdminServiceClient(backEndUrl,
                                               sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Sequence " + sequenceName);
        boolean isSequenceExist = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] sequences = sequenceAdminServiceClient.getSequences();
            if (sequences != null && sequences.length > 0) {
                for (String sequence : sequences) {

                    if (sequence.equals(sequenceName)) {
                        isSequenceExist = true;
                        log.info(sequenceName + " Sequence Found in " + time + " millis");
                        break;
                    }
                }
            }
            if (isSequenceExist) {
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isSequenceExist;
    }

    public static boolean isSequenceTemplateDeployed(String backEndUrl, String sessionCookie,
                                              String sequenceTemplateName) throws RemoteException {
        SequenceTemplateAdminServiceClient sequenceTemplateAdminServiceClient =
                new SequenceTemplateAdminServiceClient(backEndUrl, sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Sequence Template " +
                 sequenceTemplateName);
        boolean isSequenceTmpFound = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] templates = sequenceTemplateAdminServiceClient.getSequenceTemplates();
            if (templates != null && templates.length > 0) {
                for (String tmpl : templates) {

                    if (tmpl.equals(sequenceTemplateName)) {
                        isSequenceTmpFound = true;
                        log.info(sequenceTemplateName + " Sequence Template Found in " + time +
                                 " millis");
                        break;
                    }
                }
            }
            if (isSequenceTmpFound) {
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isSequenceTmpFound;
    }

    public static boolean isEndpointTemplateDeployed(String backEndUrl, String sessionCookie,
                                              String endpointTemplateName) throws RemoteException {
        EndpointTemplateAdminServiceClient endpointTemplateAdminServiceClient =
                new EndpointTemplateAdminServiceClient(backEndUrl, sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Endpoint Template " +
                 endpointTemplateName);
        boolean isEndpointTmpFound = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] templates = endpointTemplateAdminServiceClient.getEndpointTemplates();
            if (templates != null && templates.length > 0) {
                for (String tmpl : templates) {

                    if (tmpl.equals(endpointTemplateName)) {
                        isEndpointTmpFound = true;
                        log.info(endpointTemplateName + " Endpoint Template Found in " + time +
                                 " millis");
                        break;
                    }
                }
            }
            if (isEndpointTmpFound) {
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isEndpointTmpFound;
    }

    public static boolean isApiDeployed(String backEndUrl, String sessionCookie, String apiName)
            throws RemoteException, RestApiAdminAPIException {
        RestApiAdminClient apiAdminClient = new RestApiAdminClient(backEndUrl, sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for API " + apiName);
        boolean isApiFound = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] apiList = apiAdminClient.getApiNames();
            if (apiList != null && apiList.length > 0) {
                for (String restApi : apiList) {

                    if (restApi.equals(apiName)) {
                        isApiFound = true;
                        log.info(apiName + " API Found in " + time + " millis");
                        break;
                    }
                }
            }
            if (isApiFound) {
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isApiFound;
    }

    public static boolean isPriorityExecutorDeployed(String backEndUrl, String sessionCookie,
                                              String executorName)
            throws RemoteException {
        PriorityMediationAdminClient priorityMediationAdminClient =
                new PriorityMediationAdminClient(backEndUrl, sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Priority Executor " +
                 executorName);
        boolean isExecutorFound = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] executorList = priorityMediationAdminClient.getExecutorList();
            if (executorList != null && executorList.length > 0) {
                for (String executor : executorList) {

                    if (executor.equals(executorName)) {
                        isExecutorFound = true;
                        log.info(executorName + " Priority Executor Found in " + time + " millis");
                        break;
                    }
                }
            }
            if (isExecutorFound) {
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isExecutorFound;
    }

    public static boolean isScheduleTaskDeployed(String backEndUrl, String sessionCookie, String taskName)
            throws RemoteException, TaskManagementException {
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Task deployment " + taskName);

        boolean isTaskDeployed = false;
        TaskAdminClient taskAdminClient = new TaskAdminClient(backEndUrl, sessionCookie);
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            if (taskAdminClient.getScheduleTaskList().contains(taskName)) {
                isTaskDeployed = true;
                log.info(taskName + " Task Deployed in " + time + " millis");
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException ignored) {

            }
        }

        return isTaskDeployed;
    }

    public static boolean isLocalEntryExist(String backEndUrl, String sessionCookie, String localEntryName)
            throws LocalEntryAdminException, RemoteException {
        LocalEntriesAdminClient localEntryAdminServiceClient =
                new LocalEntriesAdminClient(backEndUrl,
                                            sessionCookie);
        String[] localEntries = localEntryAdminServiceClient.getEntryNames();
        if (localEntries == null || localEntries.length == 0) {
            return false;
        }
        return ArrayUtils.contains(localEntries, localEntryName);
    }

    public static boolean isSequenceExist(String backEndUrl, String sessionCookie, String sequenceName)
            throws SequenceEditorException, RemoteException {
        SequenceAdminServiceClient sequenceAdminServiceClient =
                new SequenceAdminServiceClient(backEndUrl,
                                               sessionCookie);
        String[] sequences = sequenceAdminServiceClient.getSequences();
        if (sequences == null || sequences.length == 0) {
            return false;
        }
        return ArrayUtils.contains(sequences, sequenceName);
    }

    public static boolean isEndpointExist(String backEndUrl, String sessionCookie, String endpointName)
            throws EndpointAdminEndpointAdminException, RemoteException {
        EndPointAdminClient endPointAdminClient = new EndPointAdminClient(backEndUrl,
                                                                          sessionCookie);
        String[] endpoints = endPointAdminClient.getEndpointNames();
        if (endpoints == null || endpoints.length == 0) {
            return false;
        }
        return ArrayUtils.contains(endpoints, endpointName);
    }

    public static boolean isSequenceTemplateExist(String backEndUrl, String sessionCookie,
                                           String sequenceTemplate) throws RemoteException {
        SequenceTemplateAdminServiceClient sequenceTemplateAdminServiceClient =
                new SequenceTemplateAdminServiceClient(backEndUrl, sessionCookie);
        return ArrayUtils.contains(sequenceTemplateAdminServiceClient.getSequenceTemplates(), sequenceTemplate);

    }

    public static boolean isEndpointTemplateExist(String backEndUrl, String sessionCookie,
                                           String endpointTemplate) throws RemoteException {
        EndpointTemplateAdminServiceClient endpointTemplateAdminServiceClient =
                new EndpointTemplateAdminServiceClient(backEndUrl, sessionCookie);
        return ArrayUtils.contains(endpointTemplateAdminServiceClient.getEndpointTemplates(), endpointTemplate);

    }

    public static boolean isApiExist(String backEndUrl, String sessionCookie, String apiName)
            throws RemoteException, RestApiAdminAPIException {
        RestApiAdminClient apiAdminClient = new RestApiAdminClient(backEndUrl, sessionCookie);
        return ArrayUtils.contains(apiAdminClient.getApiNames(), apiName);

    }

    public static boolean isPriorityExecutorExist(String backEndUrl, String sessionCookie,
                                           String priorityExecutorName) throws RemoteException {
        PriorityMediationAdminClient priorityMediationAdminClient =
                new PriorityMediationAdminClient(backEndUrl, sessionCookie);
        return ArrayUtils
                .contains(priorityMediationAdminClient.getExecutorList(), priorityExecutorName);

    }

    public static boolean isScheduleTaskExist(String backEndUrl, String sessionCookie, String taskName)
            throws RemoteException, TaskManagementException {
        TaskAdminClient taskAdminClient = new TaskAdminClient(backEndUrl, sessionCookie);
        return taskAdminClient.getScheduleTaskList().contains(taskName);
    }

    public static void deleteLocalEntry(String backEndUrl, String sessionCookie, String localEntryName)
            throws LocalEntryAdminException, RemoteException {
        LocalEntriesAdminClient localEntryAdminServiceClient =
                new LocalEntriesAdminClient(backEndUrl,
                                            sessionCookie);
        assertTrue(localEntryAdminServiceClient.deleteLocalEntry(localEntryName), "LocalEntry Deletion failed");
        assertTrue(isLocalEntryUnDeployed(backEndUrl, sessionCookie, localEntryName),
                   "LocalEntry undeployment failed");

    }

    public static void deleteEndpoint(String backEndUrl, String sessionCookie, String endpointName)
            throws EndpointAdminEndpointAdminException, RemoteException {
        EndPointAdminClient endPointAdminClient = new EndPointAdminClient(backEndUrl,
                                                                          sessionCookie);
        assertTrue(endPointAdminClient.deleteEndpoint(endpointName), "Endpoint deletion failed");
        assertTrue(isEndpointUnDeployed(backEndUrl, sessionCookie, endpointName),
                   "Endpoint undeployment failed");
    }

    public static void deleteSequence(String backEndUrl, String sessionCookie, String sequenceName)
            throws SequenceEditorException, RemoteException {
        SequenceAdminServiceClient sequenceAdminServiceClient =
                new SequenceAdminServiceClient(backEndUrl,
                                               sessionCookie);
        sequenceAdminServiceClient.deleteSequence(sequenceName);
        assertTrue(isSequenceUnDeployed(backEndUrl, sessionCookie, sequenceName),
                   "Sequence undeployment failed");
    }

    public static void deleteEndpointTemplate(String backEndUrl, String sessionCookie,
                                       String endpointTemplate)
            throws RemoteException, SequenceEditorException, EndpointAdminEndpointAdminException {

        EndpointTemplateAdminServiceClient endpointTemplateAdminServiceClient =
                new EndpointTemplateAdminServiceClient(backEndUrl, sessionCookie);
        endpointTemplateAdminServiceClient.deleteEndpointTemplate(endpointTemplate);
        assertTrue(isEndpointTemplateUnDeployed(backEndUrl, sessionCookie, endpointTemplate),
                   "Endpoint Template undeployment failed");
    }

    public static void deleteSequenceTemplate(String backEndUrl, String sessionCookie,
                                       String sequenceTemplateName)
            throws RemoteException, SequenceEditorException, EndpointAdminEndpointAdminException {
        SequenceTemplateAdminServiceClient sequenceTemplateAdminServiceClient =
                new SequenceTemplateAdminServiceClient(backEndUrl, sessionCookie);
        sequenceTemplateAdminServiceClient.deleteTemplate(sequenceTemplateName);
        assertTrue(
                isSequenceTemplateUnDeployed(backEndUrl, sessionCookie, sequenceTemplateName),
                "Sequence Template undeployment failed");
    }

    public static void deleteApi(String backEndUrl, String sessionCookie, String apiName)
            throws RemoteException, RestApiAdminAPIException {
        RestApiAdminClient apiAdminClient = new RestApiAdminClient(backEndUrl, sessionCookie);
        apiAdminClient.deleteApi(apiName);
        assertTrue(isApiUnDeployed(backEndUrl, sessionCookie, apiName),
                   "API undeployment failed");
    }

    public static void deletePriorityExecutor(String backEndUrl, String sessionCookie, String executorName)
            throws RemoteException {
        PriorityMediationAdminClient priorityMediationAdminClient =
                new PriorityMediationAdminClient(backEndUrl, sessionCookie);
        priorityMediationAdminClient.remove(executorName);
        assertTrue(isPriorityExecutorUnDeployed(backEndUrl, sessionCookie, executorName),
                   "Priority Executor undeployment failed");
    }

    public static void deleteScheduleTask(String backEndUrl, String sessionCookie, String taskName,
                                   String group)
            throws TaskManagementException, RemoteException {
        TaskAdminClient taskAdminClient = new TaskAdminClient(backEndUrl, sessionCookie);
        taskAdminClient.deleteTask(taskName, group);
        assertTrue(isScheduleTaskUnDeployed(backEndUrl, sessionCookie, taskName),
                   "ScheduleTask deployment failed");

    }

    public static boolean isMessageProcessorUnDeployed(String backEndUrl, String sessionCookie,
                                                String messageProcessorName)
            throws SequenceEditorException, RemoteException {
        MessageProcessorClient messageProcessorClient =
                new MessageProcessorClient(backEndUrl, sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY +
                " millis for Undeployment Message Processor " + messageProcessorName);
        boolean isMessageProcessorDeleted = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] mProcessors = messageProcessorClient.getMessageProcessorNames();
            if (!ArrayUtils.contains(mProcessors, messageProcessorName)) {
                isMessageProcessorDeleted = true;
                break;
            }

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isMessageProcessorDeleted;
    }

    public static boolean isLocalEntryDeployed(String backEndUrl, String sessionCookie,
                                        String localEntryName)
            throws LocalEntryAdminException, RemoteException {
        LocalEntriesAdminClient localEntryAdminServiceClient =
                new LocalEntriesAdminClient(backEndUrl,
                                            sessionCookie);
        log.info(
                "waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for LocalEntry " + localEntryName);
        boolean isLocalEntryExist = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] localEntries = localEntryAdminServiceClient.getEntryNames();
            if (localEntries != null && localEntries.length > 0) {
                for (String localEntry : localEntries) {

                    if (localEntryName.equals(localEntry)) {
                        isLocalEntryExist = true;
                        log.info(localEntryName + " LocalEntry Found in " + time + " millis");
                        break;
                    }
                }
            }
            if (isLocalEntryExist) {
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isLocalEntryExist;
    }

    public static boolean isLocalEntryUnDeployed(String backEndUrl, String sessionCookie,
                                          String localEntryName)
            throws LocalEntryAdminException, RemoteException {
        LocalEntriesAdminClient localEntryAdminServiceClient =
                new LocalEntriesAdminClient(backEndUrl,
                                            sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Undeployment LocalEntry " +
                 localEntryName);
        boolean isLocalEntryUnDeployed = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] localEntries = localEntryAdminServiceClient.getEntryNames();
            if (!ArrayUtils.contains(localEntries, localEntryName)) {
                isLocalEntryUnDeployed = true;
                break;
            }

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isLocalEntryUnDeployed;
    }

    public static boolean isSequenceUnDeployed(String backEndUrl, String sessionCookie,
                                        String sequenceName)
            throws SequenceEditorException, RemoteException {
        SequenceAdminServiceClient sequenceAdminServiceClient =
                new SequenceAdminServiceClient(backEndUrl,
                                               sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Undeployment Sequence " +
                 sequenceName);
        boolean isSequenceUnDeployed = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] sequences = sequenceAdminServiceClient.getSequences();
            if (!ArrayUtils.contains(sequences, sequenceName)) {
                isSequenceUnDeployed = true;
                break;
            }

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isSequenceUnDeployed;
    }

    public static boolean isEndpointUnDeployed(String backEndUrl, String sessionCookie,
                                        String endpointName)
            throws EndpointAdminEndpointAdminException, RemoteException {
        EndPointAdminClient endPointAdminClient = new EndPointAdminClient(backEndUrl,
                                                                          sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Undeployment Endpoint " +
                 endpointName);
        boolean isEndpointUnDeployed = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] endpoints = endPointAdminClient.getEndpointNames();
            if (!ArrayUtils.contains(endpoints, endpointName)) {
                isEndpointUnDeployed = true;
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isEndpointUnDeployed;
    }

    public static boolean isEndpointTemplateUnDeployed(String backEndUrl, String sessionCookie,
                                                String endpointTemplateName)
            throws EndpointAdminEndpointAdminException, RemoteException {
        EndpointTemplateAdminServiceClient endpointTemplateAdminServiceClient =
                new EndpointTemplateAdminServiceClient(backEndUrl, sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY +
                 " millis for Undeployment Endpoint Template " + endpointTemplateName);
        boolean isEndpointTemplateUnDeployed = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] endpointTemplates = endpointTemplateAdminServiceClient.getEndpointTemplates();
            if (!ArrayUtils.contains(endpointTemplates, endpointTemplateName)) {
                isEndpointTemplateUnDeployed = true;
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isEndpointTemplateUnDeployed;
    }

    public static boolean isSequenceTemplateUnDeployed(String backEndUrl, String sessionCookie,
                                                String sequenceTemplateName)
            throws EndpointAdminEndpointAdminException, RemoteException {
        SequenceTemplateAdminServiceClient sequenceTemplateAdminServiceClient =
                new SequenceTemplateAdminServiceClient(backEndUrl, sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY +
                 " millis for Undeployment Sequence Template " + sequenceTemplateName);
        boolean isSequenceTemplateUnDeployed = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] sequenceTemplates = sequenceTemplateAdminServiceClient.getSequenceTemplates();
            if (!ArrayUtils.contains(sequenceTemplates, sequenceTemplateName)) {
                isSequenceTemplateUnDeployed = true;
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isSequenceTemplateUnDeployed;
    }

    public static boolean isApiUnDeployed(String backEndUrl, String sessionCookie,
                                   String apiName)
            throws RemoteException, RestApiAdminAPIException {
        RestApiAdminClient apiAdminClient = new RestApiAdminClient(backEndUrl, sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Undeployment API " + apiName);
        boolean isApiUnDeployed = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] apiList = apiAdminClient.getApiNames();
            if (!ArrayUtils.contains(apiList, apiName)) {
                isApiUnDeployed = true;
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isApiUnDeployed;
    }

    public static boolean isPriorityExecutorUnDeployed(String backEndUrl, String sessionCookie,
                                                String executorName)
            throws RemoteException {
        PriorityMediationAdminClient priorityMediationAdminClient =
                new PriorityMediationAdminClient(backEndUrl, sessionCookie);
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY +
                 " millis for Undeployment Priority Executor " + executorName);
        boolean isExecutorUnDeployed = false;
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            String[] executorList = priorityMediationAdminClient.getExecutorList();
            if (!ArrayUtils.contains(executorList, executorName)) {
                isExecutorUnDeployed = true;
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                //ignore
            }
        }
        return isExecutorUnDeployed;
    }

    public static boolean isScheduleTaskUnDeployed(String backEndUrl, String sessionCookie,
                                            String taskName)
            throws RemoteException, TaskManagementException {
        log.info("waiting " + SERVICE_DEPLOYMENT_DELAY + " millis for Task Undeployment " +
                 taskName);

        boolean isTaskUnDeployed = false;
        TaskAdminClient taskAdminClient = new TaskAdminClient(backEndUrl, sessionCookie);
        Calendar startTime = Calendar.getInstance();
        long time;
        while ((time = (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis())) <
               SERVICE_DEPLOYMENT_DELAY) {
            if (!taskAdminClient.getScheduleTaskList().contains(taskName)) {
                isTaskUnDeployed = true;
                log.info(taskName + " Task UnDeployed in " + time + " millis");
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException ignored) {

            }
        }

        return isTaskUnDeployed;
    }

    public static void verifySynapseDeployment(OMElement synapseConfig, String backendURL,
                                        String sessionCookie)
            throws LocalEntryAdminException, RemoteException, EndpointAdminEndpointAdminException,
                   SequenceEditorException, RestApiAdminAPIException {
        Iterator localEntries = synapseConfig.getChildrenWithLocalName(LOCAL_ENTRY);
        while (localEntries.hasNext()) {
            OMElement leOM = (OMElement) localEntries.next();
            String le = leOM.getAttributeValue(new QName(KEY));
            assertTrue(isLocalEntryDeployed(backendURL, sessionCookie, le),
                       le + " LocalEntry deployment not found or time out");
        }

        Iterator endpoints = synapseConfig.getChildrenWithLocalName(ENDPOINT);
        while (endpoints.hasNext()) {
            OMElement epOM = (OMElement) endpoints.next();
            String ep = epOM.getAttributeValue(new QName(NAME));
            assertTrue(isEndpointDeployed(backendURL, sessionCookie, ep),
                       ep + " Endpoint deployment not found or time out");
        }

        Iterator sequences = synapseConfig.getChildrenWithLocalName(SEQUENCE);
        while (sequences.hasNext()) {
            OMElement sqnOM = (OMElement) sequences.next();
            String sqn = sqnOM.getAttributeValue(new QName(NAME));
            assertTrue(isSequenceDeployed(backendURL, sessionCookie, sqn),
                       sqn + " Sequence deployment not found or time out");
        }




        Iterator templates = synapseConfig.getChildrenWithLocalName(TEMPLATE);

        while (templates.hasNext()) {
            OMElement template = (OMElement) templates.next();
            String templateName = template.getAttributeValue(new QName(NAME));

            if (template.getFirstChildWithName(new QName(template.getNamespace().getNamespaceURI(),
                                                         SEQUENCE)) != null) {
                assertTrue(isSequenceTemplateDeployed(backendURL, sessionCookie, templateName),
                           templateName + " Sequence Template Deployment not found or time out");
            } else {

                assertTrue(isEndpointTemplateDeployed(backendURL, sessionCookie, templateName),
                           templateName + " Endpoint Template Deployment not found or time out");
            }
            log.info("Template Uploaded");
        }

        Iterator apiList = synapseConfig.getChildrenWithLocalName(API);
        while (apiList.hasNext()) {
            OMElement api = (OMElement) apiList.next();
            String apiName = api.getAttributeValue(new QName(NAME));
            String version = api.getAttributeValue(new QName(VERSION));
            if (version != null && !version.equals("")) {
                apiName = apiName + ":v" + version;
            }
            assertTrue(isApiDeployed(backendURL, sessionCookie, apiName),
                       apiName + " API Deployment not found or time out");
        }

        Iterator executorList =
                synapseConfig.getChildrenWithLocalName(PRIORITY_EXECUTOR);
        while (executorList.hasNext()) {
            OMElement executorNameOM = (OMElement) executorList.next();
            String executorName = executorNameOM.getAttributeValue(new QName(NAME));
            assertTrue(isPriorityExecutorDeployed(backendURL, sessionCookie, executorName),
                       executorName + " Priority Executor Deployment not found or time out");
        }
    }

    /**
     * create API bean object from response
     *
     * @param httpResponse - HTTP response
     * @return - APIBean instance
     */
    public static APIBean getAPIBeanFromHttpResponse(HttpResponse httpResponse)
            throws APIManagerIntegrationTestException {
        JSONObject jsonObject;
        String APIName;
        String APIProvider;
        String APIVersion;
        APIBean apiBean;
        try {
            jsonObject = new JSONObject(httpResponse.getData());

            APIName = ((JSONObject) jsonObject.get("api")).getString("name");
            APIVersion = ((JSONObject) jsonObject.get("api")).getString("version");
            APIProvider = ((JSONObject) jsonObject.get("api")).getString("provider");

            APIIdentifier identifier = new APIIdentifier(APIProvider, APIName, APIVersion);

            apiBean = new APIBean(identifier);
            apiBean.setContext(((JSONObject) jsonObject.get("api")).getString("context"));
            apiBean.setDescription(((JSONObject) jsonObject.get("api")).getString("description"));
            apiBean.setWsdlUrl(((JSONObject) jsonObject.get("api")).getString("wsdl"));
            apiBean.setTags(((JSONObject) jsonObject.get("api")).getString("tags"));
            apiBean.setAvailableTiers(((JSONObject) jsonObject.get("api")).getString("availableTiers"));

            apiBean.setThumbnailUrl(((JSONObject) jsonObject.get("api")).getString("thumb"));
            apiBean.setSandboxUrl(((JSONObject) jsonObject.get("api")).getString("sandbox"));
            apiBean.setBusinessOwner(((JSONObject) jsonObject.get("api")).getString("bizOwner"));
            apiBean.setBusinessOwnerEmail(((JSONObject) jsonObject.get("api")).getString("bizOwnerMail"));
            apiBean.setTechnicalOwner(((JSONObject) jsonObject.get("api")).getString("techOwner"));
            apiBean.setTechnicalOwnerEmail(((JSONObject) jsonObject.get("api")).getString("techOwnerMail"));

            apiBean.setWadlUrl(((JSONObject) jsonObject.get("api")).getString("wadl"));
            apiBean.setVisibility(((JSONObject) jsonObject.get("api")).getString("visibility"));
            apiBean.setVisibleRoles(((JSONObject) jsonObject.get("api")).getString("roles"));
            apiBean.setEndpointUTUsername(((JSONObject) jsonObject.get("api")).getString("epUsername"));
            apiBean.setEndpointUTPassword(((JSONObject) jsonObject.get("api")).getString("epPassword"));

            apiBean.setEndpointSecured((Boolean.getBoolean(((JSONObject) jsonObject.get("api")).getString("endpointTypeSecured"))));
            apiBean.setTransports(((JSONObject) jsonObject.get("api")).getString("transport_http"));
            apiBean.setTransports(((JSONObject) jsonObject.get("api")).getString("transport_https"));
            apiBean.setInSequence(((JSONObject) jsonObject.get("api")).getString("inSequence"));
            apiBean.setOutSequence(((JSONObject) jsonObject.get("api")).getString("outSequence"));
            apiBean.setAvailableTiers(((JSONObject) jsonObject.get("api")).getString("availableTiersDisplayNames"));


            //-----------Here are some of unused properties, if we need to use them add params to APIBean class
            //((JSONObject) jsonObject.get("api")).getString("name");
            //((JSONObject) jsonObject.get("api")).getString("endpoint");
            //((JSONObject) jsonObject.get("api")).getString("subscriptionAvailability");
            //((JSONObject) jsonObject.get("api")).getString("subscriptionTenants");
            //((JSONObject) jsonObject.get("api")).getString("endpointConfig");
            //((JSONObject) jsonObject.get("api")).getString("responseCache");
            //(((JSONObject) jsonObject.get("api")).getString("cacheTimeout");
            //((JSONObject) jsonObject.get("api")).getString("endpointConfig");
            //((JSONObject) jsonObject.get("api")).getString("version");
            //((JSONObject) jsonObject.get("api")).getString("apiStores");
            // ((JSONObject) jsonObject.get("api")).getString("provider");
            //)((JSONObject) jsonObject.get("api")).getString("tierDescs");
            //((JSONObject) jsonObject.get("api")).getString("subs");
            //((JSONObject) jsonObject.get("api")).getString("context");
            // apiBean.setLastUpdated(Date.parse((JSONObject); jsonObject.get("api")).getString("lastUpdated")));
            // apiBean.setUriTemplates((JSONObject) jsonObject.get("api")).getString("templates"));
        } catch (JSONException e) {
            throw new APIManagerIntegrationTestException("Generating APIBen instance fails ", e);
        }
        return apiBean;
    }

    public static void sendGetRequest(String url, String accessToken)
            throws XPathExpressionException, IOException {
        HttpResponse httpResponse;

        URL urlAPI = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) urlAPI.openConnection();
        conn.setRequestMethod("GET");
        conn.setDoOutput(true);
        conn.setReadTimeout(10000);
        //setting headers

        conn.setRequestProperty("Authorization", "Bearer " + accessToken);

        conn.connect();
        // Get the response
        StringBuilder sb = new StringBuilder();
        BufferedReader rd = null;
        try {
            rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String line;
            while ((line = rd.readLine()) != null) {
                sb.append(line);
            }
            httpResponse = new HttpResponse(sb.toString(), conn.getResponseCode());
            httpResponse.setResponseMessage(conn.getResponseMessage());
        } catch (IOException ignored) {

        } finally {
            if (rd != null) {
                rd.close();
            }
        }
    }

    public static String getDecodedJWT(String jwt) throws UnsupportedEncodingException {
        //take first part
        String[] jwtTokenArray = jwt.split(Pattern.quote("."));
        // decode  JWT part
        byte[] jwtByteArray = Base64.decodeBase64(jwtTokenArray[1].getBytes("UTF-8"));
        return new String(jwtByteArray, "UTF-8");
    }

    public static String getJWTAssertion(String jwt) throws UnsupportedEncodingException {
        //take first element
        String[] jwtTokenArray = jwt.split(Pattern.quote("."));
        //Generate the jwt assertion by concatenating header and body section of the jwt token array
        return  jwtTokenArray[0].trim() + "." + jwtTokenArray[1].trim();
    }

    public static boolean isJwtSignatureValid(String jwtAssertion, byte[] jwtSignature, String jsonHeader) throws UnsupportedEncodingException {
        KeyStore keyStore = null;
        String thumbPrint = null;
        String signatureAlgorithm = null;
        JSONObject jsonHeaderObject = null;
        try {
            jsonHeaderObject = new JSONObject(jsonHeader);
            thumbPrint = new String(Base64.decodeBase64(jsonHeaderObject.get("x5t").toString().getBytes()));
            signatureAlgorithm = (String) jsonHeaderObject.get("alg");
        } catch (JSONException e) {
            log.error("Error while parsing json" + e);
        }

        if("RS256".equals(signatureAlgorithm)){
            signatureAlgorithm = "SHA256withRSA";
        } else if("RS515".equals(signatureAlgorithm)){
            signatureAlgorithm = "SHA512withRSA";
        } else if("RS384".equals(signatureAlgorithm)){
            signatureAlgorithm = "SHA384withRSA";
        } else {
            //Default algorithm
            signatureAlgorithm = "SHA256withRSA";
        }

        if(jwtAssertion != null && jwtSignature != null && thumbPrint != null) {
            try {
                String trustStore = TestConfigurationProvider.getTrustStoreLocation();
                String trustStorePassword = TestConfigurationProvider.getTrustStorePassword();
                keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(new FileInputStream(trustStore), trustStorePassword.toCharArray());
                String alias = getAliasForX509CertThumb(thumbPrint.getBytes(), keyStore);
                Certificate certificate = keyStore.getCertificate(alias);
                Signature signature = Signature.getInstance(signatureAlgorithm);
                signature.initVerify(certificate);
                signature.update(jwtAssertion.getBytes());
                return signature.verify(jwtSignature);
            } catch (Exception e) {
                log.error("Error occurred while validating signature", e);
                return false;
            }
        } else {
            log.debug("JWT Signature is empty");
            return false;
        }
    }

    public static String getDecodedJWTHeader(String jwt) throws UnsupportedEncodingException {
        //take first part
        String[] jwtTokenArray = jwt.split(Pattern.quote("."));
        // decode  JWT header
        byte[] jwtByteArray = Base64.decodeBase64(jwtTokenArray[0].getBytes("UTF-8"));
        return new String(jwtByteArray, "UTF-8");
    }

    public static byte[] getDecodedJWTSignature(String jwt) throws UnsupportedEncodingException {
        //take first part
        String[] jwtTokenArray = jwt.split(Pattern.quote("."));
        // decode  JWT signature
        return Base64.decodeBase64(jwtTokenArray[2].getBytes());
    }

    public static byte[] getDecodedURLSafeJWTSignature(String jwt) throws UnsupportedEncodingException {
        //take first part
        String[] jwtTokenArray = jwt.split(Pattern.quote("."));
        // decode  JWT part
        return decode(jwtTokenArray[2]);
    }


    /**
     * This method is used to base64Url-decode a base64Url-encoded string
     *
     * @param stringToBeDecodedArg - The base64Url encoded string to be decoded
     * @return - The base64Url decoded string
     * @throws UnsupportedEncodingException
     */
    public static byte[] decode(String stringToBeDecodedArg) throws UnsupportedEncodingException{

        String stringToBeDecoded = stringToBeDecodedArg;
        stringToBeDecoded = stringToBeDecoded.replaceAll("-", "+");
        stringToBeDecoded = stringToBeDecoded.replaceAll("_", "/");

        switch (stringToBeDecoded.length() % 4) {
            case 0: break;
            case 1: break;
            case 2: stringToBeDecoded = stringToBeDecoded + "==";
                    break;
            case 3: stringToBeDecoded = stringToBeDecoded + "=";
                    break;
        }

        return Base64.decodeBase64(stringToBeDecoded.getBytes("UTF-8"));
    }

    public static String getDecodedURLSafeJWT(String jwt) throws UnsupportedEncodingException {
        //take first part
        String[] jwtTokenArray = jwt.split(Pattern.quote("."));
        // decode  JWT part
        byte[] jwtByteArray = decode(jwtTokenArray[1]);
        return new String(jwtByteArray, "UTF-8");
    }

    public static String getDecodedURLSafeJWTHeader(String jwt) throws UnsupportedEncodingException {
        //take first part
        String[] jwtTokenArray = jwt.split(Pattern.quote("."));
        // decode  JWT header
        byte[] jwtByteArray = decode(jwtTokenArray[0]);
        return new String(jwtByteArray, "UTF-8");
    }

    /**
     * Get the API information from the response  object as Lost of  APIIdentifier
     *
     * @param httpResponse Response that contains the API information
     * @return List of APIIdentifier
     * @throws org.json.JSONException
     */
    public static List<APIIdentifier> getAPIIdentifierListFromHttpResponse(
            HttpResponse httpResponse) throws APIManagerIntegrationTestException {
        List<APIIdentifier> apiIdentifierList = new ArrayList<APIIdentifier>();
        String APIName;
        String APIProvider;
        String APIVersion;
        if (httpResponse.getData() != null && (!httpResponse.getData().equals(""))) {
            try {
                JSONObject jsonRootObject = new JSONObject(httpResponse.getData());

                if (jsonRootObject.has("apis")) {
                    JSONArray jsonArray = jsonRootObject.getJSONArray("apis");
                    for (int index = 0; index < jsonArray.length(); index++) {
                        JSONObject jsonObject = (JSONObject) jsonArray.get(index);
                        APIName = jsonObject.getString("name");
                        APIVersion = jsonObject.getString("version");
                        APIProvider = jsonObject.getString("provider");
                        apiIdentifierList.add(new APIIdentifier(APIProvider, APIName, APIVersion));
                    }
                } else if (jsonRootObject.has("api")) {
                    APIName = jsonRootObject.getJSONObject("api").getString("name");
                    APIVersion = jsonRootObject.getJSONObject("api").getString("version");
                    APIProvider = jsonRootObject.getJSONObject("api").getString("provider");
                    apiIdentifierList.add(new APIIdentifier(APIProvider, APIName, APIVersion));
                }

            } catch (JSONException e) {
                log.error("Error when extraction data from JSON" + e.getMessage());
                throw new APIManagerIntegrationTestException("Error when extraction data from JSON", e);
            }
        }
        return apiIdentifierList;
    }

    /**
     * @param apiListDTO
     * @return
     * @throws APIManagerIntegrationTestException
     */
    public static List<APIIdentifier> getAPIIdentifierListFromHttpResponse(APIListDTO apiListDTO) {
        if (apiListDTO == null) {
            return Collections.emptyList();
        }
        List<APIIdentifier> apiIdentifierList = new ArrayList<>();
        for (APIInfoDTO apiInfoDTO : apiListDTO.getList()) {
            apiIdentifierList
                    .add(new APIIdentifier(apiInfoDTO.getProvider(), apiInfoDTO.getName(), apiInfoDTO.getVersion()));
        }
        return apiIdentifierList;
    }

    /**
     * @param apiListDTO
     * @return
     * @throws APIManagerIntegrationTestException
     */
    public static List<APIIdentifier> getAPIIdentifierListFromHttpResponse(
            org.wso2.am.integration.clients.store.api.v1.dto.APIListDTO apiListDTO) {
        if (apiListDTO == null) {
            return Collections.emptyList();
        }
        List<APIIdentifier> apiIdentifierList = new ArrayList<>();
        for (org.wso2.am.integration.clients.store.api.v1.dto.APIInfoDTO apiInfoDTO : apiListDTO.getList()) {
            apiIdentifierList
                    .add(new APIIdentifier(apiInfoDTO.getProvider(), apiInfoDTO.getName(), apiInfoDTO.getVersion()));
        }
        return apiIdentifierList;
    }

    /**
     * Check  the given API is available in the APIIdentifier List. it will match for API Name,API Version and API Provider
     *
     * @param apiIdentifierToCheck - API identifier to verify
     * @param apiIdentifierList    - API identifier list
     * @return - Status of API availability
     */
    public static boolean isAPIAvailable(APIIdentifier apiIdentifierToCheck,
                                         List<APIIdentifier> apiIdentifierList) {
        boolean isFound = false;
        for (APIIdentifier apiIdentifier : apiIdentifierList) {
            if (apiIdentifier.getApiName().equals(apiIdentifierToCheck.getApiName()) &&
                apiIdentifier.getVersion().equals(apiIdentifierToCheck.getVersion()) &&
                apiIdentifier.getProviderName().equals(apiIdentifierToCheck.getProviderName())) {
                isFound = true;
                break;
            }
        }
        return isFound;
    }

    /**
     * Get the json payload required for getting an access token using the password grant-type
     * @param username - The username of the user (required)
     * @param password - The password of the user (required)
     * @return - The json payload. Sample: "grant_type=password&username=user&password=pass"
     */
    public static String getPayloadForPasswordGrant(String username, String password){
        return "grant_type=password&username=" + username + "&password=" + password;
    }

    private static String getAliasForX509CertThumb(byte[] thumb, KeyStore keyStore) {
        Certificate cert = null;
        MessageDigest sha = null;
        try {
            sha = MessageDigest.getInstance("SHA-1");
            for (Enumeration e = keyStore.aliases(); e.hasMoreElements();) {
                String alias = (String) e.nextElement();
                Certificate[] certs = keyStore.getCertificateChain(alias);
                if (certs == null || certs.length == 0) {
                    cert = keyStore.getCertificate(alias);
                    if (cert == null) {
                        return null;
                    }
                } else {
                    cert = certs[0];
                }
                sha.update(cert.getEncoded());
                byte[] data = sha.digest();
                if (new String(thumb).equals(hexify(data))) {
                    return alias;
                }
            }
        } catch (Exception e) {
            log.error("Error while getting the alias", e);
        }
        return null;
    }

    private static String hexify(byte bytes[]) {
        char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        for (byte aByte : bytes) {
            buf.append(hexDigits[(aByte & 0xf0) >> 4]);
            buf.append(hexDigits[aByte & 0x0f]);
        }
        return buf.toString();
    }

    /**
     * Check  the given API is available in the APIIdentifier List. it will match for API Name,API Version and API Provider
     *
     * @param apiIdentifier - API DTO to verify
     * @param apiListDTO    - API Info DTO list
     * @return - Status of API availability
     */
    public static boolean isAPIAvailable(APIIdentifier apiIdentifier, APIListDTO apiListDTO) {
        boolean isFound = false;
        if (apiListDTO != null) {
            for (APIInfoDTO api : apiListDTO.getList()) {
                if (apiIdentifier.getName().equals(api.getName()) &&
                        apiIdentifier.getVersion().equals(api.getVersion()) &&
                        apiIdentifier.getProviderName().equals(api.getProvider())) {
                    isFound = true;
                    break;
                }
            }
        }
        return isFound;
    }

    /**
     * Check  the given API is available in the APIIdentifier List. it will match for API Name,API Version and API Provider
     *
     * @param apiIdentifier - API DTO to verify
     * @param apiListDTO    - API Info DTO list
     * @return - Status of API availability
     */
    public static boolean isAPIAvailableInStore(APIIdentifier apiIdentifier,
                            org.wso2.am.integration.clients.store.api.v1.dto.APIListDTO apiListDTO) {
        boolean isFound = false;
        if (apiListDTO != null) {
            for (org.wso2.am.integration.clients.store.api.v1.dto.APIInfoDTO api : apiListDTO.getList()) {
                if (apiIdentifier.getName().equals(api.getName()) &&
                        apiIdentifier.getVersion().equals(api.getVersion()) &&
                        apiIdentifier.getProviderName().equals(api.getProvider())) {
                    isFound = true;
                    break;
                }
            }
        }
        return isFound;
    }

    /**
     * get the base64 encoded username and password
     *
     * @param user username
     * @param pass password
     * @return encoded basic auth, as string
     */
    public static String encodeCredentials(String user, char[] pass) {
        StringBuilder builder = new StringBuilder(user).append(':').append(pass);
        String cred = builder.toString();
        byte[] encodedBytes = Base64.encodeBase64(cred.getBytes());
        return new String(encodedBytes);
    }

    public static File getTempSwaggerFileWithContent(String swagger) throws Exception {

        File temp = File.createTempFile("swagger", ".json");
        temp.deleteOnExit();
        BufferedWriter out = new BufferedWriter(new FileWriter(temp));
        out.write(swagger);
        out.close();
        return temp;
    }
}
